From 0c490a8700e895a1cd51267e37dc40b94b6a8d2e Mon Sep 17 00:00:00 2001 From: charludo Date: Mon, 3 Feb 2025 16:27:50 +0100 Subject: [PATCH] Reformat phone numbers in the contact form --- integreat_cms/cms/fixtures/test_data.json | 6 ++-- .../cms/forms/contacts/contact_form.py | 26 ++++++++++++++ .../cms/templates/contacts/contact_card.html | 2 +- integreat_cms/core/settings.py | 6 ++++ tests/cms/views/contacts/test_contact_form.py | 35 +++++++++++++++++++ 5 files changed, 71 insertions(+), 4 deletions(-) diff --git a/integreat_cms/cms/fixtures/test_data.json b/integreat_cms/cms/fixtures/test_data.json index f3bfc2a458..d8cafd9563 100644 --- a/integreat_cms/cms/fixtures/test_data.json +++ b/integreat_cms/cms/fixtures/test_data.json @@ -982,7 +982,7 @@ "name": "Martina Musterfrau", "location": 6, "email": "martina-musterfrau@example.com", - "phone_number": "0123456789", + "phone_number": "+49 (0) 123456789", "website": "", "archived": false, "last_updated": "2024-08-06T13:23:45.256Z", @@ -1012,7 +1012,7 @@ "name": "Mariana Musterfrau", "location": 6, "email": "mariana-musterfrau@example.com", - "phone_number": "0123456789", + "phone_number": "+49 (0) 123456789", "website": "https://integreat-app.de/", "archived": false, "last_updated": "2024-08-06T13:23:45.256Z", @@ -1027,7 +1027,7 @@ "name": "", "location": 6, "email": "generalcontactinformation@example.com", - "phone_number": "0123456789", + "phone_number": "+49 (0) 123456789", "website": "https://integreat-app.de/", "archived": false, "last_updated": "2024-08-06T13:23:45.256Z", diff --git a/integreat_cms/cms/forms/contacts/contact_form.py b/integreat_cms/cms/forms/contacts/contact_form.py index 1c891a0383..29f4b473d9 100644 --- a/integreat_cms/cms/forms/contacts/contact_form.py +++ b/integreat_cms/cms/forms/contacts/contact_form.py @@ -1,7 +1,9 @@ from __future__ import annotations import logging +import re +from django.conf import settings from django.utils.translation import gettext_lazy as _ from ...models import Contact @@ -36,3 +38,27 @@ class Meta: error_messages = { "location": {"invalid_choice": _("Location cannot be empty.")}, } + + def clean_phone_number(self) -> str: + """ + Validate the phone number field (see :ref:`overriding-modelform-clean-method`). + The number will be converted to the international format, i.e. `+XX (X) XXXXXXXX`. + + :return: The reformatted phone number + """ + phone_number = self.cleaned_data["phone_number"] + if not phone_number or re.fullmatch(r"^\+\d{2,3} \(0\) \d*$", phone_number): + return phone_number + + phone_number = re.sub(r"[^0-9+]", "", phone_number) + prefix = settings.DEFAULT_PHONE_NUMBER_COUNTRY_CODE + if phone_number.startswith("00"): + prefix = f"+{phone_number[2:4]}" + phone_number = phone_number[4:] + elif phone_number.startswith("0"): + phone_number = phone_number[1:] + elif phone_number.startswith("+"): + prefix = phone_number[0:3] + phone_number = phone_number[3:] + + return f"{prefix} (0) {phone_number}" diff --git a/integreat_cms/cms/templates/contacts/contact_card.html b/integreat_cms/cms/templates/contacts/contact_card.html index 6c64cdaf1e..3e342e2fe6 100644 --- a/integreat_cms/cms/templates/contacts/contact_card.html +++ b/integreat_cms/cms/templates/contacts/contact_card.html @@ -43,7 +43,7 @@

alt="Phone Number: " width="15" height="15" /> - {{ contact.phone_number }} + {{ contact.phone_number }}

{% endif %} {% if contact.website and "website" in wanted %} diff --git a/integreat_cms/core/settings.py b/integreat_cms/core/settings.py index d9541653a7..b3d0c8d659 100644 --- a/integreat_cms/core/settings.py +++ b/integreat_cms/core/settings.py @@ -913,6 +913,12 @@ "integreat_cms.core.formats", ] +#: The country code used for phone numbers when converting user input to a standardized international format, +#: if no country code is specified by the user. +DEFAULT_PHONE_NUMBER_COUNTRY_CODE: Final[str] = os.environ.get( + "INTEGREAT_CMS_DEFAULT_PHONE_NUMBER_COUNTRY_CODE", "+49" +) + ##################################### # MT Global - AUTOMATIC TRANSLATION # diff --git a/tests/cms/views/contacts/test_contact_form.py b/tests/cms/views/contacts/test_contact_form.py index 11f7d9adc0..71d31020d1 100644 --- a/tests/cms/views/contacts/test_contact_form.py +++ b/tests/cms/views/contacts/test_contact_form.py @@ -10,6 +10,7 @@ import pytest from django.urls import reverse +from integreat_cms.cms.forms import ContactForm from integreat_cms.cms.models import Contact, Region from tests.conftest import ANONYMOUS, HIGH_PRIV_STAFF_ROLES from tests.utils import assert_message_in_log @@ -287,3 +288,37 @@ def test_one_primary_contact_per_poi( ) else: assert response.status_code == 403 + + +@pytest.mark.django_db +def test_phone_number_conversion() -> None: + """ + Test that phone numbers are converted to the expected international format. + """ + variants = [ + "+49123456789", + "0123456789", + "012 34/56789", + "01234-56789", + "0049123456789", + "00 (49) (1234) 56789", + " +49/1234-56789", + ] + for variant in variants: + form_data = { + "location": POI_ID, + "point_of_contact_for": "test", + "name": "", + "email": "mail@mail.integreat", + "phone_number": variant, + "website": "https://integreat-app.de/", + } + + form = ContactForm( + data=form_data, + instance=None, + additional_instance_attributes={"region": REGION_SLUG}, + ) + form.is_valid() # this is not an assert, because it would fail. calling is_valid() is required to populate cleaned_data. + cleaned = form.clean() + assert cleaned["phone_number"] == "+49 (0) 123456789"