commonground-api-common 2.6.4__py3-none-any.whl → 2.6.6__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.4
2
2
  Name: commonground-api-common
3
- Version: 2.6.4
3
+ Version: 2.6.6
4
4
  Summary: Commonground API tooling
5
5
  Home-page: https://github.com/maykinmedia/commonground-api-common
6
6
  Author: Maykin Media, VNG-Realisatie
@@ -18,6 +18,7 @@ Classifier: Programming Language :: Python :: 3
18
18
  Classifier: Programming Language :: Python :: 3 :: Only
19
19
  Classifier: Programming Language :: Python :: 3.10
20
20
  Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
21
22
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
23
  Requires-Dist: django>=4.2.0
23
24
  Requires-Dist: django-filter<=25.1,>=23.1
@@ -33,7 +34,6 @@ Requires-Dist: zgw-consumers>=0.35.1
33
34
  Requires-Dist: oyaml
34
35
  Requires-Dist: PyJWT>=2.1.1
35
36
  Requires-Dist: requests
36
- Requires-Dist: requests-mock
37
37
  Requires-Dist: coreapi
38
38
  Requires-Dist: ape-pie
39
39
  Provides-Extra: markdown-docs
@@ -45,24 +45,23 @@ Provides-Extra: drf-extra-fields
45
45
  Requires-Dist: drf-extra-fields>=3.7.0; extra == "drf-extra-fields"
46
46
  Provides-Extra: tests
47
47
  Requires-Dist: psycopg2; extra == "tests"
48
- Requires-Dist: pytest; extra == "tests"
48
+ Requires-Dist: pytest==8.3.5; extra == "tests"
49
49
  Requires-Dist: pytest-django; extra == "tests"
50
50
  Requires-Dist: pytest-dotenv; extra == "tests"
51
51
  Requires-Dist: pytest-factoryboy; extra == "tests"
52
52
  Requires-Dist: tox; extra == "tests"
53
- Requires-Dist: isort; extra == "tests"
54
- Requires-Dist: black; extra == "tests"
53
+ Requires-Dist: ruff; extra == "tests"
55
54
  Requires-Dist: requests-mock; extra == "tests"
56
55
  Requires-Dist: freezegun; extra == "tests"
57
56
  Requires-Dist: zgw-consumers-oas; extra == "tests"
58
57
  Requires-Dist: djangorestframework-gis; extra == "tests"
59
58
  Requires-Dist: drf-extra-fields; extra == "tests"
59
+ Provides-Extra: oas
60
+ Requires-Dist: requests-mock; extra == "oas"
60
61
  Provides-Extra: testutils
61
62
  Requires-Dist: zgw-consumers-oas; extra == "testutils"
62
63
  Provides-Extra: setup-configuration
63
64
  Requires-Dist: django-setup-configuration>=0.7.0; extra == "setup-configuration"
64
- Provides-Extra: pep8
65
- Requires-Dist: flake8; extra == "pep8"
66
65
  Provides-Extra: coverage
67
66
  Requires-Dist: pytest-cov; extra == "coverage"
68
67
  Provides-Extra: docs
@@ -76,7 +75,12 @@ Requires-Dist: bump2version; extra == "release"
76
75
  Commonground-API-common - Tooling voor RESTful APIs
77
76
  ===================================================
78
77
 
79
- |build-status| |code-quality| |coverage| |docs| |black|
78
+
79
+ :Version: 2.6.6
80
+ :Source: https://github.com/maykinmedia/commonground-api-common
81
+ :PythonVersion: 3.12
82
+
83
+ |build-status| |code-quality| |coverage| |docs| |ruff|
80
84
 
81
85
  |python-versions| |django-versions| |pypi-version|
82
86
 
@@ -105,7 +109,7 @@ Features
105
109
  * Niet-negatieve waarde validator
106
110
  * Alfanumerieke waarde (zonder diacritics)
107
111
  * URL-validator (test dat URL bestaat) met pluggable link-checker
108
- * ``UntilNowValidator`` - valideer datetimes tot en met *nu*.
112
+ * ``UntilNowValidator`` - valideer datetimes tot en met *nu*. (Via de TIME_LEEWAY setting kan speling worden toegevoegd)
109
113
  * ``UniekeIdentificatieValidator`` (in combinatie met organisatie)
110
114
  * ``InformatieObjectUniqueValidator`` om te valideren dat M2M entries
111
115
  slechts eenmalig voorkomen
@@ -158,7 +162,8 @@ Features
158
162
  .. |pypi-version| image:: https://img.shields.io/pypi/v/commonground-api-common.svg
159
163
  :target: https://pypi.org/project/commonground-api-common/
160
164
 
161
- .. |black| image:: https://img.shields.io/badge/code%20style-black-000000.svg
162
- :target: https://github.com/psf/black
165
+ .. |ruff| image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
166
+ :target: https://github.com/astral-sh/ruff
167
+ :alt: Ruff
163
168
 
164
169
  .. _documentatie: https://commonground-api-common.readthedocs.io/en/latest/?badge=latest
@@ -1,40 +1,40 @@
1
- commonground_api_common-2.6.4.data/scripts/generate_schema,sha256=OpKgzlFc_uzA3TVW_vHSYXAD_feLaCdTEnkWjIcxVzA,280
2
- vng_api_common/__init__.py,sha256=ODIwI6SfzWmx_FdtwCfr6k5TmpNuA5JdvGyV-9G9YrM,22
3
- vng_api_common/admin.py,sha256=iFtUPGf-ha0I-bXgq8QIFrP23Kzk_H3FlgAjt0U-ip0,259
1
+ commonground_api_common-2.6.6.data/scripts/generate_schema,sha256=OpKgzlFc_uzA3TVW_vHSYXAD_feLaCdTEnkWjIcxVzA,280
2
+ vng_api_common/__init__.py,sha256=MJHGx-Qo0nycI7WHSavnK8Mok6HS_De_qLfGWXih6Og,22
3
+ vng_api_common/admin.py,sha256=WiD6afzO9sJh_Nz7TKsxCiGm49vS0qQH1PxyXnGpEt8,204
4
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
- vng_api_common/client.py,sha256=HNLc86RwczAudPBDgH_zQncE19OUaLyhSnacQRxJO0c,1972
7
+ vng_api_common/client.py,sha256=2qLi5BvSiPZ2J93X7_-WFx7F9qBv-y3FhSt5e31QBVo,1971
8
8
  vng_api_common/compat.py,sha256=n4jDFSPzXnh-D_VXjftKMCJYj_q_t6eJrUTWLayl8jQ,768
9
- vng_api_common/constants.py,sha256=yYtnYId9alRuhGBoqaO8lkXYi_ATi2FW-wEDGRpiRuQ,10948
9
+ vng_api_common/constants.py,sha256=_diFyf14vYCdRX8Ewb9IgaK4t8od6zuG_W48TxWL-Lo,11121
10
10
  vng_api_common/decorators.py,sha256=_p-mAyi5Na_-ll00ErcQ3mRoZNCsJzYDAliXn50Bmes,278
11
- vng_api_common/descriptors.py,sha256=RFOqnDn5PEX0-qXb_r4_9wdEvuck5wNxT4tcrP95KaE,3136
11
+ vng_api_common/descriptors.py,sha256=QJX9GINLnxpFDViyfX1SfSq3mowkN9Oq2tvj34qqkE4,3129
12
12
  vng_api_common/doc.py,sha256=a4Wm6Y-Va-tBsLwZFjPX_oA4PppkDR4wpIiw9q7NLd4,1167
13
13
  vng_api_common/exception_handling.py,sha256=Z8Si1-GPWaTtsgaFI_zLOvlnLVLM8jqfgFIimX8eo-8,4759
14
14
  vng_api_common/exceptions.py,sha256=7Qk5dlETjoQjZeGRKei4PkeLACLoZOMrMiuyi-yn6Kk,615
15
15
  vng_api_common/fields.py,sha256=SXY0HB9NiDVmlKdjBDy3b55E4rn-qboiIMBr_eOBuZE,6302
16
- vng_api_common/filters.py,sha256=mfpew4NkUy4AIqXDg5rE1tzUl8Ae9FTmYz9_MKjjLuA,3763
17
- vng_api_common/filters_backend.py,sha256=bb8D0Z6uT39PW5ASqlExTesALOVAplJgG4hR7ikG2BI,2096
16
+ vng_api_common/filters.py,sha256=E0Di4HsvaQUFfORn4uzxiVTCcJKeGMfnGSS9BNaX9Mg,3746
17
+ vng_api_common/filters_backend.py,sha256=VUJB6Ya8gwM4DVCffAy0Z3czGMRK6ZEQ8Kq7Rpdhjws,2041
18
18
  vng_api_common/filtersets.py,sha256=CpmuOg6jGKFDwVeCusax-CBI7tv-EuOSBLwewdkLu1Y,1256
19
19
  vng_api_common/generators.py,sha256=88yQN5-vRFUegfzQcsZtlpbtQyn_zZQwvs20OidPK7M,1239
20
20
  vng_api_common/geo.py,sha256=AZbrw0rwGYOmaSUk8JJSkx-4_tVrfT_cgggh9omRwhU,1862
21
21
  vng_api_common/middleware.py,sha256=2DRw0hPpvUMqwoH1Ze8S7tDB16lmj4Bnd6vN5ijkGM8,875
22
- vng_api_common/mocks.py,sha256=0sELLs-uy2ndu29m5P6FN_p1ehNhYv7IoRayYPs379Y,6200
22
+ vng_api_common/mocks.py,sha256=9vL4t-CLIFFgL6MxeyaQy1UP91lrObYI-s3-0h2q3YU,6209
23
23
  vng_api_common/models.py,sha256=3WgpCWQpkCOrMCtqp7EbnP681II43Sg_cch8ZOm4EcU,1707
24
24
  vng_api_common/oas.py,sha256=ATqqNM7zkDMoK3E-cxNh_c65n6YCrP96KxCFYfkEVK0,2523
25
25
  vng_api_common/pagination.py,sha256=U2zojaSHgEIzCEMBzx9r3KLpAujMCdM0ndH3AT6ik1U,734
26
26
  vng_api_common/permissions.py,sha256=ayDxk9Wt8j0yO57FhZ8XaRkPET4lAqd8SSw3m4o3EGs,7562
27
27
  vng_api_common/polymorphism.py,sha256=N-x39pG2unD4N0ZbxFvuhE8ibPaJ0eKeqfvAJW3NnEU,6623
28
- vng_api_common/routers.py,sha256=hEnhBulkgMM-7W_lYaykKTgTBj3-avl7DGsR9P7BbTU,1897
28
+ vng_api_common/routers.py,sha256=UVx7g7UCw7kSQswSVN8fwOGNO0y9vWeHTXHPuMT0h7c,1897
29
29
  vng_api_common/schema.py,sha256=axs2Q8IXwpHNd5WscQg5xOErL6bWhP8WFItTt4xCFO4,16305
30
30
  vng_api_common/scopes.py,sha256=PGs6CkXorAAdWXGFY1bSy-jmsPn122Njen9aFFOpFIQ,2351
31
31
  vng_api_common/search.py,sha256=yehS6boCOk1JXLCqAMU-B62hWtbTBSf_WKIVGPgp0Mg,1045
32
- vng_api_common/serializers.py,sha256=D0DEw-iw4se1MLAlDw25G6q4g1BTEL3VXcuvMTj6qlk,13462
32
+ vng_api_common/serializers.py,sha256=ohdUC11RGMxZQcN2ekLappgT4SbYz12o4GZ7maVS3RY,13464
33
33
  vng_api_common/urls.py,sha256=9IWHYLlEIIHNaZ_Zq02qNQ2HJpETb7o-89r7yBM_tQs,270
34
34
  vng_api_common/utils.py,sha256=EHqVjZhtqnbU7YrqgYIBss28Sd19jtnTLNaMWLfj3Zw,8203
35
- vng_api_common/validators.py,sha256=ejaFZvFXFaBlqxjA2_07NSHKHlG5pejrfC_GHjwCj6E,12852
35
+ vng_api_common/validators.py,sha256=tZkjHPXfcG1FxGXCSNnyFkMQPzFHhlxfyOfNdEOb5js,12978
36
36
  vng_api_common/version.py,sha256=yJV9_yTM7Qnzg0zGNkJQkN9Uai3I_ZUkcyseJRPRk5I,129
37
- vng_api_common/views.py,sha256=pxpI2dl22I9auTYvRJ-Rx-_NHAKgo1F2QwQJF6WIjrE,7603
37
+ vng_api_common/views.py,sha256=ARqNuPlrZ0ctzkHTNs7NMyzrji2LvRmrmzrSNmtS-v0,7603
38
38
  vng_api_common/viewsets.py,sha256=jAXKHFRBhNKzkjugpYnXkE2zKvCWwKwZA6_VoiTWjvw,2286
39
39
  vng_api_common/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
40
  vng_api_common/api/permissions.py,sha256=okbwiscxlAtbQWTCRDLL2reOxgj0rRDZeDcrtXAYq00,739
@@ -45,7 +45,7 @@ vng_api_common/audittrails/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
45
45
  vng_api_common/audittrails/admin.py,sha256=mrRK9KhvFlRWcmsq-DM9cJdwtpBUciMa4DvtEIYfirQ,301
46
46
  vng_api_common/audittrails/apps.py,sha256=eM4RMMgqXq_Hm1Il-dUlO0rtXJVP0DgAFQBW25epzdw,111
47
47
  vng_api_common/audittrails/audits.py,sha256=44_vry_9XPZoyKUJeMhhf4xr0OsCndgzGGxRqa65_d0,337
48
- vng_api_common/audittrails/models.py,sha256=O1GhyJlZaDYPTwKcZE45J2Fl1q02BGtYciu-QdjzBsQ,3596
48
+ vng_api_common/audittrails/models.py,sha256=ja3SUY8cdcAMfjp2h4J7QiWikqa1gaCrtHPg_Z7-UIw,3581
49
49
  vng_api_common/audittrails/utils.py,sha256=fhDQ-iaSGE8mWkcE9LXySI_pYfn7Xpao-n1m699h_hk,1316
50
50
  vng_api_common/audittrails/viewsets.py,sha256=K0AMPHYU6w_Z1cAww_itzfHjeqzZhIAi1m3cUHcXp30,8105
51
51
  vng_api_common/audittrails/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -76,10 +76,10 @@ vng_api_common/audittrails/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCe
76
76
  vng_api_common/audittrails/migrations/_operations.py,sha256=UOMv0zAK8CIQ73cSu6wwQG_hkW46Isdy7JCnljn8GII,3280
77
77
  vng_api_common/authorizations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
78
78
  vng_api_common/authorizations/admin.py,sha256=Tk0yYKbb005E0XZaYYWbucMf_K5M8Hhz62wSBDi8rhM,813
79
- vng_api_common/authorizations/middleware.py,sha256=KJ3znCXPRMOVqSur62SmBjvC6RcKxtcWq1rzaHdYR98,8416
80
- vng_api_common/authorizations/models.py,sha256=slIYxSktxCxSg03Nfb2mhsQse17b93KWE-rdPdMv8Ik,5199
79
+ vng_api_common/authorizations/middleware.py,sha256=cR7reyRIZmCtH2qONopva8PZKCkwBl3DU-VWJqnL-Z0,8418
80
+ vng_api_common/authorizations/models.py,sha256=-PwbFceloUz6pbfFp2DB3YfioC2xq63YDm-EVc3U3HE,5160
81
81
  vng_api_common/authorizations/serializers.py,sha256=3HeKWEqhI3UWwI8SttC4rEID-Epbk7SWsC-bEjolbaw,5151
82
- vng_api_common/authorizations/utils.py,sha256=GmwTy5GhYk3e1VU4LpdfYdr8VD-R8p00hUY11QBbOhc,555
82
+ vng_api_common/authorizations/utils.py,sha256=GSeHVXia-GHGCN_E4u671r4pGssvcyp9osKFf8Fc8v4,590
83
83
  vng_api_common/authorizations/validators.py,sha256=u7fKm0QgGy8fiAeYmIEB9Gy-yIE9C-tC2ZpnNQBXPso,2816
84
84
  vng_api_common/authorizations/migrations/0001_initial.py,sha256=ooAZtQeDtWgDxXzAP-KnSyyFYLRPM-PMrK5RgOnTPjQ,4360
85
85
  vng_api_common/authorizations/migrations/0002_authorizationsconfig.py,sha256=m4taH6ClHI-YHYGGOKaq_qYXGx9lq1InXOGLQKg9MSw,1364
@@ -104,10 +104,10 @@ vng_api_common/caching/decorators.py,sha256=lU5dnBjD9aHjoYaV32FlYxY7VFZPdMZe26fV
104
104
  vng_api_common/caching/etags.py,sha256=3zY0DTdwt19QHsxFLK1wqQ3K98JfO6Uxr6tFuixichg,7337
105
105
  vng_api_common/caching/introspection.py,sha256=JKeEuTiyWp1oN1Fg27j5-2btROz9NcLxxfzSZuVVJ9w,575
106
106
  vng_api_common/caching/models.py,sha256=RroS9HFiKNXDV59Odh0x8BO8Az8E81v4gwuprF1A1qg,988
107
- vng_api_common/caching/registry.py,sha256=mY1r99x7m0DQ1BN9lZF2zMjFj_oDNq7urxDkOH7-8Yg,6205
107
+ vng_api_common/caching/registry.py,sha256=oXE4kMnVpdp7qvb_goVkCTY5qeY8kB3EDKVX65fPtYc,6207
108
108
  vng_api_common/caching/signals.py,sha256=78ej5cVan-JpNHKzZNAfs0m2ON_TXKphe8ZKtP-6FVY,4615
109
109
  vng_api_common/conf/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
110
- vng_api_common/conf/api.py,sha256=tNShwZevKpJ6n713pPGPuUpThcPq-057JAd3xSHW5sU,3158
110
+ vng_api_common/conf/api.py,sha256=F1Aj8jOdN-T0ZYqUtuu-jUjST5XcyYcRFqZc057M0Bc,3160
111
111
  vng_api_common/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
112
112
  vng_api_common/contrib/setup_configuration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
113
113
  vng_api_common/contrib/setup_configuration/models.py,sha256=1-G0hXeRe-x6GYtsAaQeMGXq0-cwU5LMb8KTQWj-pQk,1201
@@ -184,7 +184,7 @@ vng_api_common/tests/auth.py,sha256=IKDWTEFv4Bign4F70-ibsFcnJqRxEJaXvqaPQJWa1xY,
184
184
  vng_api_common/tests/caching.py,sha256=zfIw5cRRvO9cekHZZKfRqZc8cx5IfJUYNmcH6cuIMg4,624
185
185
  vng_api_common/tests/schema.py,sha256=WDvifDQQiKqIpQijpeQ7rYkFroJmuPuHe7zNhl1Bigk,2293
186
186
  vng_api_common/tests/urls.py,sha256=PFrYzQbBC0TFPMEn3uPhcBG0IQs9JsEPqckicJT1UA4,2159
187
- commonground_api_common-2.6.4.dist-info/METADATA,sha256=3ukeRcXs4xAZnPuryteaoyPCP7SHHYFMa6tIAxgP6HM,6969
188
- commonground_api_common-2.6.4.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
189
- commonground_api_common-2.6.4.dist-info/top_level.txt,sha256=vPismc83zPzWXTmlNCCwfDlFV9iygJYxNJW5iDjKTgw,15
190
- commonground_api_common-2.6.4.dist-info/RECORD,,
187
+ commonground_api_common-2.6.6.dist-info/METADATA,sha256=cWsFJ1YO-TZLhYWVXu6r7Dp-9Qbt9RXbb8lfB97JAvM,7195
188
+ commonground_api_common-2.6.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
189
+ commonground_api_common-2.6.6.dist-info/top_level.txt,sha256=vPismc83zPzWXTmlNCCwfDlFV9iygJYxNJW5iDjKTgw,15
190
+ commonground_api_common-2.6.6.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.7.1)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1 +1 @@
1
- __version__ = "2.6.4"
1
+ __version__ = "2.6.6"
vng_api_common/admin.py CHANGED
@@ -1,5 +1,4 @@
1
1
  from django.contrib import admin
2
- from django.utils.translation import gettext_lazy as _
3
2
 
4
3
  from .models import JWTSecret
5
4
 
@@ -20,8 +20,7 @@ class AuditTrail(models.Model):
20
20
  max_length=255,
21
21
  blank=True,
22
22
  help_text=_(
23
- 'Een globaal "request" ID om een verzoek door het '
24
- "netwerk heen te traceren."
23
+ 'Een globaal "request" ID om een verzoek door het netwerk heen te traceren.'
25
24
  ),
26
25
  )
27
26
  bron = models.CharField(
@@ -108,7 +108,7 @@ class JWTAuth:
108
108
  self.encoded,
109
109
  algorithms=["HS256"],
110
110
  options={"verify_signature": False},
111
- leeway=settings.JWT_LEEWAY,
111
+ leeway=settings.TIME_LEEWAY,
112
112
  )
113
113
  except jwt.DecodeError:
114
114
  logger.info("Invalid JWT encountered")
@@ -146,7 +146,7 @@ class JWTAuth:
146
146
  self.encoded,
147
147
  key,
148
148
  algorithms=["HS256"],
149
- leeway=settings.JWT_LEEWAY,
149
+ leeway=settings.TIME_LEEWAY,
150
150
  )
151
151
  except jwt.InvalidSignatureError:
152
152
  logger.exception("Invalid signature - possible payload tampering?")
@@ -11,7 +11,6 @@ from zgw_consumers.constants import APITypes, AuthTypes
11
11
  from vng_api_common.client import Client, get_client
12
12
 
13
13
  from ..constants import ComponentTypes, VertrouwelijkheidsAanduiding
14
- from ..decorators import field_default
15
14
  from ..fields import VertrouwelijkheidsAanduidingField
16
15
  from ..models import APIMixin
17
16
 
@@ -1,18 +1,27 @@
1
- def generate_jwt(client_id, secret, user_id, user_representation):
2
- from zgw_consumers.client import ZGWAuth
1
+ import time
3
2
 
4
- class FakeService:
5
- def __init__(self, **kwargs):
6
- for key, value in kwargs.items():
7
- setattr(self, key, value)
3
+ import jwt
8
4
 
9
- auth = ZGWAuth(
10
- service=FakeService( # type: ignore
11
- client_id=client_id,
12
- secret=secret,
13
- user_id=user_id,
14
- user_representation=user_representation,
15
- jwt_valid_for=5 * 60,
16
- )
17
- )
18
- return f"Bearer {auth._token}"
5
+
6
+ def generate_jwt(
7
+ client_id: str,
8
+ secret: str,
9
+ user_id: str,
10
+ user_representation: str,
11
+ jwt_valid_for: int | None = None,
12
+ ) -> str:
13
+ iat = int(time.time())
14
+ payload = {
15
+ # standard claims
16
+ "iss": client_id,
17
+ "iat": iat,
18
+ # custom claims
19
+ "client_id": client_id,
20
+ "user_id": user_id,
21
+ "user_representation": user_representation,
22
+ }
23
+ if jwt_valid_for:
24
+ payload["exp"] = iat + jwt_valid_for
25
+
26
+ token = jwt.encode(payload, secret, algorithm="HS256")
27
+ return f"Bearer {token}"
@@ -64,9 +64,9 @@ class Dependency:
64
64
  instance: models.Model,
65
65
  is_delete: bool = False,
66
66
  ) -> Iterable[models.Model]:
67
- assert isinstance(
68
- instance, self.source_model
69
- ), "Instance is not of expected model class"
67
+ assert isinstance(instance, self.source_model), (
68
+ "Instance is not of expected model class"
69
+ )
70
70
 
71
71
  reverse_relation_field = self.field.remote_field
72
72
 
vng_api_common/client.py CHANGED
@@ -40,7 +40,6 @@ class Client(APIClient):
40
40
  def request(
41
41
  self, method: str | bytes, url: str | bytes, *args, **kwargs
42
42
  ) -> Response:
43
-
44
43
  headers = kwargs.pop("headers", {})
45
44
  headers.setdefault("Accept", "application/json")
46
45
  headers.setdefault("Content-Type", "application/json")
@@ -8,7 +8,7 @@ __all__ = [
8
8
  "GEMMA_URL_INFORMATIEMODEL_VERSIE",
9
9
  "GEMMA_URL_INFORMATIEMODEL",
10
10
  "GEMMA_URL_TEMPLATE",
11
- "JWT_LEEWAY",
11
+ "TIME_LEEWAY",
12
12
  "JWT_SPECTACULAR_SETTINGS",
13
13
  "LINK_FETCHER",
14
14
  "NOTIFICATIONS_DISABLED",
@@ -95,6 +95,6 @@ vng_repo = "VNG-Realisatie/vng-api-common"
95
95
  vng_branch = "ref-responses"
96
96
  COMMON_SPEC = f"https://raw.githubusercontent.com/{vng_repo}/feature/{vng_branch}/vng_api_common/schemas/common.yaml"
97
97
 
98
- JWT_LEEWAY = 0 # default in PyJWT
98
+ TIME_LEEWAY = 0 # default in PyJWT
99
99
 
100
100
  COMMONGROUND_API_COMMON_GET_DOMAIN = "vng_api_common.utils.get_site_domain"
@@ -88,28 +88,40 @@ class RolTypes(models.TextChoices):
88
88
 
89
89
 
90
90
  class Archiefnominatie(models.TextChoices):
91
- blijvend_bewaren = "blijvend_bewaren", _(
92
- "Het zaakdossier moet bewaard blijven en op de Archiefactiedatum "
93
- "overgedragen worden naar een archiefbewaarplaats."
91
+ blijvend_bewaren = (
92
+ "blijvend_bewaren",
93
+ _(
94
+ "Het zaakdossier moet bewaard blijven en op de Archiefactiedatum "
95
+ "overgedragen worden naar een archiefbewaarplaats."
96
+ ),
94
97
  )
95
- vernietigen = "vernietigen", _(
96
- "Het zaakdossier moet op of na de Archiefactiedatum vernietigd worden."
98
+ vernietigen = (
99
+ "vernietigen",
100
+ _("Het zaakdossier moet op of na de Archiefactiedatum vernietigd worden."),
97
101
  )
98
102
 
99
103
 
100
104
  class Archiefstatus(models.TextChoices):
101
- nog_te_archiveren = "nog_te_archiveren", _(
102
- "De zaak cq. het zaakdossier is nog niet als geheel gearchiveerd."
105
+ nog_te_archiveren = (
106
+ "nog_te_archiveren",
107
+ _("De zaak cq. het zaakdossier is nog niet als geheel gearchiveerd."),
103
108
  )
104
- gearchiveerd = "gearchiveerd", _(
105
- "De zaak cq. het zaakdossier is als geheel niet-wijzigbaar bewaarbaar gemaakt."
109
+ gearchiveerd = (
110
+ "gearchiveerd",
111
+ _(
112
+ "De zaak cq. het zaakdossier is als geheel niet-wijzigbaar bewaarbaar gemaakt."
113
+ ),
106
114
  )
107
- gearchiveerd_procestermijn_onbekend = "gearchiveerd_procestermijn_onbekend", _(
108
- "De zaak cq. het zaakdossier is als geheel niet-wijzigbaar bewaarbaar gemaakt "
109
- "maar de vernietigingsdatum kan nog niet bepaald worden."
115
+ gearchiveerd_procestermijn_onbekend = (
116
+ "gearchiveerd_procestermijn_onbekend",
117
+ _(
118
+ "De zaak cq. het zaakdossier is als geheel niet-wijzigbaar bewaarbaar gemaakt "
119
+ "maar de vernietigingsdatum kan nog niet bepaald worden."
120
+ ),
110
121
  )
111
- overgedragen = "overgedragen", _(
112
- "De zaak cq. het zaakdossier is overgebracht naar een archiefbewaarplaats."
122
+ overgedragen = (
123
+ "overgedragen",
124
+ _("De zaak cq. het zaakdossier is overgebracht naar een archiefbewaarplaats."),
113
125
  )
114
126
 
115
127
 
@@ -190,17 +202,20 @@ class ZaakobjectTypes(models.TextChoices):
190
202
  buurt = "buurt", _("Buurt")
191
203
  enkelvoudig_document = "enkelvoudig_document", _("Enkelvoudig document")
192
204
  gemeente = "gemeente", _("Gemeente")
193
- gemeentelijke_openbare_ruimte = "gemeentelijke_openbare_ruimte", _(
194
- "Gemeentelijke openbare ruimte"
205
+ gemeentelijke_openbare_ruimte = (
206
+ "gemeentelijke_openbare_ruimte",
207
+ _("Gemeentelijke openbare ruimte"),
195
208
  )
196
209
  huishouden = "huishouden", _("Huishouden")
197
210
  inrichtingselement = "inrichtingselement", _("Inrichtingselement")
198
- kadastrale_onroerende_zaak = "kadastrale_onroerende_zaak", _(
199
- "Kadastrale onroerende zaak"
211
+ kadastrale_onroerende_zaak = (
212
+ "kadastrale_onroerende_zaak",
213
+ _("Kadastrale onroerende zaak"),
200
214
  )
201
215
  kunstwerkdeel = "kunstwerkdeel", _("Kunstwerkdeel")
202
- maatschappelijke_activiteit = "maatschappelijke_activiteit", _(
203
- "Maatschappelijke activiteit"
216
+ maatschappelijke_activiteit = (
217
+ "maatschappelijke_activiteit",
218
+ _("Maatschappelijke activiteit"),
204
219
  )
205
220
  medewerker = "medewerker", _("Medewerker")
206
221
  natuurlijk_persoon = "natuurlijk_persoon", _("Natuurlijk persoon")
@@ -30,9 +30,9 @@ class GegevensGroepType:
30
30
  self.none_for_empty = none_for_empty
31
31
 
32
32
  all_fields_known = set(self.optional).issubset(set(mapping.keys()))
33
- assert (
34
- all_fields_known
35
- ), "The fields in 'optional' must be a subset of the mapping keys"
33
+ assert all_fields_known, (
34
+ "The fields in 'optional' must be a subset of the mapping keys"
35
+ )
36
36
 
37
37
  # check if it's optional or not
38
38
  self.required = (
@@ -45,7 +45,7 @@ class GegevensGroepType:
45
45
  fields = ", ".join(
46
46
  [
47
47
  field if field not in self.optional else f"{field} (optional)"
48
- for field in self.mapping.keys()
48
+ for field in self.mapping
49
49
  ]
50
50
  )
51
51
  return "<GegevensGroepType: fields=%r required=%r>" % (fields, self.required)
vng_api_common/filters.py CHANGED
@@ -1,5 +1,5 @@
1
1
  import logging
2
- from urllib.parse import urlencode, urlparse
2
+ from urllib.parse import urlparse
3
3
 
4
4
  from django.core.exceptions import ValidationError
5
5
  from django.core.validators import URLValidator
@@ -73,7 +73,7 @@ class URLModelChoiceFilter(filters.ModelChoiceFilter):
73
73
 
74
74
  def __init__(self, *args, **kwargs):
75
75
  super().__init__(*args, **kwargs)
76
- self.instance_path = kwargs.get("instance_path", None)
76
+ self.instance_path = kwargs.get("instance_path")
77
77
  self.queryset = kwargs.get("queryset")
78
78
 
79
79
  @property
@@ -3,7 +3,6 @@ from urllib.parse import urlencode
3
3
 
4
4
  from django.db import models
5
5
  from django.http import QueryDict
6
- from django.utils.translation import gettext_lazy as _
7
6
 
8
7
  from django_filters.rest_framework import DjangoFilterBackend
9
8
  from djangorestframework_camel_case.parser import CamelCaseJSONParser
vng_api_common/mocks.py CHANGED
@@ -3,7 +3,7 @@ from urllib.parse import urlparse
3
3
 
4
4
  UUID_PATTERN = re.compile(
5
5
  r"[0-9a-f]{8}\-[0-9a-f]{4}\-4[0-9a-f]{3}\-[89ab][0-9a-f]{3}\-[0-9a-f]{12}",
6
- flags=re.I,
6
+ flags=re.IGNORECASE,
7
7
  )
8
8
 
9
9
 
vng_api_common/routers.py CHANGED
@@ -55,7 +55,7 @@ class DefaultRouter(NestedRegisteringMixin, routers.DefaultRouter):
55
55
  APIRootView = APIRootView
56
56
 
57
57
 
58
- class nested:
58
+ class Nested:
59
59
  def __init__(self, prefix, viewset, nested=None, **kwargs):
60
60
  self.prefix = prefix
61
61
  self.viewset = viewset
@@ -63,4 +63,4 @@ class nested:
63
63
  self.kwargs = kwargs
64
64
 
65
65
  def __repr__(self):
66
- return "nested(prefix={!r}, viewset={!r}".format(self.prefix, self.viewset)
66
+ return "Nested(prefix={!r}, viewset={!r}".format(self.prefix, self.viewset)
@@ -104,12 +104,12 @@ class GegevensGroepSerializerMetaclass(serializers.SerializerMetaclass):
104
104
  def __new__(cls, name, bases, attrs):
105
105
  Meta = attrs.get("Meta")
106
106
  if Meta:
107
- assert hasattr(
108
- Meta, "model"
109
- ), "The 'model' class must be defined on the Meta."
110
- assert hasattr(
111
- Meta, "gegevensgroep"
112
- ), "The 'gegevensgroep' name must be defined on the Meta."
107
+ assert hasattr(Meta, "model"), (
108
+ "The 'model' class must be defined on the Meta."
109
+ )
110
+ assert hasattr(Meta, "gegevensgroep"), (
111
+ "The 'gegevensgroep' name must be defined on the Meta."
112
+ )
113
113
 
114
114
  gegevensgroep = getattr(Meta.model, Meta.gegevensgroep)
115
115
  Meta.fields = []
@@ -391,6 +391,6 @@ class CachedNestedHyperlinkedRelatedField(CacheMixin, NestedHyperlinkedRelatedFi
391
391
  return None
392
392
 
393
393
  # Replace the placeholder from the cached base URI with the actual identifier
394
- for k, v in self.parent_lookup_kwargs.items():
394
+ for v in self.parent_lookup_kwargs.values():
395
395
  url = url.replace(v, str(get_nested_fk_attribute(obj, v)))
396
396
  return url
@@ -1,6 +1,7 @@
1
1
  import json
2
2
  import logging
3
3
  import re
4
+ from datetime import timedelta
4
5
  from typing import Callable
5
6
 
6
7
  from django.conf import settings
@@ -234,7 +235,7 @@ class ResourceValidator(URLValidator):
234
235
  # at this point, we know the URL actually exists
235
236
  try:
236
237
  obj = response.json()
237
- except json.JSONDecodeError as exc:
238
+ except json.JSONDecodeError:
238
239
  logger.info(
239
240
  "URL %s doesn't seem to point to a JSON endpoint", url, exc_info=1
240
241
  )
@@ -277,6 +278,8 @@ class UntilNowValidator:
277
278
  Validate a datetime to not be in the future.
278
279
 
279
280
  This means that `now` is included.
281
+
282
+ Some leeway can be added with the TIME_LEEWAY setting.
280
283
  """
281
284
 
282
285
  message = _("Ensure this value is not in the future.")
@@ -284,7 +287,7 @@ class UntilNowValidator:
284
287
 
285
288
  @property
286
289
  def limit_value(self):
287
- return timezone.now()
290
+ return timezone.now() + timedelta(seconds=settings.TIME_LEEWAY)
288
291
 
289
292
  def __call__(self, value):
290
293
  if value > self.limit_value:
vng_api_common/views.py CHANGED
@@ -117,7 +117,7 @@ def _test_sites_config(request: HttpRequest) -> list:
117
117
  return []
118
118
  return [
119
119
  (_("Site domain"), domain, request.get_host() == domain),
120
- (_("HTTPS"), settings.IS_HTTPS, settings.IS_HTTPS == request.is_secure()),
120
+ (_("HTTPS"), settings.IS_HTTPS, request.is_secure() == settings.IS_HTTPS),
121
121
  ]
122
122
 
123
123