|
6 | 6 | from onegov.form import Form |
7 | 7 | from onegov.form import parse_form |
8 | 8 | from onegov.form.fields import UploadField |
9 | | -from onegov.form.validators import ExpectedExtensions |
| 9 | +from onegov.form.validators import ExpectedExtensions, PhoneNumberType |
10 | 10 | from onegov.form.validators import ImageSizeLimit |
11 | 11 | from onegov.form.validators import InputRequiredIf |
12 | 12 | from onegov.form.validators import ValidSwissSocialSecurityNumber |
@@ -82,47 +82,120 @@ def __init__(self, data: int | str | None) -> None: |
82 | 82 | validator(request, Field(None)) |
83 | 83 | validator(request, Field('')) |
84 | 84 |
|
| 85 | + # non-swiss numbers are allowed by default |
| 86 | + validator(request, Field('+4909562181751')) # DE |
| 87 | + validator(request, Field('+4319876543')) # A |
| 88 | + validator(request, Field('+43695621817')) # A |
| 89 | + validator(request, Field('+330956218175')) # FR |
| 90 | + validator(request, Field('+390612345678')) # IT |
| 91 | + |
85 | 92 | validator(request, Field('+41791112233')) |
86 | 93 | validator(request, Field('0041791112233')) |
87 | 94 | validator(request, Field('0791112233')) |
88 | 95 |
|
89 | | - # non-swiss numbers are allowed by default |
90 | | - validator(request, Field('+4909562181751')) |
| 96 | + def error(data: int | str | None) -> str: |
| 97 | + with raises(ValidationError) as exception: |
| 98 | + validator(request, Field(data)) |
| 99 | + return exception.value.args[0].interpolate() |
91 | 100 |
|
92 | | - with raises(ValidationError): |
93 | | - validator(request, Field(1234)) |
94 | | - with raises(ValidationError): |
95 | | - validator(request, Field('1234')) |
| 101 | + # numbers that cannot be parsed at all |
| 102 | + assert error(1234) == 'Not a valid phone number.' |
| 103 | + assert error('not a number') == 'Not a valid phone number.' |
96 | 104 |
|
97 | | - with raises(ValidationError): |
98 | | - validator(request, Field('+417911122333')) |
99 | | - with raises(ValidationError): |
100 | | - validator(request, Field('041791112233')) |
101 | | - with raises(ValidationError): |
102 | | - validator(request, Field('041791112233')) |
103 | | - with raises(ValidationError): |
104 | | - validator(request, Field('00791112233')) |
| 105 | + # swiss numbers are 9 or 12 digits long, so anything shorter, longer |
| 106 | + # or in between reports the same length error |
| 107 | + invalid_length = 'This phone number has an invalid length.' |
| 108 | + assert error('1234') == invalid_length |
| 109 | + assert error('00791112233') == invalid_length |
| 110 | + assert error('+417911122334455') == invalid_length |
| 111 | + assert error('079111223344556677') == invalid_length |
| 112 | + assert error('+417911122333') == invalid_length |
| 113 | + assert error('+4179111223344') == invalid_length |
105 | 114 |
|
| 115 | + # plausible length, but no such number exists |
| 116 | + assert error('041791112233') == 'This phone number does not exist.' |
106 | 117 |
|
107 | | -def test_phone_number_validator_whitelist() -> None: |
| 118 | + validator = ValidPhoneNumber(country='US') |
| 119 | + assert error('2345678') == 'Please include the area code.' |
108 | 120 |
|
109 | | - class Field(BaseField): |
110 | | - def __init__(self, data: str | None) -> None: |
111 | | - self.data = data |
| 121 | + validator = ValidPhoneNumber(phone_type=PhoneNumberType.ANY.value) |
| 122 | + validator(request, Field('+41791112233')) |
| 123 | + validator(request, Field('0041791112233')) |
| 124 | + validator(request, Field('41791112233')) |
| 125 | + validator(request, Field('41791112233')) |
| 126 | + validator(request, Field('41781112233')) |
| 127 | + validator(request, Field('41771112233')) |
| 128 | + validator(request, Field('41761112233')) |
| 129 | + validator(request, Field('41411112233')) |
| 130 | + |
| 131 | + validator = ValidPhoneNumber(phone_type=PhoneNumberType.MOBILE.value) |
| 132 | + validator(request, Field('+41791112233')) |
| 133 | + validator(request, Field('0041791112233')) |
| 134 | + validator(request, Field('41791112233')) |
| 135 | + validator(request, Field('41791112233')) |
| 136 | + validator(request, Field('41781112233')) |
| 137 | + validator(request, Field('41771112233')) |
| 138 | + validator(request, Field('41761112233')) |
| 139 | + assert error('41411112233') == 'Please enter a mobile phone number.' |
| 140 | + |
| 141 | + validator = ValidPhoneNumber(phone_type=PhoneNumberType.FIXED_LINE.value) |
| 142 | + landline = 'Please enter a landline phone number.' |
| 143 | + assert error('+41791112233') == landline |
| 144 | + assert error('0041791112233') == landline |
| 145 | + assert error('41791112233') == landline |
| 146 | + assert error('41781112233') == landline |
| 147 | + assert error('41771112233') == landline |
| 148 | + assert error('41761112233') == landline |
| 149 | + validator(request, Field('41411112233')) |
| 150 | + |
| 151 | + # the number type is only checked once the number itself is valid |
| 152 | + assert error('041791112233') == 'This phone number does not exist.' |
112 | 153 |
|
113 | 154 | validator = ValidPhoneNumber(country_whitelist={'CH'}) |
114 | | - |
115 | | - request: Any = None |
116 | 155 | validator(request, Field(None)) |
117 | 156 | validator(request, Field('')) |
118 | 157 |
|
119 | 158 | validator(request, Field('+41791112233')) |
120 | 159 | validator(request, Field('0041791112233')) |
121 | 160 | validator(request, Field('0791112233')) |
122 | 161 |
|
123 | | - with raises(ValidationError): |
124 | | - # not a swiss number |
125 | | - validator(request, Field('+4909562181751')) |
| 162 | + # not a swiss number |
| 163 | + unsupported = 'Phone numbers from this country are not supported.' |
| 164 | + assert error('+4909562181751') == ( # DE |
| 165 | + f'{unsupported} Allowed countries: CH' |
| 166 | + ) |
| 167 | + |
| 168 | + # the whitelist is listed in a stable order |
| 169 | + validator = ValidPhoneNumber(country_whitelist={'LI', 'CH', 'AT'}) |
| 170 | + assert error('+4909562181751') == ( # DE |
| 171 | + f'{unsupported} Allowed countries: AT, CH, LI' |
| 172 | + ) |
| 173 | + |
| 174 | + # every whitelisted country is accepted |
| 175 | + validator(request, Field('+41791112233')) # CH |
| 176 | + validator(request, Field('+4319876543')) # AT |
| 177 | + validator(request, Field('+4232371234')) # LI |
| 178 | + |
| 179 | + # numbers from anywhere else are not, no matter how far away |
| 180 | + assert error('+390612345678').startswith(unsupported) # IT |
| 181 | + assert error('+12025550123').startswith(unsupported) # US |
| 182 | + |
| 183 | + # an invalid number is reported as such, not as a country problem |
| 184 | + assert error('+417911122333') == invalid_length |
| 185 | + assert error('+42366012345') == invalid_length |
| 186 | + |
| 187 | + # the whitelist is combined with the other checks |
| 188 | + validator = ValidPhoneNumber( |
| 189 | + country_whitelist={'CH', 'AT'}, |
| 190 | + phone_type=PhoneNumberType.MOBILE.value |
| 191 | + ) |
| 192 | + validator(request, Field('+41791112233')) |
| 193 | + assert error('+41411112233') == 'Please enter a mobile phone number.' |
| 194 | + assert error('+390612345678').startswith(unsupported) # IT |
| 195 | + |
| 196 | + # the default country has to be part of the whitelist |
| 197 | + with raises(AssertionError): |
| 198 | + ValidPhoneNumber(country='DE', country_whitelist={'CH'}) |
126 | 199 |
|
127 | 200 |
|
128 | 201 | def test_input_required_if_validator() -> None: |
|
0 commit comments