commonground-api-common 2.3.0__py3-none-any.whl → 2.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: commonground-api-common
3
- Version: 2.3.0
3
+ Version: 2.5.0
4
4
  Summary: Commonground API tooling
5
5
  Home-page: https://github.com/maykinmedia/commonground-api-common
6
6
  Author: Maykin Media, VNG-Realisatie
@@ -61,7 +61,7 @@ Requires-Dist: drf-extra-fields; extra == "tests"
61
61
  Provides-Extra: testutils
62
62
  Requires-Dist: zgw-consumers-oas; extra == "testutils"
63
63
  Provides-Extra: setup-configuration
64
- Requires-Dist: django-setup-configuration>=0.4.0; extra == "setup-configuration"
64
+ Requires-Dist: django-setup-configuration>=0.7.0; extra == "setup-configuration"
65
65
  Provides-Extra: pep8
66
66
  Requires-Dist: flake8; extra == "pep8"
67
67
  Provides-Extra: coverage
@@ -1,7 +1,7 @@
1
- commonground_api_common-2.3.0.data/scripts/generate_schema,sha256=OpKgzlFc_uzA3TVW_vHSYXAD_feLaCdTEnkWjIcxVzA,280
2
- vng_api_common/__init__.py,sha256=CpK8IH_dCUAwg9tqv7zm9FxbBFkxCnED1JUiRe7cftU,22
1
+ commonground_api_common-2.5.0.data/scripts/generate_schema,sha256=OpKgzlFc_uzA3TVW_vHSYXAD_feLaCdTEnkWjIcxVzA,280
2
+ vng_api_common/__init__.py,sha256=fMbNgIJqxiZEaSBLadLBt4rZpCHqarzb4Okt-aWsp2E,22
3
3
  vng_api_common/admin.py,sha256=iFtUPGf-ha0I-bXgq8QIFrP23Kzk_H3FlgAjt0U-ip0,259
4
- vng_api_common/apps.py,sha256=14vSvFX2H6alME95uOK9aL5TIWI3reiOW86Qa9kmhNw,3610
4
+ vng_api_common/apps.py,sha256=QQiJXRmjX9Q91oh0P9fvVnHe3NSYd1cEcUUBw0HLBCA,3690
5
5
  vng_api_common/checks.py,sha256=tOyfV7MMLGh4anrd_W30LvJCxiyQ4sFs1mGd9mtrEc0,1175
6
6
  vng_api_common/choices.py,sha256=dboFRoM34GpRUpxB9WexexccopcQSogu1QIyY4B9ACY,541
7
7
  vng_api_common/client.py,sha256=HNLc86RwczAudPBDgH_zQncE19OUaLyhSnacQRxJO0c,1972
@@ -28,12 +28,12 @@ vng_api_common/routers.py,sha256=hEnhBulkgMM-7W_lYaykKTgTBj3-avl7DGsR9P7BbTU,189
28
28
  vng_api_common/schema.py,sha256=axs2Q8IXwpHNd5WscQg5xOErL6bWhP8WFItTt4xCFO4,16305
29
29
  vng_api_common/scopes.py,sha256=PGs6CkXorAAdWXGFY1bSy-jmsPn122Njen9aFFOpFIQ,2351
30
30
  vng_api_common/search.py,sha256=yehS6boCOk1JXLCqAMU-B62hWtbTBSf_WKIVGPgp0Mg,1045
31
- vng_api_common/serializers.py,sha256=7_7IotlRfVb0woe6Wy79l_el3sPzrSY8-bfiYLbEUqs,10162
31
+ vng_api_common/serializers.py,sha256=NdrZJqP7p54lRKoKG4mEDS9MqaMcPESIr4dB1tnLaqI,10163
32
32
  vng_api_common/urls.py,sha256=9IWHYLlEIIHNaZ_Zq02qNQ2HJpETb7o-89r7yBM_tQs,270
33
33
  vng_api_common/utils.py,sha256=zrtpssOA-NcJHhAlxioBiXeY3G2R_uf0l8oWkDD_EiE,8511
34
- vng_api_common/validators.py,sha256=Y1OQrmnH3U01hnCizWc_xjpSSGUWKlwiFxeHHGCThpI,11012
34
+ vng_api_common/validators.py,sha256=ejaFZvFXFaBlqxjA2_07NSHKHlG5pejrfC_GHjwCj6E,12852
35
35
  vng_api_common/version.py,sha256=yJV9_yTM7Qnzg0zGNkJQkN9Uai3I_ZUkcyseJRPRk5I,129
36
- vng_api_common/views.py,sha256=VnvlpDmzBeSkDB9a-pBUkqBncKO7TT-6bY5zbYP4QOk,7607
36
+ vng_api_common/views.py,sha256=pxpI2dl22I9auTYvRJ-Rx-_NHAKgo1F2QwQJF6WIjrE,7603
37
37
  vng_api_common/viewsets.py,sha256=z5pzvSymFiiuCjP_-uuW-3OJKZY_psPAt8fWeWySU0c,2278
38
38
  vng_api_common/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
39
  vng_api_common/api/permissions.py,sha256=okbwiscxlAtbQWTCRDLL2reOxgj0rRDZeDcrtXAYq00,739
@@ -108,7 +108,7 @@ vng_api_common/conf/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
108
108
  vng_api_common/conf/api.py,sha256=Lx3Kk7S7mKxeaUr0dm6jbKrEh4WI2gye4i7QxN2x69E,3150
109
109
  vng_api_common/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
110
110
  vng_api_common/contrib/setup_configuration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
111
- vng_api_common/contrib/setup_configuration/models.py,sha256=ztev7KDGW0ESLl6jSuLx0tlNV58IOL3ibYEfVmjfv2Y,920
111
+ vng_api_common/contrib/setup_configuration/models.py,sha256=oqw0cOrbromC9CS3nWzfpDgOLg_xXyHoAi7jgw0f7Yk,1195
112
112
  vng_api_common/contrib/setup_configuration/steps.py,sha256=3jYRdHFlPq5zR-T-SPYTDp_Aipy0JK1HaJFrSgH4Vd0,1680
113
113
  vng_api_common/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
114
114
  vng_api_common/db/operations.py,sha256=3vj9zD4EntMSmYsNGN1pRDjAcVM68MESDdoAk9wl0U0,3333
@@ -182,7 +182,7 @@ vng_api_common/tests/auth.py,sha256=IKDWTEFv4Bign4F70-ibsFcnJqRxEJaXvqaPQJWa1xY,
182
182
  vng_api_common/tests/caching.py,sha256=zfIw5cRRvO9cekHZZKfRqZc8cx5IfJUYNmcH6cuIMg4,624
183
183
  vng_api_common/tests/schema.py,sha256=WDvifDQQiKqIpQijpeQ7rYkFroJmuPuHe7zNhl1Bigk,2293
184
184
  vng_api_common/tests/urls.py,sha256=PFrYzQbBC0TFPMEn3uPhcBG0IQs9JsEPqckicJT1UA4,2159
185
- commonground_api_common-2.3.0.dist-info/METADATA,sha256=Ke1dE5k_UQ-0ZdksTJ9aBp_AxOy0ZZh3OxtgTn5AS4k,6988
186
- commonground_api_common-2.3.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
187
- commonground_api_common-2.3.0.dist-info/top_level.txt,sha256=vPismc83zPzWXTmlNCCwfDlFV9iygJYxNJW5iDjKTgw,15
188
- commonground_api_common-2.3.0.dist-info/RECORD,,
185
+ commonground_api_common-2.5.0.dist-info/METADATA,sha256=h6PrcdoJEkOrGklI9qIKWV6YsNIpPilsXP2fG1m-P0Q,6988
186
+ commonground_api_common-2.5.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
187
+ commonground_api_common-2.5.0.dist-info/top_level.txt,sha256=vPismc83zPzWXTmlNCCwfDlFV9iygJYxNJW5iDjKTgw,15
188
+ commonground_api_common-2.5.0.dist-info/RECORD,,
@@ -1 +1 @@
1
- __version__ = "2.3.0"
1
+ __version__ = "2.5.0"
vng_api_common/apps.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import logging
2
2
 
3
3
  from django.apps import AppConfig
4
+ from django.core.exceptions import ImproperlyConfigured
4
5
  from django.db import models
5
6
  from django.forms.fields import CharField
6
7
  from django.utils.translation import gettext_lazy as _
@@ -89,7 +90,7 @@ def register_geojson_field_extension() -> None:
89
90
  """
90
91
  try:
91
92
  from rest_framework_gis.fields import GeometryField # noqa
92
- except ImportError:
93
+ except (ImportError, ImproperlyConfigured):
93
94
  logger.debug(
94
95
  "Could not import djangorestframework-gis, skipping "
95
96
  "GeometryFieldExtension registration."
@@ -13,10 +13,14 @@ class SingleJWTSecretConfigurationModel(ConfigurationModel):
13
13
  "secret",
14
14
  ]
15
15
  }
16
+ extra_kwargs = {
17
+ "identifier": {"examples": ["application-name"]},
18
+ "secret": {"examples": ["modify-this"]},
19
+ }
16
20
 
17
21
 
18
22
  class JWTSecretsConfigurationModel(ConfigurationModel):
19
- items: list[SingleJWTSecretConfigurationModel] = Field(default_factory=list)
23
+ items: list[SingleJWTSecretConfigurationModel] = Field()
20
24
 
21
25
 
22
26
  class SingleApplicatieConfigurationModel(ConfigurationModel):
@@ -26,7 +30,11 @@ class SingleApplicatieConfigurationModel(ConfigurationModel):
26
30
  django_model_refs = {
27
31
  Applicatie: ["uuid", "client_ids", "label", "heeft_alle_autorisaties"]
28
32
  }
33
+ extra_kwargs = {
34
+ "client_ids": {"examples": [["open-notificaties-prod"]]},
35
+ "label": {"examples": ["Open Notificaties (productie)"]},
36
+ }
29
37
 
30
38
 
31
39
  class ApplicatieConfigurationModel(ConfigurationModel):
32
- items: list[SingleApplicatieConfigurationModel] = Field(default_factory=list)
40
+ items: list[SingleApplicatieConfigurationModel]
@@ -91,7 +91,7 @@ class ValidatieFoutSerializer(FoutSerializer):
91
91
 
92
92
 
93
93
  def add_choice_values_help_text(
94
- choices: Union[models.Choices, List[Tuple[str, str]]]
94
+ choices: Union[models.Choices, List[Tuple[str, str]]],
95
95
  ) -> str:
96
96
  is_dj_choices = inspect.isclass(choices) and issubclass(choices, models.Choices)
97
97
 
@@ -5,7 +5,6 @@ from typing import Callable
5
5
 
6
6
  from django.conf import settings
7
7
  from django.core.exceptions import ValidationError
8
- from django.core.validators import RegexValidator
9
8
  from django.utils import timezone
10
9
  from django.utils.deconstruct import deconstructible
11
10
  from django.utils.module_loading import import_string
@@ -13,7 +12,7 @@ from django.utils.translation import gettext_lazy as _
13
12
 
14
13
  from rest_framework import serializers, validators
15
14
 
16
- from .constants import RSIN_LENGTH
15
+ from .constants import BSN_LENGTH, RSIN_LENGTH
17
16
  from .oas import fetcher, obj_has_shape
18
17
 
19
18
  logger = logging.getLogger(__name__)
@@ -22,6 +21,90 @@ logger = logging.getLogger(__name__)
22
21
  WORD_REGEX = re.compile(r"[\w\-]+$", re.ASCII)
23
22
 
24
23
 
24
+ class BaseIdentifierValidator:
25
+ """
26
+ Validator base class that performs common validation logic.
27
+ Digit check, length, and optional 11-proof check.
28
+ """
29
+
30
+ error_messages = {
31
+ "isdigit": _("Voer een numerieke waarde in"),
32
+ "length": _("Waarde moet %(identifier_length)s tekens lang zijn"),
33
+ "11proefnumber": _("Ongeldige code"),
34
+ }
35
+
36
+ def __init__(
37
+ self,
38
+ value: str,
39
+ identifier_length: int,
40
+ validate_11proef: bool = False,
41
+ ):
42
+ self.value = value
43
+ self.identifier_length = identifier_length
44
+ self.validate_11proef = validate_11proef
45
+
46
+ def validate_isdigit(self) -> None:
47
+ """Validates that the value contains only digits."""
48
+ if not self.value.isdigit():
49
+ raise ValidationError(self.error_messages["isdigit"], code="only-digits")
50
+
51
+ def validate_length(self) -> None:
52
+ """Validates that the length of the value is within the allowed sizes."""
53
+ if len(self.value) != self.identifier_length:
54
+ raise ValidationError(
55
+ self.error_messages["length"]
56
+ % {"identifier_length": self.identifier_length},
57
+ code="invalid-length",
58
+ )
59
+
60
+ def validate_11proefnumber(self) -> None:
61
+ """Validates the value based on the 11-proof check."""
62
+ total = 0
63
+ for multiplier, char in enumerate(reversed(self.value), start=1):
64
+ if multiplier == 1:
65
+ total += -multiplier * int(char)
66
+ else:
67
+ total += multiplier * int(char)
68
+
69
+ if total % 11 != 0:
70
+ raise ValidationError(self.error_messages["11proefnumber"], code="invalid")
71
+
72
+ def validate(self) -> None:
73
+ self.validate_isdigit()
74
+ self.validate_length()
75
+ if self.validate_11proef:
76
+ self.validate_11proefnumber()
77
+
78
+
79
+ def validate_rsin(value: str) -> None:
80
+ """
81
+ Validates that a string value is a valid RSIN number by applying the
82
+ '11-proef' checking.
83
+
84
+ :param value: String object representing a presumably good RSIN number.
85
+ """
86
+
87
+ validator = BaseIdentifierValidator(
88
+ value, identifier_length=RSIN_LENGTH, validate_11proef=True
89
+ )
90
+ validator.error_messages["11proefnumber"] = _("Onjuist RSIN nummer")
91
+ validator.validate()
92
+
93
+
94
+ def validate_bsn(value: str) -> None:
95
+ """
96
+ Validates that a string value is a valid BSN number by applying the
97
+ '11-proef' checking.
98
+
99
+ :param value: String object representing a presumably good BSN number.
100
+ """
101
+ validator = BaseIdentifierValidator(
102
+ value, identifier_length=BSN_LENGTH, validate_11proef=True
103
+ )
104
+ validator.error_messages["11proefnumber"] = _("Onjuist BSN nummer")
105
+ validator.validate()
106
+
107
+
25
108
  @deconstructible
26
109
  class AlphanumericExcludingDiacritic:
27
110
  """
@@ -73,37 +156,6 @@ def validate_non_negative_string(value):
73
156
  raise ValidationError("De waarde moet een niet-negatief getal zijn.")
74
157
 
75
158
 
76
- validate_digits = RegexValidator(
77
- regex="^[0-9]+$", message="Waarde moet numeriek zijn.", code="only-digits"
78
- )
79
-
80
-
81
- def validate_rsin(value):
82
- """
83
- Validates that a string value is a valid RSIN number by applying the
84
- '11-proef' checking.
85
-
86
- :param value: String object representing a presumably good RSIN number.
87
- """
88
- # Initial sanity checks.
89
- validate_digits(value)
90
- if len(value) != RSIN_LENGTH:
91
- raise ValidationError(
92
- "RSIN moet %s tekens lang zijn." % RSIN_LENGTH, code="invalid-length"
93
- )
94
-
95
- # 11-proef check.
96
- total = 0
97
- for multiplier, char in enumerate(reversed(value), start=1):
98
- if multiplier == 1:
99
- total += -multiplier * int(char)
100
- else:
101
- total += multiplier * int(char)
102
-
103
- if total % 11 != 0:
104
- raise ValidationError("Onjuist RSIN nummer.", code="invalid")
105
-
106
-
107
159
  class URLValidator:
108
160
  """
109
161
  Validate that the URL actually resolves to a HTTP 200
vng_api_common/views.py CHANGED
@@ -184,12 +184,12 @@ def _test_nrc_config(check_autorisaties_subscription=True) -> list:
184
184
  nrc_client: Optional[Client] = NotificationsConfig.get_client()
185
185
 
186
186
  if not nrc_client:
187
- return [((_("NRC"), _("Missing"), False))]
187
+ return [(_("NRC"), _("Missing"), False)]
188
188
 
189
189
  has_nrc_auth = nrc_client.auth is not None if nrc_client else False
190
190
 
191
191
  if not nrc_config.notifications_api_service:
192
- checks = [((_("NRC"), _("Missing"), False))]
192
+ checks = [(_("NRC"), _("Missing"), False)]
193
193
  return checks
194
194
 
195
195
  checks = [