From 186c158caa652e7bf017c6a0e490c783706ad309 Mon Sep 17 00:00:00 2001 From: Paul Schilling Date: Mon, 30 Sep 2024 16:49:28 +0200 Subject: [PATCH 1/2] [#2752] Add math captcha to contactform --- .../components/Contact/ContactForm.html | 11 ++++ src/open_inwoner/openklant/forms.py | 10 +++- .../openklant/tests/test_contactform.py | 53 +++++++++++++----- src/open_inwoner/utils/forms.py | 54 +++++++++++++++++++ .../utils/tests/test_form_fields.py | 52 ++++++++++++++++++ 5 files changed, 164 insertions(+), 16 deletions(-) create mode 100644 src/open_inwoner/utils/tests/test_form_fields.py diff --git a/src/open_inwoner/components/templates/components/Contact/ContactForm.html b/src/open_inwoner/components/templates/components/Contact/ContactForm.html index 0df736478c..3a751d018f 100644 --- a/src/open_inwoner/components/templates/components/Contact/ContactForm.html +++ b/src/open_inwoner/components/templates/components/Contact/ContactForm.html @@ -22,7 +22,18 @@ {% input form_object.phonenumber %} {% endif %} {% input form_object.question %} + + {% if form_object.captcha %} + + {{ form_object.captcha.label }} * + + {{ form_object.captcha_prompt }} + {{ form_object.captcha.question }} + {% field_as_widget form_object.captcha "input" form_id %} + {% endif %} + {% form_actions primary_text=_("Verzenden") primary_icon="arrow_forward" %} + {% endrender_form %} {% endrender_column %} diff --git a/src/open_inwoner/openklant/forms.py b/src/open_inwoner/openklant/forms.py index 78239ef3e2..ae22d9c327 100644 --- a/src/open_inwoner/openklant/forms.py +++ b/src/open_inwoner/openklant/forms.py @@ -1,13 +1,13 @@ from django import forms -from django.forms import Form from django.utils.translation import gettext_lazy as _ from open_inwoner.accounts.models import User from open_inwoner.openklant.models import ContactFormSubject, OpenKlantConfig +from open_inwoner.utils.forms import MathCaptchaField from open_inwoner.utils.validators import DutchPhoneNumberValidator -class ContactForm(Form): +class ContactForm(forms.Form): subject = forms.ModelChoiceField( label=_("Onderwerp"), required=True, @@ -45,6 +45,10 @@ class ContactForm(Form): widget=forms.Textarea(attrs={"rows": "5"}), required=True, ) + captcha = MathCaptchaField( + label=_("Beantwoord deze rekensom"), + required=True, + ) user: User @@ -54,11 +58,13 @@ def __init__(self, user, *args, **kwargs): config = OpenKlantConfig.get_solo() self.fields["subject"].queryset = config.contactformsubject_set.all() + self.captcha_prompt = self.fields["captcha"].question if self.user.is_authenticated: del self.fields["first_name"] del self.fields["last_name"] del self.fields["infix"] + del self.fields["captcha"] if self.user.email: del self.fields["email"] if self.user.phonenumber: diff --git a/src/open_inwoner/openklant/tests/test_contactform.py b/src/open_inwoner/openklant/tests/test_contactform.py index 1889badbc8..045c085d12 100644 --- a/src/open_inwoner/openklant/tests/test_contactform.py +++ b/src/open_inwoner/openklant/tests/test_contactform.py @@ -17,6 +17,7 @@ from open_inwoner.openklant.tests.factories import ContactFormSubjectFactory from open_inwoner.openklant.views.contactform import ContactFormView from open_inwoner.openzaak.tests.factories import ServiceFactory +from open_inwoner.utils.forms import MathCaptchaField from open_inwoner.utils.test import ClearCachesMixin, DisableRequestLogMixin from open_inwoner.utils.tests.helpers import AssertFormMixin, AssertTimelineLogMixin @@ -25,6 +26,7 @@ @modify_settings( MIDDLEWARE={"remove": ["open_inwoner.kvk.middleware.KvKLoginMiddleware"]} ) +@patch.object(MathCaptchaField, "clean", autospec=True) @patch( "open_inwoner.openklant.views.contactform.send_contact_confirmation_mail", autospec=True, @@ -61,7 +63,9 @@ def setUp(self): # bypass CMS for rendering form template directly via ContactFormView ContactFormView.template_name = "pages/contactform/form.html" - def test_singleton_has_configuration_method(self, m, mock_send_confirm): + def test_singleton_has_configuration_method( + self, m, mock_send_confirm, mock_captcha + ): # use cleared (from setUp() config = OpenKlantConfig.get_solo() self.assertFalse(config.has_form_configuration()) @@ -87,7 +91,9 @@ def test_singleton_has_configuration_method(self, m, mock_send_confirm): mock_send_confirm.assert_not_called() - def test_no_form_shown_if_not_has_configuration(self, m, mock_send_confirm): + def test_no_form_shown_if_not_has_configuration( + self, m, mock_send_confirm, mock_captcha + ): # set nothing config = OpenKlantConfig.get_solo() self.assertFalse(config.has_form_configuration()) @@ -96,7 +102,9 @@ def test_no_form_shown_if_not_has_configuration(self, m, mock_send_confirm): self.assertContains(response, _("Contact formulier niet geconfigureerd.")) self.assertEqual(0, len(response.pyquery("#contactmoment-form"))) - def test_anon_form_requires_either_email_or_phonenumber(self, m, mock_send_confirm): + def test_anon_form_requires_either_email_or_phonenumber( + self, m, mock_send_confirm, mock_captcha + ): config = OpenKlantConfig.get_solo() config.register_email = "example@example.com" config.save() @@ -115,6 +123,7 @@ def test_anon_form_requires_either_email_or_phonenumber(self, m, mock_send_confi "email", "phonenumber", "question", + "captcha", # captcha present for anon user ), ) form["subject"].select(text=subject.subject) @@ -130,7 +139,9 @@ def test_anon_form_requires_either_email_or_phonenumber(self, m, mock_send_confi ) mock_send_confirm.assert_not_called() - def test_regular_auth_form_fills_email_and_phonenumber(self, m, mock_send_confirm): + def test_regular_auth_form_fills_email_and_phonenumber( + self, m, mock_send_confirm, mock_captcha + ): config = OpenKlantConfig.get_solo() config.register_email = "example@example.com" config.save() @@ -153,7 +164,9 @@ def test_regular_auth_form_fills_email_and_phonenumber(self, m, mock_send_confir response = form.submit(status=302) mock_send_confirm.assert_called_once_with(user.email, subject.subject) - def test_expected_ordered_subjects_are_shown(self, m, mock_send_confirm): + def test_expected_ordered_subjects_are_shown( + self, m, mock_send_confirm, mock_captcha + ): config = OpenKlantConfig.get_solo() config.register_email = "example@example.com" config.save() @@ -190,7 +203,7 @@ def test_expected_ordered_subjects_are_shown(self, m, mock_send_confirm): ) mock_send_confirm.assert_not_called() - def test_submit_and_register_via_email(self, m, mock_send_confirm): + def test_submit_and_register_via_email(self, m, mock_send_confirm, mock_captcha): config = OpenKlantConfig.get_solo() config.register_email = "example@example.com" config.has_form_configuration = True @@ -230,7 +243,9 @@ def test_submit_and_register_via_email(self, m, mock_send_confirm): mock_send_confirm.assert_called_once_with("foo@example.com", subject.subject) - def test_submit_and_register_anon_via_api_with_klant(self, m, mock_send_confirm): + def test_submit_and_register_anon_via_api_with_klant( + self, m, mock_send_confirm, mock_captcha + ): MockAPICreateData.setUpServices() config = OpenKlantConfig.get_solo() @@ -313,7 +328,9 @@ def test_submit_and_register_anon_via_api_with_klant(self, m, mock_send_confirm) mock_send_confirm.assert_called_once_with("foo@example.com", subject.subject) - def test_submit_and_register_anon_via_api_without_klant(self, m, mock_send_confirm): + def test_submit_and_register_anon_via_api_without_klant( + self, m, mock_send_confirm, mock_captcha + ): MockAPICreateData.setUpServices() config = OpenKlantConfig.get_solo() @@ -388,7 +405,9 @@ def test_submit_and_register_anon_via_api_without_klant(self, m, mock_send_confi self.assertTimelineLog("registered contactmoment by API") mock_send_confirm.assert_called_once_with("foo@example.com", subject.subject) - def test_register_bsn_user_via_api_without_id(self, m, mock_send_confirm): + def test_register_bsn_user_via_api_without_id( + self, m, mock_send_confirm, mock_captcha + ): MockAPICreateData.setUpServices() config = OpenKlantConfig.get_solo() @@ -439,7 +458,9 @@ def test_register_bsn_user_via_api_without_id(self, m, mock_send_confirm): }, ) - def test_submit_and_register_bsn_user_via_api(self, m, mock_send_confirm): + def test_submit_and_register_bsn_user_via_api( + self, m, mock_send_confirm, mock_captcha + ): MockAPICreateData.setUpServices() config = OpenKlantConfig.get_solo() @@ -513,7 +534,9 @@ def test_submit_and_register_bsn_user_via_api(self, m, mock_send_confirm): self.assertTimelineLog("registered contactmoment by API") mock_send_confirm.assert_called_once_with("foo@example.com", subject.subject) - def test_submit_and_register_kvk_or_rsin_user_via_api(self, _m, mock_send_confirm): + def test_submit_and_register_kvk_or_rsin_user_via_api( + self, _m, mock_send_confirm, mock_captcha + ): MockAPICreateData.setUpServices() config = OpenKlantConfig.get_solo() @@ -617,7 +640,7 @@ def test_submit_and_register_kvk_or_rsin_user_via_api(self, _m, mock_send_confir mock_send_confirm.reset_mock() def test_submit_and_register_bsn_user_via_api_and_update_klant( - self, m, mock_send_confirm + self, m, mock_send_confirm, mock_captcha ): MockAPICreateData.setUpServices() @@ -701,7 +724,7 @@ def test_submit_and_register_bsn_user_via_api_and_update_klant( mock_send_confirm.reset_mock() def test_submit_and_register_kvk_or_rsin_user_via_api_and_update_klant( - self, _m, mock_send_confirm + self, m, mock_send_confirm, mock_captcha ): self.maxDiff = None MockAPICreateData.setUpServices() @@ -804,7 +827,9 @@ def test_submit_and_register_kvk_or_rsin_user_via_api_and_update_klant( ) mock_send_confirm.reset_mock() - def test_send_email_confirmation_is_configurable(self, m, mock_send_confirm): + def test_send_email_confirmation_is_configurable( + self, m, mock_send_confirm, mock_captcha + ): MockAPICreateData.setUpServices() config = OpenKlantConfig.get_solo() diff --git a/src/open_inwoner/utils/forms.py b/src/open_inwoner/utils/forms.py index ddb58266ef..d8a680320e 100644 --- a/src/open_inwoner/utils/forms.py +++ b/src/open_inwoner/utils/forms.py @@ -1,4 +1,5 @@ import mimetypes +import secrets from django import forms from django.conf import settings @@ -163,3 +164,56 @@ def clean(self, *args, **kwargs): ) return f + + +class MathCaptchaField(forms.Field): + def __init__( + self, + range_: tuple = (1, 10), + operators: list[str] | None = None, + *args, + **kwargs, + ): + super().__init__(*args, **kwargs) + self.widget = forms.TextInput() + self.range_ = range_ + self.operators = operators or ["+", "-"] + self.question, self.answer = self.generate_question_answer_pair( + self.range_, self.operators + ) + + @staticmethod + def generate_question_answer_pair( + range_: tuple[int, int], + operators: list[str], + ) -> tuple[str, int]: + lower, upper = range_ + num1 = secrets.choice(range(lower, upper)) + num2 = secrets.choice(range(lower, upper)) + operator = secrets.choice(operators) + + # exclude negative results + num1, num2 = max(num1, num2), min(num1, num2) + + question = _("What is {num1} {operator_str} {num2}?").format( + num1=num1, operator_str=operator, num2=num2 + ) + + match operator: + case "+": + answer = num1 + num2 + case "-": + answer = num1 - num2 + + return question, answer + + def clean(self, value: str) -> str: + if not value: + raise forms.ValidationError(_("Dit veld is vereist.")) + if not isinstance(value, str): + raise forms.ValidationError(_("Voer een geheel getal in.")) + if value.isspace(): + raise forms.ValidationError(_("Voer een geheel getal in.")) + if int(value) != self.answer: + raise forms.ValidationError(_("Fout antwoord, probeer het opnieuw.")) + return value diff --git a/src/open_inwoner/utils/tests/test_form_fields.py b/src/open_inwoner/utils/tests/test_form_fields.py new file mode 100644 index 0000000000..d2cac53534 --- /dev/null +++ b/src/open_inwoner/utils/tests/test_form_fields.py @@ -0,0 +1,52 @@ +from django import forms +from django.test import TestCase +from django.utils.translation import gettext as _ + +from ..forms import MathCaptchaField + + +class MockForm(forms.Form): + captcha = MathCaptchaField(range_=(4, 5), operators=["+"]) + captcha_2 = MathCaptchaField(range_=(4, 5), operators=["-"]) + + +class MathCaptchaFieldUnitTest(TestCase): + def test_captcha_invalid(self): + test_cases = [ + { + "captcha": "", + "message": _("Dit veld is vereist."), + "reason": "field required", + }, + { + "captcha": " ", + "message": _("Voer een geheel getal in."), + "reason": "wrong input type", + }, + { + "captcha": 42, + "message": _("Voer een geheel getal in."), + "reason": "wrong input type", + }, + { + "captcha": "42", # captcha only computes 2 numbers between 1 and 10 + "message": _("Fout antwoord, probeer het opnieuw."), + "reason": "wrong answer", + }, + ] + for test_case in test_cases: + with self.subTest(reason=test_case["reason"]): + form = MockForm( + data={ + "captcha": test_case["captcha"], + "captcha_2": test_case["captcha"], + }, + ) + self.assertFalse(form.is_valid()) + self.assertEqual(form.errors["captcha"], [test_case["message"]]) + + def test_captcha_valid(self): + form = MockForm( + data={"captcha": "8", "captcha_2": "0"}, + ) + self.assertTrue(form.is_valid()) From cd85a8decffd0dd957dcc246d2520c323312c53b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cjiromaykin=E2=80=9D?= Date: Tue, 1 Oct 2024 19:12:33 +0200 Subject: [PATCH 2/2] :sparkles: [#2752] Added styling for captcha and captcha-translations --- .../components/Contact/ContactForm.html | 24 ++- .../conf/locale/nl/LC_MESSAGES/django.mo | Bin 153882 -> 154195 bytes .../conf/locale/nl/LC_MESSAGES/django.po | 203 +++++++++--------- src/open_inwoner/openklant/forms.py | 1 - .../scss/components/Captcha/Captcha.scss | 25 +++ src/open_inwoner/scss/components/_index.scss | 1 + src/open_inwoner/utils/forms.py | 4 +- 7 files changed, 151 insertions(+), 107 deletions(-) create mode 100644 src/open_inwoner/scss/components/Captcha/Captcha.scss diff --git a/src/open_inwoner/components/templates/components/Contact/ContactForm.html b/src/open_inwoner/components/templates/components/Contact/ContactForm.html index 3a751d018f..72b2efb948 100644 --- a/src/open_inwoner/components/templates/components/Contact/ContactForm.html +++ b/src/open_inwoner/components/templates/components/Contact/ContactForm.html @@ -24,15 +24,25 @@ {% input form_object.question %} {% if form_object.captcha %} - - {{ form_object.captcha.label }} * - - {{ form_object.captcha_prompt }} - {{ form_object.captcha.question }} - {% field_as_widget form_object.captcha "input" form_id %} +
+
+ +
+
+ {{ form_object.captcha.field.question }} +
+ {% field_as_widget form_object.captcha "input" form_id %} +
+ {% if form_object.captcha.errors %} + {% errors errors=form_object.captcha.errors %} + {% endif %} +
+
{% endif %} - {% form_actions primary_text=_("Verzenden") primary_icon="arrow_forward" %} + {% form_actions primary_text=_("Verzenden") primary_icon="arrow_forward" fullwidth=True %} {% endrender_form %} diff --git a/src/open_inwoner/conf/locale/nl/LC_MESSAGES/django.mo b/src/open_inwoner/conf/locale/nl/LC_MESSAGES/django.mo index 82f8417c50320b8996a3a7a404728a752b461f70..8f25c699c0da40463f083b9fa1f9c0f1afb4228a 100644 GIT binary patch delta 36113 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 delta 35787 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%0A}uQ&Qe9x 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\n" "Language-Team: LANGUAGE \n" @@ -1448,11 +1448,11 @@ msgstr "Actie '{action}' is verwijdered." #: open_inwoner/accounts/views/contacts.py:31 #: open_inwoner/accounts/views/contacts.py:66 #: open_inwoner/accounts/views/profile.py:81 -#: open_inwoner/accounts/views/profile.py:217 -#: open_inwoner/accounts/views/profile.py:268 -#: open_inwoner/accounts/views/profile.py:290 -#: open_inwoner/accounts/views/profile.py:321 -#: open_inwoner/accounts/views/profile.py:400 +#: open_inwoner/accounts/views/profile.py:221 +#: open_inwoner/accounts/views/profile.py:272 +#: open_inwoner/accounts/views/profile.py:294 +#: open_inwoner/accounts/views/profile.py:325 +#: open_inwoner/accounts/views/profile.py:404 #: open_inwoner/questionnaire/views.py:52 #: open_inwoner/questionnaire/views.py:148 msgid "Mijn profiel" @@ -1501,6 +1501,8 @@ msgstr "" #: open_inwoner/pdc/tests/test_organization_location.py:34 #: open_inwoner/pdc/tests/test_product_location.py:239 #: open_inwoner/pdc/tests/test_product_location.py:240 +#: open_inwoner/utils/forms.py:207 +#: open_inwoner/utils/tests/test_form_fields.py:18 msgid "Dit veld is vereist." msgstr "Dit veld is vereist." @@ -1633,22 +1635,22 @@ msgid "user was created" msgstr "gebruikersaccount is aangemaakt" #: open_inwoner/accounts/tests/test_logging.py:92 -#: open_inwoner/accounts/views/profile.py:230 +#: open_inwoner/accounts/views/profile.py:234 msgid "profile was modified" msgstr "profiel is gewijzigd" #: open_inwoner/accounts/tests/test_logging.py:116 -#: open_inwoner/accounts/views/profile.py:278 +#: open_inwoner/accounts/views/profile.py:282 msgid "categories were modified" msgstr "interessegebieden zijn gewijzigd" #: open_inwoner/accounts/tests/test_logging.py:142 -#: open_inwoner/accounts/views/profile.py:354 +#: open_inwoner/accounts/views/profile.py:358 msgid "users notifications were modified" msgstr "gebruikersnotificaties zijn gewijzigd" #: open_inwoner/accounts/tests/test_logging.py:234 -#: open_inwoner/accounts/views/profile.py:191 +#: open_inwoner/accounts/views/profile.py:195 msgid "user was deleted via frontend" msgstr "gebruikersaccount is op eigen verzoek verwijderd" @@ -1802,44 +1804,44 @@ msgid "Stuur een bericht" msgstr "Stuur een bericht" #: open_inwoner/accounts/tests/test_profile_views.py:362 -#: open_inwoner/accounts/tests/test_profile_views.py:726 +#: open_inwoner/accounts/tests/test_profile_views.py:730 msgid "" "Het verplichte veld \"E-mailadres\" is niet (goed) ingevuld. Vul het veld in." msgstr "" "Het verplichte veld \"E-mailadres\" is niet (goed) ingevuld. Vul het veld in." -#: open_inwoner/accounts/tests/test_profile_views.py:720 +#: open_inwoner/accounts/tests/test_profile_views.py:724 msgid "Het verplichte veld \"Naam\" is niet (goed) ingevuld. Vul het veld in." msgstr "Het verplichte veld \"Naam\" is niet (goed) ingevuld. Vul het veld in." -#: open_inwoner/accounts/tests/test_profile_views.py:733 #: open_inwoner/accounts/tests/test_profile_views.py:737 +#: open_inwoner/accounts/tests/test_profile_views.py:741 msgid "Naam is verplicht." msgstr "Naam is verplicht." -#: open_inwoner/accounts/tests/test_profile_views.py:734 #: open_inwoner/accounts/tests/test_profile_views.py:738 +#: open_inwoner/accounts/tests/test_profile_views.py:742 msgid "E-mail is verplicht." msgstr "E-mail is verplicht." -#: open_inwoner/accounts/tests/test_profile_views.py:900 -#: open_inwoner/accounts/tests/test_profile_views.py:917 -#: open_inwoner/accounts/tests/test_profile_views.py:951 -#: open_inwoner/accounts/views/profile.py:300 +#: open_inwoner/accounts/tests/test_profile_views.py:904 +#: open_inwoner/accounts/tests/test_profile_views.py:921 +#: open_inwoner/accounts/tests/test_profile_views.py:955 +#: open_inwoner/accounts/views/profile.py:304 msgid "user requests for brp data" msgstr "gebruiker vraagt BRP data op" -#: open_inwoner/accounts/tests/test_profile_views.py:1259 -#: open_inwoner/accounts/tests/test_profile_views.py:1294 -#: open_inwoner/accounts/tests/test_profile_views.py:1399 -#: open_inwoner/accounts/views/profile.py:115 +#: open_inwoner/accounts/tests/test_profile_views.py:1263 +#: open_inwoner/accounts/tests/test_profile_views.py:1298 +#: open_inwoner/accounts/tests/test_profile_views.py:1403 +#: open_inwoner/accounts/views/profile.py:119 #: open_inwoner/cms/profile/cms_appconfig.py:65 #: open_inwoner/laposta/forms.py:24 #: open_inwoner/templates/pages/profile/me.html:130 msgid "Nieuwsbrieven" msgstr "Nieuwsbrieven" -#: open_inwoner/accounts/tests/test_profile_views.py:1334 +#: open_inwoner/accounts/tests/test_profile_views.py:1338 #: open_inwoner/laposta/forms.py:95 #: open_inwoner/laposta/tests/test_forms.py:301 #, python-brace-format @@ -1850,7 +1852,7 @@ msgstr "" "Er ging iets mis bij het aanmelden op '{list_name}', probeer het later nog " "een keer" -#: open_inwoner/accounts/tests/test_profile_views.py:1340 +#: open_inwoner/accounts/tests/test_profile_views.py:1344 #: open_inwoner/laposta/forms.py:114 #: open_inwoner/laposta/tests/test_forms.py:305 #, python-brace-format @@ -1861,16 +1863,16 @@ msgstr "" "Er ging iets mis bij het afmelden op '{list_name}', probeer het later nog " "een keer" -#: open_inwoner/accounts/tests/test_profile_views.py:1432 -#: open_inwoner/accounts/tests/test_profile_views.py:1442 -#: open_inwoner/accounts/tests/test_profile_views.py:1456 -#: open_inwoner/accounts/tests/test_profile_views.py:1470 -#: open_inwoner/accounts/tests/test_profile_views.py:1479 +#: open_inwoner/accounts/tests/test_profile_views.py:1436 +#: open_inwoner/accounts/tests/test_profile_views.py:1446 +#: open_inwoner/accounts/tests/test_profile_views.py:1460 +#: open_inwoner/accounts/tests/test_profile_views.py:1474 +#: open_inwoner/accounts/tests/test_profile_views.py:1483 #: open_inwoner/templates/pages/profile/appointments.html:42 msgid "Geen afspraken beschikbaar" msgstr "Geen afspraken beschikbaar" -#: open_inwoner/accounts/tests/test_profile_views.py:1486 +#: open_inwoner/accounts/tests/test_profile_views.py:1490 #: open_inwoner/templates/pages/profile/appointments.html:9 msgid "Een overzicht van uw afspraken" msgstr "Een overzicht van uw afspraken" @@ -2025,9 +2027,9 @@ msgid "failed to modify user newsletter subscription" msgstr "het bijwerken van het nieuwsbriefabonnement is niet gelukt" #: open_inwoner/accounts/views/profile.py:73 -#: open_inwoner/accounts/views/profile.py:229 -#: open_inwoner/accounts/views/profile.py:277 -#: open_inwoner/accounts/views/profile.py:353 +#: open_inwoner/accounts/views/profile.py:233 +#: open_inwoner/accounts/views/profile.py:281 +#: open_inwoner/accounts/views/profile.py:357 msgid "Uw wijzigingen zijn opgeslagen" msgstr "Uw wijzigingen zijn opgeslagen" @@ -2035,17 +2037,12 @@ msgstr "Uw wijzigingen zijn opgeslagen" msgid "users newsletter subscriptions were modified" msgstr "nieuwsbrief abonnementen zijn gewijzigd" -#: open_inwoner/accounts/views/profile.py:106 +#: open_inwoner/accounts/views/profile.py:107 #: open_inwoner/templates/pages/profile/me.html:62 #: open_inwoner/templates/pages/profile/mydata.html:12 msgid "Persoonlijke gegevens" msgstr "Persoonlijke gegevens" -#: open_inwoner/accounts/views/profile.py:107 -#: open_inwoner/templates/pages/profile/me.html:104 -msgid "Voorkeuren voor meldingen" -msgstr "Voorkeuren voor meldingen" - #: open_inwoner/accounts/views/profile.py:108 #: open_inwoner/components/templates/components/Header/Header.html:49 #: open_inwoner/templates/pages/profile/me.html:165 @@ -2058,7 +2055,12 @@ msgstr "Overzicht" msgid "Profiel verwijderen" msgstr "Profiel verwijderen" -#: open_inwoner/accounts/views/profile.py:184 +#: open_inwoner/accounts/views/profile.py:113 +#: open_inwoner/templates/pages/profile/me.html:104 +msgid "Voorkeuren voor meldingen" +msgstr "Voorkeuren voor meldingen" + +#: open_inwoner/accounts/views/profile.py:188 msgid "" "Your profile could not be deleted because you still have plans associated " "with it." @@ -2066,29 +2068,29 @@ msgstr "" "Profiel kon niet worden verwijderd, u bent nog actief in 1 of meerdere " "samenwerkingsplannen." -#: open_inwoner/accounts/views/profile.py:197 +#: open_inwoner/accounts/views/profile.py:201 msgid "Uw account kon niet worden verwijderd" msgstr "Uw account kon niet worden verwijderd" -#: open_inwoner/accounts/views/profile.py:218 +#: open_inwoner/accounts/views/profile.py:222 msgid "Bewerk profiel" msgstr "Bewerk profiel" -#: open_inwoner/accounts/views/profile.py:269 +#: open_inwoner/accounts/views/profile.py:273 msgid "Mijn interessegebieden" msgstr "Mijn interessegebieden" -#: open_inwoner/accounts/views/profile.py:291 +#: open_inwoner/accounts/views/profile.py:295 #: open_inwoner/cms/profile/cms_appconfig.py:9 msgid "Mijn gegevens" msgstr "Mijn Gegevens" -#: open_inwoner/accounts/views/profile.py:322 +#: open_inwoner/accounts/views/profile.py:326 #: open_inwoner/templates/pages/profile/notifications.html:17 msgid "Ontvang berichten over" msgstr "Ontvang berichten over" -#: open_inwoner/accounts/views/profile.py:401 +#: open_inwoner/accounts/views/profile.py:405 #: open_inwoner/cms/profile/cms_appconfig.py:70 #: open_inwoner/templates/pages/profile/me.html:311 msgid "Mijn afspraken" @@ -2192,10 +2194,6 @@ msgstr "Bestand type" msgid "Bestand" msgstr "Bestand" -#: open_inwoner/cms/cases/forms.py:101 -msgid "Filter by status" -msgstr "Filter op status" - #: open_inwoner/cms/cases/tests/test_contactform.py:493 #: open_inwoner/cms/cases/tests/test_contactform.py:555 #: open_inwoner/cms/cases/tests/test_contactform.py:639 @@ -2203,11 +2201,11 @@ msgstr "Filter op status" #: open_inwoner/cms/cases/tests/test_contactform.py:732 #: open_inwoner/cms/cases/tests/test_htmx.py:527 #: open_inwoner/cms/cases/views/status.py:928 -#: open_inwoner/openklant/tests/test_contactform.py:207 -#: open_inwoner/openklant/tests/test_contactform.py:259 -#: open_inwoner/openklant/tests/test_contactform.py:339 -#: open_inwoner/openklant/tests/test_contactform.py:469 -#: open_inwoner/openklant/tests/test_contactform.py:558 +#: open_inwoner/openklant/tests/test_contactform.py:220 +#: open_inwoner/openklant/tests/test_contactform.py:274 +#: open_inwoner/openklant/tests/test_contactform.py:360 +#: open_inwoner/openklant/tests/test_contactform.py:496 +#: open_inwoner/openklant/tests/test_contactform.py:587 #: open_inwoner/openklant/views/contactform.py:72 msgid "Vraag verstuurd!" msgstr "Vraag verstuurd!" @@ -2234,13 +2232,20 @@ msgid "Vraag versturen" msgstr "Vraag versturen" #: open_inwoner/cms/cases/views/cases.py:31 -#: open_inwoner/templates/pages/cases/list_inner.html:40 -msgid "Openstaande aanvraag" -msgstr "Openstaande aanvraag" +msgid "Openstaande formulieren" +msgstr "Openstaande formulieren" + +#: open_inwoner/cms/cases/views/cases.py:32 +msgid "Lopende aanvragen" +msgstr "Lopende aanvragen" -#: open_inwoner/cms/cases/views/cases.py:111 -#: open_inwoner/cms/cases/views/cases.py:115 -#: open_inwoner/cms/cases/views/cases.py:141 +#: open_inwoner/cms/cases/views/cases.py:33 +msgid "Afgeronde aanvragen" +msgstr "Afgeronde aanvragen" + +#: open_inwoner/cms/cases/views/cases.py:167 +#: open_inwoner/cms/cases/views/cases.py:171 +#: open_inwoner/cms/cases/views/cases.py:197 #: open_inwoner/cms/cases/views/status.py:80 #: open_inwoner/cms/cases/views/status.py:138 msgid "Mijn aanvragen" @@ -2713,7 +2718,7 @@ msgid "Einddatum" msgstr "Einddatum" #: open_inwoner/components/templates/components/Contact/ContactForm.html:8 -#: open_inwoner/components/templates/components/Contact/ContactForm.html:27 +#: open_inwoner/components/templates/components/Contact/ContactForm.html:45 #: open_inwoner/components/templates/components/Messages/Messages.html:68 #: open_inwoner/components/templatetags/form_tags.py:138 #: open_inwoner/templates/pages/plans/create.html:72 @@ -2722,8 +2727,8 @@ msgstr "Einddatum" msgid "Verzenden" msgstr "Verzenden" -#: open_inwoner/components/templates/components/Contact/ContactForm.html:31 -#: open_inwoner/openklant/tests/test_contactform.py:90 +#: open_inwoner/components/templates/components/Contact/ContactForm.html:50 +#: open_inwoner/openklant/tests/test_contactform.py:96 msgid "Contact formulier niet geconfigureerd." msgstr "Contact formulier niet geconfigureerd." @@ -4815,8 +4820,8 @@ msgid "Afgehandeld" msgstr "Afgehandeld" #: open_inwoner/openklant/forms.py:15 -#: open_inwoner/openklant/tests/test_contactform.py:163 -#: open_inwoner/openklant/tests/test_contactform.py:179 +#: open_inwoner/openklant/tests/test_contactform.py:176 +#: open_inwoner/openklant/tests/test_contactform.py:192 msgid "Selecteren" msgstr "Selecteren" @@ -4835,8 +4840,12 @@ msgstr "Tussenvoegsel" msgid "Achternaam" msgstr "Achternaam" -#: open_inwoner/openklant/forms.py:76 -#: open_inwoner/openklant/tests/test_contactform.py:122 +#: open_inwoner/openklant/forms.py:49 +msgid "Beantwoord deze rekensom" +msgstr "" + +#: open_inwoner/openklant/forms.py:82 +#: open_inwoner/openklant/tests/test_contactform.py:131 msgid "Vul een e-mailadres of telefoonnummer in." msgstr "Vul een e-mailadres of telefoonnummer in." @@ -4972,7 +4981,7 @@ msgstr "KlantContactMomenten" msgid "Nieuw antwoord beschikbaar" msgstr "Nieuw antwoord beschikbaar" -#: open_inwoner/openklant/views/contactform.py:221 +#: open_inwoner/openklant/views/contactform.py:219 #, python-brace-format msgid "" "{text}\n" @@ -4980,22 +4989,6 @@ msgid "" "Naam: {full_name}" msgstr "" -#: open_inwoner/openklant/views/contactform.py:226 -#, python-brace-format -msgid "" -"{text}\n" -"Email: {email}" -msgstr "" - -#: open_inwoner/openklant/views/contactform.py:231 -#, python-brace-format -msgid "" -"{text}\n" -"Telefoonnummer: {phone}" -msgstr "" -"{text}\n" -"Telefoonnummer: {phone}" - #: open_inwoner/openzaak/admin.py:76 msgid "API behaviour override options" msgstr "eSuite-specifieke ZGW API opties" @@ -5594,10 +5587,6 @@ msgstr "" "Een fout is opgetreden bij het uploaden van {self." "uploaded_informatie_object['bestandsnaam']}" -#: open_inwoner/openzaak/tests/test_cases.py:1150 -msgid "Selecteer een geldige keuze. Bogus is geen beschikbare keuze." -msgstr "" - #: open_inwoner/pdc/admin/category.py:81 open_inwoner/pdc/admin/category.py:116 msgid "Parent nodes have to be published in order to publish a child." msgstr "" @@ -7190,8 +7179,12 @@ msgid "U heeft op dit moment nog geen lopende aanvragen." msgstr "U heeft op dit moment nog geen lopende aanvragen." #: open_inwoner/templates/pages/cases/list_inner.html:37 -msgid "Aanvraag verloopt op:" -msgstr "Aanvraag verloopt op:" +msgid "Laatst gewijzigd op:" +msgstr "Laatst gewijzigd op:" + +#: open_inwoner/templates/pages/cases/list_inner.html:40 +msgid "Openstaande aanvraag" +msgstr "Openstaande aanvraag" #: open_inwoner/templates/pages/cases/list_inner.html:43 msgid "Aanvraag afronden" @@ -7562,12 +7555,12 @@ msgstr "Voeg document toe" msgid "Bewerk contactgegevens" msgstr "Bewerk contactgegevens" -#: open_inwoner/templates/pages/profile/edit.html:54 +#: open_inwoner/templates/pages/profile/edit.html:53 #: open_inwoner/templates/pages/profile/notifications.html:71 msgid "Sla wijzigingen op" msgstr "Sla wijzigingen op" -#: open_inwoner/templates/pages/profile/edit.html:55 +#: open_inwoner/templates/pages/profile/edit.html:54 #: open_inwoner/templates/pages/profile/notifications.html:73 msgid "Terug naar Mijn profiel" msgstr "Terug naar mijn profiel" @@ -8179,14 +8172,14 @@ msgstr "Start taak" msgid "Opens external website" msgstr "Opens external website" -#: open_inwoner/utils/forms.py:14 +#: open_inwoner/utils/forms.py:15 #, python-brace-format msgid "" "Het verplichte veld {field_name} is niet (goed) ingevuld. Vul het veld in." msgstr "" "Het verplichte veld {field_name} is niet (goed) ingevuld. Vul het veld in." -#: open_inwoner/utils/forms.py:85 +#: open_inwoner/utils/forms.py:86 #, python-format msgid "" "Een aangeleverd bestand dient minimaal %(size)s te zijn, uw bestand is te " @@ -8195,7 +8188,7 @@ msgstr "" "Een aangeleverd bestand dient minimaal %(size)s te zijn, uw bestand is te " "klein." -#: open_inwoner/utils/forms.py:88 +#: open_inwoner/utils/forms.py:89 #, python-format msgid "" "Een aangeleverd bestand dient maximaal %(size)s te zijn, uw bestand is te " @@ -8204,7 +8197,7 @@ msgstr "" "Een aangeleverd bestand dient maximaal %(size)s te zijn, uw bestand is te " "groot." -#: open_inwoner/utils/forms.py:91 +#: open_inwoner/utils/forms.py:92 #, python-format msgid "" "Het type bestand dat u hebt geüpload is ongeldig. Geldige bestandstypen " @@ -8213,6 +8206,22 @@ msgstr "" "Het type bestand dat u hebt geüpload is ongeldig. Geldige bestandstypen " "zijn: %(file_extensions)s" +#: open_inwoner/utils/forms.py:198 +#, python-brace-format +msgid "What is {num1} {operator_str} {num2}?" +msgstr "Wat is {num1} {operator_str} {num2}?" + +#: open_inwoner/utils/forms.py:209 open_inwoner/utils/forms.py:211 +#: open_inwoner/utils/tests/test_form_fields.py:23 +#: open_inwoner/utils/tests/test_form_fields.py:28 +msgid "Voer een geheel getal in." +msgstr "Voer een geheel getal in." + +#: open_inwoner/utils/forms.py:213 +#: open_inwoner/utils/tests/test_form_fields.py:33 +msgid "Fout antwoord, probeer het opnieuw." +msgstr "Fout antwoord, probeer het opnieuw." + #: open_inwoner/utils/logentry.py:32 #, python-brace-format msgid "Changed: {changed_fields}." diff --git a/src/open_inwoner/openklant/forms.py b/src/open_inwoner/openklant/forms.py index ae22d9c327..9541e432a3 100644 --- a/src/open_inwoner/openklant/forms.py +++ b/src/open_inwoner/openklant/forms.py @@ -58,7 +58,6 @@ def __init__(self, user, *args, **kwargs): config = OpenKlantConfig.get_solo() self.fields["subject"].queryset = config.contactformsubject_set.all() - self.captcha_prompt = self.fields["captcha"].question if self.user.is_authenticated: del self.fields["first_name"] diff --git a/src/open_inwoner/scss/components/Captcha/Captcha.scss b/src/open_inwoner/scss/components/Captcha/Captcha.scss new file mode 100644 index 0000000000..04dc7ddcd2 --- /dev/null +++ b/src/open_inwoner/scss/components/Captcha/Captcha.scss @@ -0,0 +1,25 @@ +.captcha { + display: flex; + flex-direction: column; + gap: var(--spacing-medium); + + .__label { + display: flex; + } + + &__check { + display: flex; + align-items: center; + justify-content: start; + gap: var(--spacing-large); + } + + &__prompt { + font-weight: bold; + } + + &__input .input { + display: inline-block; + width: 100px; + } +} diff --git a/src/open_inwoner/scss/components/_index.scss b/src/open_inwoner/scss/components/_index.scss index 5d68b93fdb..aaf940dec5 100644 --- a/src/open_inwoner/scss/components/_index.scss +++ b/src/open_inwoner/scss/components/_index.scss @@ -4,6 +4,7 @@ @import './Autocomplete/Autocomplete.scss'; @import './Button/Button.scss'; @import './Button/ButtonRow.scss'; +@import './Captcha/Captcha.scss'; @import './Card/Card.scss'; @import './Card/CardGrid.scss'; @import './Card/LocationCardList.scss'; diff --git a/src/open_inwoner/utils/forms.py b/src/open_inwoner/utils/forms.py index d8a680320e..eddb9bac1f 100644 --- a/src/open_inwoner/utils/forms.py +++ b/src/open_inwoner/utils/forms.py @@ -195,8 +195,8 @@ def generate_question_answer_pair( # exclude negative results num1, num2 = max(num1, num2), min(num1, num2) - question = _("What is {num1} {operator_str} {num2}?").format( - num1=num1, operator_str=operator, num2=num2 + question = _("What is {num1} {operator} {num2}?").format( + num1=num1, operator=operator, num2=num2 ) match operator: