From 25902aa92b7f6cfeff74f1ae2c85b051bbd690d0 Mon Sep 17 00:00:00 2001 From: Gurdeep Atwal Date: Mon, 30 Dec 2024 18:43:41 +0000 Subject: [PATCH] changed so it cleans data --- core/helpers.py | 4 + exporter/applications/forms/parties.py | 12 ++- exporter/core/validators.py | 12 --- .../applications/forms/test_parties.py | 74 ++++++++++--------- 4 files changed, 54 insertions(+), 48 deletions(-) diff --git a/core/helpers.py b/core/helpers.py index 44c7870567..ff68e3cfae 100644 --- a/core/helpers.py +++ b/core/helpers.py @@ -72,3 +72,7 @@ def stream_document_response(api_response): ]: response.headers[header_to_copy] = api_response.headers[header_to_copy] return response + + +def remove_non_printable_characters(str): + return "".join([c for c in str if ord(c) > 31 or ord(c) == 9 or ord(c) == 10]) diff --git a/exporter/applications/forms/parties.py b/exporter/applications/forms/parties.py index 823ebfeed3..e7be51a22c 100644 --- a/exporter/applications/forms/parties.py +++ b/exporter/applications/forms/parties.py @@ -1,3 +1,4 @@ +from core.helpers import remove_non_printable_characters from crispy_forms_gds.choices import Choice from crispy_forms_gds.helper import FormHelper from crispy_forms_gds.layout import Layout, Submit, HTML @@ -11,7 +12,6 @@ from core.forms.widgets import Autocomplete from exporter.core.constants import CaseTypes, FileUploadFileTypes from exporter.core.services import get_countries -from exporter.core.validators import SpecialCharacterStringValidator from lite_content.lite_exporter_frontend import strings from lite_content.lite_exporter_frontend.applications import PartyForm, PartyTypeForm from lite_forms.common import country_question @@ -223,10 +223,13 @@ class PartyNameForm(BaseForm): 80, f"End user name should be 80 characters or less", ), - SpecialCharacterStringValidator(), ], ) + def clean_name(self): + name = self.cleaned_data["name"] + return remove_non_printable_characters(name) + def get_layout_fields(self): return ("name",) @@ -302,7 +305,6 @@ class PartyAddressForm(BaseForm): address = forms.CharField( widget=forms.Textarea(attrs={"rows": "10"}), error_messages={"required": "Enter an address"}, - validators=[SpecialCharacterStringValidator()], ) country = forms.ChoiceField( choices=[("", "Select a country")], error_messages={"required": "Select the country"} @@ -318,6 +320,10 @@ def __init__(self, *args, **kwargs): country_choices = [(country["id"], country["name"]) for country in countries] self.fields["country"].choices += country_choices + def clean_address(self): + address = self.cleaned_data["address"] + return remove_non_printable_characters(address) + def get_layout_fields(self): return ( "address", diff --git a/exporter/core/validators.py b/exporter/core/validators.py index 2b0345e942..f7960cad7b 100644 --- a/exporter/core/validators.py +++ b/exporter/core/validators.py @@ -1,6 +1,5 @@ from datetime import date from dateutil.relativedelta import relativedelta -import re from django.core.exceptions import ValidationError from django.utils import timezone @@ -53,14 +52,3 @@ def __init__(self, message, **kwargs): def __call__(self, value): if value > (date.today() + self.relativedelta): raise ValidationError(self.message) - - -class SpecialCharacterStringValidator: - message = "There's a invalid special charactor in this field." - regex_string = r"^[\000-\031]" - - def __call__(self, value): - if value: - match_regex = re.compile(self.regex_string) - if bool(match_regex.match(value)): - raise ValidationError(self.message) diff --git a/unit_tests/exporter/applications/forms/test_parties.py b/unit_tests/exporter/applications/forms/test_parties.py index df1548a2dd..9d9fcf2c93 100644 --- a/unit_tests/exporter/applications/forms/test_parties.py +++ b/unit_tests/exporter/applications/forms/test_parties.py @@ -84,6 +84,24 @@ def test_consignee_name_form(data, valid, errors): assert form.errors == errors +@pytest.mark.parametrize( + "data, expected", + ( + ({"name": "\x02 test1"}, " test1"), + ({"name": "\x02test2"}, "test2"), + ({"name": "this is \n test4"}, "this is \n test4"), + ({"name": "namé 5"}, "namé 5"), + ({"name": "namé's"}, "namé's"), + ({"name": "test 6"}, "test 6"), + ), +) +def test_consignee_name_removes_non_printable(data, expected): + form = parties.ConsigneeNameForm(data=data) + + form.is_valid() + assert form.cleaned_data["name"] == expected + + @pytest.mark.parametrize( "data, valid, errors", ( @@ -94,17 +112,6 @@ def test_consignee_name_form(data, valid, errors): False, {"name": [f"End user name should be 80 characters or less"]}, ), - ( - {"name": "\x02 control chars not allowed"}, - False, - {"name": ["There's a invalid special charactor in this field."]}, - ), - ({"name": "control \x1A is allowed"}, True, None), - ( - {"name": "\x00 control chars not allowed"}, - False, - {"name": ["There's a invalid special charactor in this field.", "Null characters are not allowed."]}, - ), ), ) def test_end_user_name_form(data, valid, errors): @@ -179,17 +186,6 @@ def test_consignee_website_form(data, valid, errors): ({"address": "this\r\nis\r\ninvalid", "country": "aus"}, True, None), ({"address": "this_is_not", "country": "aus"}, True, None), ({"address": "this\w\ais\a\ainvalid", "country": "aus"}, True, None), - ( - {"address": "\x02 control chars not allowed", "country": "aus"}, - False, - {"address": ["There's a invalid special charactor in this field."]}, - ), - ({"address": "control \x1A is allowed", "country": "aus"}, True, None), - ( - {"address": "\x00 control chars not allowed", "country": "aus"}, - False, - {"address": ["There's a invalid special charactor in this field.", "Null characters are not allowed."]}, - ), ), ) @patch("exporter.applications.forms.parties.get_countries") @@ -208,6 +204,29 @@ class Request: assert form.errors == errors +@pytest.mark.parametrize( + "data, expected", + ( + ({"address": "1 somewhere", "country": "aus"}, "1 somewhere"), + ({"address": "1 \x02 somewhere", "country": "aus"}, "1 somewhere"), + ({"address": "1 \x02 \n somewhere's", "country": "aus"}, "1 \n somewhere's"), + ({"address": "1 \x01somewhere", "country": "aus"}, "somewhere"), + ({"address": "1 \x03 \n somewhere", "country": "aus"}, "1 somewhere"), + ({"address": "1 \x03 \n ô somewhere", "country": "aus"}, "1 ô somewhere"), + ), +) +@patch("exporter.applications.forms.parties.get_countries") +def test_end_user_address_removes_non_printable(mock_get_countries, data, expected): + class Request: + csp_nonce = "test" + + request = Request() + mock_get_countries.return_value = [{"id": "aus", "name": "Austria"}, {"id": "fr", "name": "France"}] + form = parties.EndUserAddressForm(request=request, data=data) + + form.is_valid() + + @pytest.mark.parametrize( "data, valid, errors", ( @@ -215,17 +234,6 @@ class Request: ({"address": "", "country": ""}, False, {"address": ["Enter an address"], "country": ["Select the country"]}), ({"address": "This-is-a-valid-address", "country": "aus"}, True, None), ({"address": "this\r\nis\r\ninvalid", "country": "aus"}, True, None), - ( - {"address": "\x02 control chars not allowed", "country": "aus"}, - False, - {"address": ["There's a invalid special charactor in this field."]}, - ), - ({"address": "control \x1A is allowed", "country": "aus"}, True, None), - ( - {"address": "\x00 control chars not allowed", "country": "aus"}, - False, - {"address": ["There's a invalid special charactor in this field.", "Null characters are not allowed."]}, - ), ), ) @patch("exporter.applications.forms.parties.get_countries")