mirror of
https://github.com/ae-utbm/sith.git
synced 2024-11-21 13:43:20 +00:00
Better validation for phone number in billing info
This commit is contained in:
parent
d29a5cdb44
commit
1b1284d3d0
@ -2,6 +2,7 @@ from ajax_select import make_ajax_field
|
||||
from ajax_select.fields import AutoCompleteSelectField, AutoCompleteSelectMultipleField
|
||||
from django import forms
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from phonenumber_field.widgets import RegionalPhoneNumberWidget
|
||||
|
||||
from core.views.forms import NFCTextInput, SelectDate, SelectDateTime
|
||||
from counter.models import (
|
||||
@ -28,6 +29,9 @@ class BillingInfoForm(forms.ModelForm):
|
||||
"country",
|
||||
"phone_number",
|
||||
]
|
||||
widgets = {
|
||||
"phone_number": RegionalPhoneNumberWidget,
|
||||
}
|
||||
|
||||
|
||||
class StudentCardForm(forms.ModelForm):
|
||||
|
@ -428,6 +428,24 @@ class TestBillingInfo:
|
||||
assert infos.phone_number.as_national == "06123 45678"
|
||||
assert infos.phone_number.country_code == 49
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"phone_number", ["061234567a", "06 12 34 56", "061234567879", "azertyuiop"]
|
||||
)
|
||||
def test_invalid_phone_number(
|
||||
self, client: Client, payload: dict, phone_number: str
|
||||
):
|
||||
"""Test that invalid phone numbers are rejected."""
|
||||
user = subscriber_user.make()
|
||||
client.force_login(user)
|
||||
payload["phone_number"] = phone_number
|
||||
response = client.put(
|
||||
reverse("api:put_billing_info", args=[user.id]),
|
||||
json.dumps(payload),
|
||||
content_type="application/json",
|
||||
)
|
||||
assert response.status_code == 422
|
||||
assert not BillingInfo.objects.filter(customer__user=user).exists()
|
||||
|
||||
|
||||
class TestBarmanConnection(TestCase):
|
||||
@classmethod
|
||||
|
@ -1,6 +1,11 @@
|
||||
from typing import Annotated
|
||||
|
||||
from ninja import ModelSchema, Schema
|
||||
from pydantic import Field, NonNegativeInt, PositiveInt, TypeAdapter
|
||||
|
||||
# from phonenumber_field.phonenumber import PhoneNumber
|
||||
from pydantic_extra_types.phone_numbers import PhoneNumber, PhoneNumberValidator
|
||||
|
||||
from counter.models import BillingInfo
|
||||
|
||||
|
||||
@ -35,4 +40,4 @@ class BillingInfoSchema(ModelSchema):
|
||||
# for reasons described in the model, BillingInfo.phone_number
|
||||
# in nullable, but null values shouldn't be actually allowed,
|
||||
# so we force the field to be required
|
||||
phone_number: str
|
||||
phone_number: Annotated[PhoneNumber, PhoneNumberValidator(default_region="FR")]
|
||||
|
@ -42,7 +42,16 @@ document.addEventListener("alpine:init", () => {
|
||||
this.req_state = res.ok
|
||||
? BillingInfoReqState.SUCCESS
|
||||
: BillingInfoReqState.FAILURE;
|
||||
if (res.ok) {
|
||||
if (res.status === 422) {
|
||||
const errors = (await res.json())["detail"].map((err) => err["loc"]).flat();
|
||||
Array.from(form.querySelectorAll("input"))
|
||||
.filter((elem) => errors.includes(elem.name))
|
||||
.forEach((elem) => {
|
||||
elem.setCustomValidity(gettext("Incorrect value"));
|
||||
elem.reportValidity();
|
||||
elem.oninput = () => elem.setCustomValidity("");
|
||||
});
|
||||
} else if (res.ok) {
|
||||
Alpine.store("billing_inputs").fill();
|
||||
}
|
||||
},
|
||||
|
@ -144,7 +144,7 @@ class EbouticCommand(LoginRequiredMixin, TemplateView):
|
||||
elif default_billing_info.phone_number is None:
|
||||
kwargs["billing_infos_state"] = BillingInfoState.MISSING_PHONE_NUMBER
|
||||
else:
|
||||
kwargs["billing_infos_state"] = BillingInfoState.EMPTY
|
||||
kwargs["billing_infos_state"] = BillingInfoState.VALID
|
||||
if kwargs["billing_infos_state"] == BillingInfoState.VALID:
|
||||
# the user has already filled all of its billing_infos, thus we can
|
||||
# get it without expecting an error
|
||||
|
@ -7,7 +7,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-09-03 15:22+0200\n"
|
||||
"POT-Creation-Date: 2024-09-27 22:32+0200\n"
|
||||
"PO-Revision-Date: 2024-09-17 11:54+0200\n"
|
||||
"Last-Translator: Sli <antoine@bartuccio.fr>\n"
|
||||
"Language-Team: AE info <ae.info@utbm.fr>\n"
|
||||
@ -16,9 +16,24 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
#: core/static/user/js/family_graph.js:230
|
||||
|
||||
#: core/static/user/js/family_graph.js:233
|
||||
msgid "family_tree.%(extension)s"
|
||||
msgstr "arbre_genealogique.%(extension)s"
|
||||
#: sas/static/sas/js/picture.js:52
|
||||
|
||||
#: core/static/user/js/user_edit.js:93
|
||||
#, javascript-format
|
||||
msgid "captured.%s"
|
||||
msgstr "capture.%s"
|
||||
|
||||
#: eboutic/static/eboutic/js/makecommand.js:50
|
||||
msgid "Incorrect value"
|
||||
msgstr "Valeur incorrecte"
|
||||
|
||||
#: sas/static/sas/js/viewer.js:196
|
||||
msgid "Couldn't moderate picture"
|
||||
msgstr "Echec de la suppression de la photo"
|
||||
|
||||
#: sas/static/sas/js/viewer.js:209
|
||||
msgid "Couldn't delete picture"
|
||||
msgstr "Echec de la suppression de la photo"
|
||||
|
29
poetry.lock
generated
29
poetry.lock
generated
@ -1813,6 +1813,33 @@ files = [
|
||||
[package.dependencies]
|
||||
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-extra-types"
|
||||
version = "2.9.0"
|
||||
description = "Extra Pydantic types."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = []
|
||||
develop = false
|
||||
|
||||
[package.dependencies]
|
||||
pydantic = ">=2.5.2"
|
||||
typing-extensions = "*"
|
||||
|
||||
[package.extras]
|
||||
all = ["pendulum (>=3.0.0,<4.0.0)", "phonenumbers (>=8,<9)", "pycountry (>=23)", "python-ulid (>=1,<2)", "python-ulid (>=1,<3)", "pytz (>=2024.1)", "semver (>=3.0.2)", "semver (>=3.0.2,<3.1.0)", "tzdata (>=2024.1)"]
|
||||
pendulum = ["pendulum (>=3.0.0,<4.0.0)"]
|
||||
phonenumbers = ["phonenumbers (>=8,<9)"]
|
||||
pycountry = ["pycountry (>=23)"]
|
||||
python-ulid = ["python-ulid (>=1,<2)", "python-ulid (>=1,<3)"]
|
||||
semver = ["semver (>=3.0.2)"]
|
||||
|
||||
[package.source]
|
||||
type = "git"
|
||||
url = "https://github.com/pydantic/pydantic-extra-types.git"
|
||||
reference = "HEAD"
|
||||
resolved_reference = "58db4b096d7c90566d3d48d51b4665c01a591df6"
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.18.0"
|
||||
@ -2626,4 +2653,4 @@ filelock = ">=3.4"
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.12"
|
||||
content-hash = "b6202203d272cecdb607ea8ebc1ba12dd8369e4f387f65692c4a9681915e6f48"
|
||||
content-hash = "c9c49497cc576b24c96ea914b74ef5c3a0c2981c488a599752f05aabb575f8d8"
|
||||
|
@ -45,6 +45,10 @@ dict2xml = "^1.7.3"
|
||||
Sphinx = "^5" # Needed for building xapian
|
||||
tomli = "^2.0.1"
|
||||
django-honeypot = "^1.2.1"
|
||||
# When I introduced pydantic-extra-types, I needed *right now*
|
||||
# the PhoneNumberValidator class which was on the master branch but not released yet.
|
||||
# Once it's released, switch this to a regular version.
|
||||
pydantic-extra-types = { git = "https://github.com/pydantic/pydantic-extra-types.git", rev = "58db4b0" }
|
||||
|
||||
[tool.poetry.group.prod.dependencies]
|
||||
# deps used in prod, but unnecessary for development
|
||||
|
Loading…
Reference in New Issue
Block a user