diff --git a/requirements/base.in b/requirements/base.in index a4b03e2..b54b7bf 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -13,6 +13,7 @@ django-localflavor django-celery-beat flower django-timeline-logger +django-json-schema-model # waiting for > 2.0.1 commonground-api-common==1.13.4 diff --git a/requirements/base.txt b/requirements/base.txt index 3e6fa0b..f7abd8b 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -85,6 +85,7 @@ django==4.2.17 # django-csp # django-filter # django-formtools + # django-json-schema-model # django-jsonform # django-localflavor # django-log-outgoing-requests @@ -137,6 +138,8 @@ django-filter==24.3 # open-api-framework django-formtools==2.5.1 # via django-two-factor-auth +django-json-schema-model==0.1.0 + # via -r requirements/base.in django-jsonform==2.23.1 # via # mozilla-django-oidc-db @@ -249,7 +252,9 @@ jinja2==3.1.4 josepy==1.14.0 # via mozilla-django-oidc jsonschema==4.23.0 - # via drf-spectacular + # via + # django-json-schema-model + # drf-spectacular jsonschema-specifications==2024.10.1 # via jsonschema kombu==5.4.2 diff --git a/requirements/ci.txt b/requirements/ci.txt index e763c39..69adf75 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -155,6 +155,7 @@ django==4.2.17 # django-csp # django-filter # django-formtools + # django-json-schema-model # django-jsonform # django-localflavor # django-log-outgoing-requests @@ -228,6 +229,10 @@ django-formtools==2.5.1 # -c requirements/base.txt # -r requirements/base.txt # django-two-factor-auth +django-json-schema-model==0.1.0 + # via + # -c requirements/base.txt + # -r requirements/base.txt django-jsonform==2.23.1 # via # -c requirements/base.txt @@ -478,6 +483,7 @@ jsonschema==4.23.0 # via # -c requirements/base.txt # -r requirements/base.txt + # django-json-schema-model # drf-spectacular jsonschema-specifications==2024.10.1 # via diff --git a/requirements/dev.txt b/requirements/dev.txt index 7268cd0..bd40b7d 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -182,6 +182,7 @@ django==4.2.17 # django-extensions # django-filter # django-formtools + # django-json-schema-model # django-jsonform # django-localflavor # django-log-outgoing-requests @@ -259,6 +260,10 @@ django-formtools==2.5.1 # -c requirements/ci.txt # -r requirements/ci.txt # django-two-factor-auth +django-json-schema-model==0.1.0 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt django-jsonform==2.23.1 # via # -c requirements/ci.txt @@ -532,6 +537,7 @@ jsonschema==4.23.0 # via # -c requirements/ci.txt # -r requirements/ci.txt + # django-json-schema-model # drf-spectacular jsonschema-specifications==2024.10.1 # via diff --git a/src/open_producten/conf/base.py b/src/open_producten/conf/base.py index 0e2b82e..8b6481a 100644 --- a/src/open_producten/conf/base.py +++ b/src/open_producten/conf/base.py @@ -22,7 +22,7 @@ "localflavor", "markdownx", "django_celery_beat", - "django_json_schema", + "django_json_schema_model", "open_producten.accounts", "open_producten.logging", "open_producten.utils", diff --git a/src/open_producten/producten/migrations/0009_product_verbruiksobject.py b/src/open_producten/producten/migrations/0004_product_verbruiksobject.py similarity index 80% rename from src/open_producten/producten/migrations/0009_product_verbruiksobject.py rename to src/open_producten/producten/migrations/0004_product_verbruiksobject.py index 76e16a4..ad3b443 100644 --- a/src/open_producten/producten/migrations/0009_product_verbruiksobject.py +++ b/src/open_producten/producten/migrations/0004_product_verbruiksobject.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.4 on 2025-01-10 10:17 +# Generated by Django 4.2.17 on 2025-01-19 20:50 from django.db import migrations, models @@ -6,7 +6,7 @@ class Migration(migrations.Migration): dependencies = [ - ("producten", "0008_alter_product_eind_datum_alter_product_start_datum"), + ("producten", "0003_product_status_alter_product_aanmaak_datum_and_more"), ] operations = [ diff --git a/src/open_producten/producten/tests/api/test_product.py b/src/open_producten/producten/tests/api/test_product.py index 8290b83..0417133 100644 --- a/src/open_producten/producten/tests/api/test_product.py +++ b/src/open_producten/producten/tests/api/test_product.py @@ -3,7 +3,7 @@ from django.urls import reverse from django.utils.translation import gettext as _ -from django_json_schema.models import JsonSchema +from django_json_schema_model.models import JsonSchema from freezegun import freeze_time from rest_framework import status from rest_framework.exceptions import ErrorDetail @@ -151,7 +151,9 @@ def test_create_product_with_invalid_verbruiksobject(self): { "verbruiksobject": [ ErrorDetail( - string=_("Het verbruiksobject komt niet overeen met het schema gedefinieerd op het product type."), + string=_( + "Het verbruiksobject komt niet overeen met het schema gedefinieerd op het product type." + ), code="invalid", ) ] diff --git a/src/open_producten/producten/tests/test_product.py b/src/open_producten/producten/tests/test_product.py index 6ddda65..5a92a8e 100644 --- a/src/open_producten/producten/tests/test_product.py +++ b/src/open_producten/producten/tests/test_product.py @@ -5,7 +5,7 @@ from django.test import TestCase from django.utils.translation import gettext as _ -from django_json_schema.models import JsonSchema +from django_json_schema_model.models import JsonSchema from freezegun import freeze_time from open_producten.producttypen.tests.factories import ProductTypeFactory @@ -151,7 +151,9 @@ def test_verbruiksobject_is_invalid(self): with self.assertRaisesMessage( ValidationError, - _("Het verbruiksobject komt niet overeen met het schema gedefinieerd op het product type."), + _( + "Het verbruiksobject komt niet overeen met het schema gedefinieerd op het product type." + ), ): product.clean() @@ -183,6 +185,7 @@ def test_verbruiksobject_with_schema_without_object(self): product.clean() + @freeze_time("2024-1-1") class TestProductStateTask(TestCase): def setUp(self): diff --git a/src/open_producten/producttypen/migrations/0007_producttype_verbruiksobject_schema.py b/src/open_producten/producttypen/migrations/0006_producttype_verbruiksobject_schema.py similarity index 69% rename from src/open_producten/producttypen/migrations/0007_producttype_verbruiksobject_schema.py rename to src/open_producten/producttypen/migrations/0006_producttype_verbruiksobject_schema.py index 302bed5..a95d972 100644 --- a/src/open_producten/producttypen/migrations/0007_producttype_verbruiksobject_schema.py +++ b/src/open_producten/producttypen/migrations/0006_producttype_verbruiksobject_schema.py @@ -1,14 +1,17 @@ -# Generated by Django 5.1.4 on 2025-01-09 12:52 +# Generated by Django 4.2.17 on 2025-01-19 20:50 -import django.db.models.deletion from django.db import migrations, models +import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ("django_json_schema", "0001_initial"), - ("producttypen", "0006_alter_producttype_aanmaak_datum_and_more"), + ("django_json_schema_model", "0001_initial"), + ( + "producttypen", + "0005_producttype_code_producttype_toegestane_statussen_and_more", + ), ] operations = [ @@ -21,7 +24,7 @@ class Migration(migrations.Migration): null=True, on_delete=django.db.models.deletion.PROTECT, related_name="product_typen", - to="django_json_schema.jsonschema", + to="django_json_schema_model.jsonschema", verbose_name="verbruiksobject schema", ), ), diff --git a/src/open_producten/producttypen/models/producttype.py b/src/open_producten/producttypen/models/producttype.py index 3ea5ff8..11c8210 100644 --- a/src/open_producten/producttypen/models/producttype.py +++ b/src/open_producten/producttypen/models/producttype.py @@ -4,7 +4,7 @@ from django.db import models from django.utils.translation import gettext_lazy as _ -from django_json_schema.models import JsonSchema +from django_json_schema_model.models import JsonSchema from markdownx.models import MarkdownxField from open_producten.locaties.models import Contact, Locatie, Organisatie diff --git a/src/open_producten/producttypen/serializers/jsonschema.py b/src/open_producten/producttypen/serializers/jsonschema.py index 52683ff..ee003b2 100644 --- a/src/open_producten/producttypen/serializers/jsonschema.py +++ b/src/open_producten/producttypen/serializers/jsonschema.py @@ -1,4 +1,4 @@ -from django_json_schema.models import JsonSchema +from django_json_schema_model.models import JsonSchema from jsonschema import Draft202012Validator from jsonschema.exceptions import SchemaError from rest_framework import serializers diff --git a/src/open_producten/producttypen/serializers/producttype.py b/src/open_producten/producttypen/serializers/producttype.py index 2d1bf2e..6e3757c 100644 --- a/src/open_producten/producttypen/serializers/producttype.py +++ b/src/open_producten/producttypen/serializers/producttype.py @@ -1,7 +1,7 @@ from django.db import transaction from django.utils.translation import gettext_lazy as _ -from django_json_schema.models import JsonSchema +from django_json_schema_model.models import JsonSchema from rest_framework import serializers from open_producten.locaties.models import Contact, Locatie, Organisatie diff --git a/src/open_producten/producttypen/tests/api/test_jsonschema.py b/src/open_producten/producttypen/tests/api/test_jsonschema.py index d8668ca..36c79af 100644 --- a/src/open_producten/producttypen/tests/api/test_jsonschema.py +++ b/src/open_producten/producttypen/tests/api/test_jsonschema.py @@ -1,6 +1,7 @@ from django.urls import reverse +from django.utils.translation import gettext as _ -from django_json_schema.models import JsonSchema +from django_json_schema_model.models import JsonSchema from rest_framework import status from rest_framework.exceptions import ErrorDetail from rest_framework.test import APIClient @@ -36,8 +37,12 @@ def test_required_fields(self): self.assertEqual( response.data, { - "name": [ErrorDetail(string="Dit veld is vereist.", code="required")], - "schema": [ErrorDetail(string="Dit veld is vereist.", code="required")], + "name": [ + ErrorDetail(string=_("This field is required."), code="required") + ], + "schema": [ + ErrorDetail(string=_("This field is required."), code="required") + ], }, ) @@ -60,7 +65,7 @@ def test_create_invalid_schema(self): { "schema": [ ErrorDetail( - string="[] is not valid under any of the given schemas", + string=_("[] is not valid under any of the given schemas"), code="invalid", ) ] diff --git a/src/open_producten/producttypen/tests/api/test_producttype.py b/src/open_producten/producttypen/tests/api/test_producttype.py index 7d9ea25..d5aeabc 100644 --- a/src/open_producten/producttypen/tests/api/test_producttype.py +++ b/src/open_producten/producttypen/tests/api/test_producttype.py @@ -3,7 +3,7 @@ from django.urls import reverse from django.utils.translation import gettext as _ -from django_json_schema.models import JsonSchema +from django_json_schema_model.models import JsonSchema from freezegun import freeze_time from rest_framework import status from rest_framework.exceptions import ErrorDetail diff --git a/src/open_producten/producttypen/views.py b/src/open_producten/producttypen/views.py index 63a6dcc..a022d74 100644 --- a/src/open_producten/producttypen/views.py +++ b/src/open_producten/producttypen/views.py @@ -2,7 +2,7 @@ from django.utils.translation import gettext_lazy as _ from django_filters.rest_framework import DjangoFilterBackend -from django_json_schema.models import JsonSchema +from django_json_schema_model.models import JsonSchema from drf_spectacular.utils import OpenApiExample, extend_schema, extend_schema_view from rest_framework import status from rest_framework.decorators import action diff --git a/src/producten-openapi.yaml b/src/producten-openapi.yaml index 54e33df..a936ee5 100644 --- a/src/producten-openapi.yaml +++ b/src/producten-openapi.yaml @@ -110,6 +110,8 @@ paths: gepubliceerd: false bsn: '111222333' status: gereed + verbruiksobject: + uren: 130 summary: Create product required: true security: @@ -559,6 +561,10 @@ components: pattern: ^[0-9]*$ maxLength: 8 minLength: 8 + verbruiksobject: + nullable: true + description: Verbruiksobject van dit product. Wordt gevalideerd met het + `verbruiksobject_schema` uit het product type. Product: type: object properties: @@ -624,6 +630,10 @@ components: pattern: ^[0-9]*$ maxLength: 8 minLength: 8 + verbruiksobject: + nullable: true + description: Verbruiksobject van dit product. Wordt gevalideerd met het + `verbruiksobject_schema` uit het product type. required: - aanmaak_datum - id @@ -680,6 +690,10 @@ components: pattern: ^[0-9]*$ maxLength: 8 minLength: 8 + verbruiksobject: + nullable: true + description: Verbruiksobject van dit product. Wordt gevalideerd met het + `verbruiksobject_schema` uit het product type. required: - product_type_id StatusEnum: diff --git a/src/producttypen-openapi.yaml b/src/producttypen-openapi.yaml index 53579c7..af2ef73 100644 --- a/src/producttypen-openapi.yaml +++ b/src/producttypen-openapi.yaml @@ -986,7 +986,7 @@ paths: /locaties/{id}/: get: operationId: locaties_retrieve - summary: Een specifiek LOCATIE opvragen. + summary: Een specifieke LOCATIE opvragen. parameters: - in: path name: id @@ -1275,7 +1275,7 @@ paths: /organisaties/{id}/: get: operationId: organisaties_retrieve - summary: Een specifiek ORGANISATIE opvragen. + summary: Een specifieke ORGANISATIE opvragen. parameters: - in: path name: id @@ -1841,6 +1841,7 @@ paths: beschrijving: uitgebreide beschrijving... keywords: - wonen + verbruiksobject_schema: 1 summary: Create product type required: true security: @@ -2144,6 +2145,295 @@ paths: schema: $ref: '#/components/schemas/DetailError' description: '' + /schemas/: + get: + operationId: schemas_list + description: Deze lijst kan gefilterd wordt met query-string parameters. + summary: Alle SCHEMA'S opvragen. + parameters: + - in: query + name: name + schema: + type: string + - name: page + required: false + in: query + description: Een pagina binnen de gepagineerde set resultaten. + schema: + type: integer + - name: page_size + required: false + in: query + description: Het aantal resultaten terug te geven per pagina. + schema: + type: integer + tags: + - schemas + security: + - tokenAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PaginatedJsonSchemaList' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + examples: + BadRequestExample: + value: + veld_a: + - Dit veld is vereist. + veld_b: + - ‘’ is geen geldige UUID. + summary: Bad request example + description: Errors worden per veld teruggegeven. Hieronder volgt + een voorbeeld. + description: Validation error + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/DetailError' + description: '' + post: + operationId: schemas_create + summary: Maak een SCHEMA aan. + tags: + - schemas + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/JsonSchemaRequest' + examples: + CreateSchema: + value: + name: parkeervergunning-verbruiksobject + schema: + type: object + properties: + uren: + type: number + required: + - uren + summary: Create schema + required: true + security: + - tokenAuth: [] + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/JsonSchema' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + examples: + BadRequestExample: + value: + veld_a: + - Dit veld is vereist. + veld_b: + - ‘’ is geen geldige UUID. + summary: Bad request example + description: Errors worden per veld teruggegeven. Hieronder volgt + een voorbeeld. + description: Validation error + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/DetailError' + description: '' + /schemas/{id}/: + get: + operationId: schemas_retrieve + summary: Een specifiek SCHEMA opvragen. + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this Json schema. + required: true + tags: + - schemas + security: + - tokenAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/JsonSchema' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + examples: + BadRequestExample: + value: + veld_a: + - Dit veld is vereist. + veld_b: + - ‘’ is geen geldige UUID. + summary: Bad request example + description: Errors worden per veld teruggegeven. Hieronder volgt + een voorbeeld. + description: Validation error + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/DetailError' + description: '' + put: + operationId: schemas_update + summary: Werk een SCHEMA in zijn geheel bij. + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this Json schema. + required: true + tags: + - schemas + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/JsonSchemaRequest' + required: true + security: + - tokenAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/JsonSchema' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + examples: + BadRequestExample: + value: + veld_a: + - Dit veld is vereist. + veld_b: + - ‘’ is geen geldige UUID. + summary: Bad request example + description: Errors worden per veld teruggegeven. Hieronder volgt + een voorbeeld. + description: Validation error + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/DetailError' + description: '' + patch: + operationId: schemas_partial_update + summary: Werk een SCHEMA deels bij. + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this Json schema. + required: true + tags: + - schemas + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PatchedJsonSchemaRequest' + security: + - tokenAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/JsonSchema' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + examples: + BadRequestExample: + value: + veld_a: + - Dit veld is vereist. + veld_b: + - ‘’ is geen geldige UUID. + summary: Bad request example + description: Errors worden per veld teruggegeven. Hieronder volgt + een voorbeeld. + description: Validation error + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/DetailError' + description: '' + delete: + operationId: schemas_destroy + summary: Verwijder een SCHEMA. + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this Json schema. + required: true + tags: + - schemas + security: + - tokenAuth: [] + responses: + '204': + description: No response body + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + examples: + BadRequestExample: + value: + veld_a: + - Dit veld is vereist. + veld_b: + - ‘’ is geen geldige UUID. + summary: Bad request example + description: Errors worden per veld teruggegeven. Hieronder volgt + een voorbeeld. + description: Validation error + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/DetailError' + description: '' /themas/: get: operationId: themas_list @@ -2859,6 +3149,39 @@ components: required: - veld_a - veld_b + JsonSchema: + type: object + properties: + id: + type: integer + readOnly: true + schema: + type: object + additionalProperties: {} + name: + type: string + title: Naam + description: Name of the json schema. + maxLength: 200 + required: + - id + - name + - schema + JsonSchemaRequest: + type: object + properties: + schema: + type: object + additionalProperties: {} + name: + type: string + minLength: 1 + title: Naam + description: Name of the json schema. + maxLength: 200 + required: + - name + - schema Link: type: object properties: @@ -3403,6 +3726,29 @@ components: type: array items: $ref: '#/components/schemas/Contact' + PaginatedJsonSchemaList: + type: object + required: + - count + - results + properties: + count: + type: integer + example: 123 + next: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?page=4 + previous: + type: string + nullable: true + format: uri + example: http://api.example.org/accounts/?page=2 + results: + type: array + items: + $ref: '#/components/schemas/JsonSchema' PaginatedLinkList: type: object required: @@ -3604,6 +3950,18 @@ components: type: string description: De rol/functie van het contact maxLength: 100 + PatchedJsonSchemaRequest: + type: object + properties: + schema: + type: object + additionalProperties: {} + name: + type: string + minLength: 1 + title: Naam + description: Name of the json schema. + maxLength: 200 PatchedLinkRequest: type: object properties: @@ -3745,6 +4103,11 @@ components: format: uuid writeOnly: true default: [] + verbruiksobject_schema_id: + type: integer + writeOnly: true + description: JSON schema om het verbruiksobject van een gerelateerd product + te valideren. gepubliceerd: type: boolean description: Geeft aan of het object getoond kan worden. @@ -3956,6 +4319,10 @@ components: items: $ref: '#/components/schemas/NestedBestand' readOnly: true + verbruiksobject_schema: + allOf: + - $ref: '#/components/schemas/JsonSchema' + readOnly: true gepubliceerd: type: boolean description: Geeft aan of het object getoond kan worden. @@ -4011,6 +4378,7 @@ components: - themas - uniforme_product_naam - update_datum + - verbruiksobject_schema - vragen ProductTypeActuelePrijs: type: object @@ -4079,6 +4447,11 @@ components: format: uuid writeOnly: true default: [] + verbruiksobject_schema_id: + type: integer + writeOnly: true + description: JSON schema om het verbruiksobject van een gerelateerd product + te valideren. gepubliceerd: type: boolean description: Geeft aan of het object getoond kan worden.