Skip to content

Commit 167fc35

Browse files
pi-sigmaswrichards
authored andcommitted
[#2903] Support export of only select ZaakType configs
1 parent 58a2e85 commit 167fc35

File tree

3 files changed

+156
-54
lines changed

3 files changed

+156
-54
lines changed

src/open_inwoner/openzaak/admin.py

+16-7
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,11 @@
1313
from django.utils.html import format_html, format_html_join
1414
from django.utils.translation import gettext_lazy as _, ngettext
1515

16-
from import_export.admin import ImportExportMixin
1716
from privates.storages import PrivateMediaFileSystemStorage
1817
from solo.admin import SingletonModelAdmin
1918

2019
from open_inwoner.ckeditor5.widgets import CKEditorWidget
21-
from open_inwoner.openzaak.import_export import (
22-
CatalogusConfigExport,
23-
CatalogusConfigImport,
24-
)
20+
from open_inwoner.openzaak.import_export import CatalogusConfigImport, ZGWConfigExport
2521
from open_inwoner.utils.forms import LimitedUploadFileField
2622

2723
from .models import (
@@ -142,7 +138,7 @@ def get_urls(self):
142138

143139
@admin.action(description=_("Export to file"))
144140
def export_catalogus_configs(modeladmin, request, queryset):
145-
export = CatalogusConfigExport.from_catalogus_configs(queryset)
141+
export = ZGWConfigExport.from_catalogus_configs(queryset)
146142
response = StreamingHttpResponse(
147143
export.as_jsonl_iter(),
148144
content_type="application/json",
@@ -374,7 +370,7 @@ def has_delete_permission(self, request, obj=None):
374370

375371

376372
@admin.register(ZaakTypeConfig)
377-
class ZaakTypeConfigAdmin(ImportExportMixin, admin.ModelAdmin):
373+
class ZaakTypeConfigAdmin(admin.ModelAdmin):
378374
inlines = [
379375
ZaakTypeInformatieObjectTypeConfigInline,
380376
ZaakTypeStatusTypeConfigInline,
@@ -383,6 +379,7 @@ class ZaakTypeConfigAdmin(ImportExportMixin, admin.ModelAdmin):
383379
actions = [
384380
"mark_as_notify_status_changes",
385381
"mark_as_not_notify_status_changes",
382+
"export_zaaktype_configs",
386383
]
387384
fields = [
388385
"urls",
@@ -437,6 +434,18 @@ class ZaakTypeConfigAdmin(ImportExportMixin, admin.ModelAdmin):
437434
]
438435
ordering = ("identificatie", "catalogus__domein")
439436

437+
@admin.action(description=_("Export to file"))
438+
def export_zaaktype_configs(modeladmin, request, queryset):
439+
export = ZGWConfigExport.from_zaaktype_configs(queryset)
440+
response = StreamingHttpResponse(
441+
export.as_jsonl_iter(),
442+
content_type="application/json",
443+
)
444+
response[
445+
"Content-Disposition"
446+
] = 'attachment; filename="zgw-zaaktype-export.json"'
447+
return response
448+
440449
def has_add_permission(self, request):
441450
return False
442451

src/open_inwoner/openzaak/import_export.py

+57-30
Original file line numberDiff line numberDiff line change
@@ -152,19 +152,17 @@ def _update_nested_zgw_config(
152152

153153

154154
@dataclasses.dataclass(frozen=True)
155-
class CatalogusConfigExport:
156-
"""Gather and export CatalogusConfig(s) and all associated relations."""
157-
155+
class ZGWConfigExport:
158156
catalogus_configs: QuerySet
159-
zaak_type_configs: QuerySet
157+
zaaktype_configs: QuerySet
160158
zaak_informatie_object_type_configs: QuerySet
161159
zaak_status_type_configs: QuerySet
162160
zaak_resultaat_type_configs: QuerySet
163161

164162
def __iter__(self) -> Generator[QuerySet, Any, None]:
165163
yield from (
166164
self.catalogus_configs,
167-
self.zaak_type_configs,
165+
self.zaaktype_configs,
168166
self.zaak_informatie_object_type_configs,
169167
self.zaak_status_type_configs,
170168
self.zaak_resultaat_type_configs,
@@ -174,9 +172,32 @@ def __eq__(self, other: QuerySet) -> bool:
174172
for a, b in zip(self, other):
175173
if a.difference(b).exists():
176174
return False
177-
178175
return True
179176

177+
def as_dicts_iter(self) -> Generator[dict, Any, None]:
178+
for qs in self:
179+
serialized_data = serializers.serialize(
180+
queryset=qs,
181+
format="json",
182+
use_natural_foreign_keys=True,
183+
use_natural_primary_keys=True,
184+
)
185+
json_data: list[dict] = json.loads(
186+
serialized_data,
187+
)
188+
yield from json_data
189+
190+
def as_jsonl_iter(self) -> Generator[str, Any, None]:
191+
for row in self.as_dicts():
192+
yield json.dumps(row)
193+
yield "\n"
194+
195+
def as_dicts(self) -> list[dict]:
196+
return list(self.as_dicts_iter())
197+
198+
def as_jsonl(self) -> str:
199+
return "".join(self.as_jsonl_iter())
200+
180201
@classmethod
181202
def from_catalogus_configs(cls, catalogus_configs: QuerySet) -> Self:
182203
if not isinstance(catalogus_configs, QuerySet):
@@ -189,50 +210,56 @@ def from_catalogus_configs(cls, catalogus_configs: QuerySet) -> Self:
189210
f"`catalogus_configs` is of type {catalogus_configs.model}, not CatalogusConfig"
190211
)
191212

192-
zaak_type_configs = ZaakTypeConfig.objects.filter(
213+
zaaktype_configs = ZaakTypeConfig.objects.filter(
193214
catalogus__in=catalogus_configs
194215
)
195216
informatie_object_types = ZaakTypeInformatieObjectTypeConfig.objects.filter(
196-
zaaktype_config__in=zaak_type_configs
217+
zaaktype_config__in=zaaktype_configs
197218
)
198219
zaak_status_type_configs = ZaakTypeStatusTypeConfig.objects.filter(
199-
zaaktype_config__in=zaak_type_configs
220+
zaaktype_config__in=zaaktype_configs
200221
)
201222
zaak_resultaat_type_configs = ZaakTypeResultaatTypeConfig.objects.filter(
202-
zaaktype_config__in=zaak_type_configs
223+
zaaktype_config__in=zaaktype_configs
203224
)
204225

205226
return cls(
206227
catalogus_configs=catalogus_configs,
207-
zaak_type_configs=zaak_type_configs,
228+
zaaktype_configs=zaaktype_configs,
208229
zaak_informatie_object_type_configs=informatie_object_types,
209230
zaak_status_type_configs=zaak_status_type_configs,
210231
zaak_resultaat_type_configs=zaak_resultaat_type_configs,
211232
)
212233

213-
def as_dicts_iter(self) -> Generator[dict, Any, None]:
214-
for qs in self:
215-
serialized_data = serializers.serialize(
216-
queryset=qs,
217-
format="json",
218-
use_natural_foreign_keys=True,
219-
use_natural_primary_keys=True,
220-
)
221-
json_data: list[dict] = json.loads(
222-
serialized_data,
234+
@classmethod
235+
def from_zaaktype_configs(cls, zaaktype_configs: QuerySet) -> Self:
236+
if not isinstance(zaaktype_configs, QuerySet):
237+
raise TypeError(
238+
f"`zaaktype_configs` is not a QuerySet, but a {type(zaaktype_configs)}"
223239
)
224-
yield from json_data
225240

226-
def as_jsonl_iter(self) -> Generator[str, Any, None]:
227-
for row in self.as_dicts():
228-
yield json.dumps(row)
229-
yield "\n"
241+
if zaaktype_configs.model != ZaakTypeConfig:
242+
raise ValueError(
243+
f"`zaaktype_configs` is of type {zaaktype_configs.model}, not ZaakTypeConfig"
244+
)
230245

231-
def as_dicts(self) -> list[dict]:
232-
return list(self.as_dicts_iter())
246+
informatie_object_types = ZaakTypeInformatieObjectTypeConfig.objects.filter(
247+
zaaktype_config__in=zaaktype_configs
248+
)
249+
zaak_status_type_configs = ZaakTypeStatusTypeConfig.objects.filter(
250+
zaaktype_config__in=zaaktype_configs
251+
)
252+
zaak_resultaat_type_configs = ZaakTypeResultaatTypeConfig.objects.filter(
253+
zaaktype_config__in=zaaktype_configs
254+
)
233255

234-
def as_jsonl(self) -> str:
235-
return "".join(self.as_jsonl_iter())
256+
return cls(
257+
catalogus_configs=CatalogusConfig.objects.none(),
258+
zaaktype_configs=zaaktype_configs,
259+
zaak_informatie_object_type_configs=informatie_object_types,
260+
zaak_status_type_configs=zaak_status_type_configs,
261+
zaak_resultaat_type_configs=zaak_resultaat_type_configs,
262+
)
236263

237264

238265
@dataclasses.dataclass(frozen=True)

src/open_inwoner/openzaak/tests/test_import_export.py

+83-17
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@
55
from django.core.files.storage.memory import InMemoryStorage
66
from django.test import TestCase
77

8-
from open_inwoner.openzaak.import_export import (
9-
CatalogusConfigExport,
10-
CatalogusConfigImport,
11-
)
8+
from open_inwoner.openzaak.import_export import CatalogusConfigImport, ZGWConfigExport
129
from open_inwoner.openzaak.models import (
1310
CatalogusConfig,
1411
ZaakTypeConfig,
@@ -94,17 +91,17 @@ def test_export_only_accepts_queryset(self):
9491
for arg in (list(), set(), tuple(), None, "", CatalogusConfig.objects.first()):
9592
with self.subTest(f"Default factory should not accept {arg}"):
9693
with self.assertRaises(TypeError):
97-
CatalogusConfigExport.from_catalogus_configs(arg)
94+
ZGWConfigExport.from_catalogus_configs(arg)
9895

9996
def test_export_only_accepts_queryset_of_correct_type(self):
10097
with self.assertRaises(ValueError):
101-
CatalogusConfigExport.from_catalogus_configs(ZaakTypeConfig.objects.all())
98+
ZGWConfigExport.from_catalogus_configs(ZaakTypeConfig.objects.all())
10299

103100
def test_equality_operator(self):
104-
export_a = CatalogusConfigExport.from_catalogus_configs(
101+
export_a = ZGWConfigExport.from_catalogus_configs(
105102
CatalogusConfig.objects.filter(pk=self.mocks[0].catalogus.pk)
106103
)
107-
export_b = CatalogusConfigExport.from_catalogus_configs(
104+
export_b = ZGWConfigExport.from_catalogus_configs(
108105
CatalogusConfig.objects.filter(pk=self.mocks[1].catalogus.pk)
109106
)
110107

@@ -113,14 +110,14 @@ def test_equality_operator(self):
113110
self.assertFalse(export_a == export_b)
114111

115112
def test_only_models_related_to_exported_catalogus_config_are_included(self):
116-
export = CatalogusConfigExport.from_catalogus_configs(
113+
export = ZGWConfigExport.from_catalogus_configs(
117114
CatalogusConfig.objects.filter(pk=self.mocks[0].catalogus.pk)
118115
)
119116

120117
for export_field, mock_field in zip(
121118
(
122119
"catalogus_configs",
123-
"zaak_type_configs",
120+
"zaaktype_configs",
124121
"zaak_status_type_configs",
125122
"zaak_resultaat_type_configs",
126123
"zaak_informatie_object_type_configs",
@@ -148,6 +145,79 @@ def test_only_models_related_to_exported_catalogus_config_are_included(self):
148145
)
149146

150147

148+
class ZaakTypeConfigExportTest(TestCase):
149+
def setUp(self):
150+
self.mocks = ZGWExportImportMockData(0)
151+
152+
def test_export_zaaktype_configs(self):
153+
export = ZGWConfigExport.from_zaaktype_configs(
154+
ZaakTypeConfig.objects.filter(pk=self.mocks.ztc.pk)
155+
)
156+
rows = export.as_dicts()
157+
158+
expected = [
159+
{
160+
"model": "openzaak.zaaktypeconfig",
161+
"fields": {
162+
"urls": '["https://foo.0.maykinmedia.nl"]',
163+
"catalogus": ["DM-0", "123456789"],
164+
"identificatie": "ztc-id-a-0",
165+
"omschrijving": "zaaktypeconfig",
166+
"notify_status_changes": False,
167+
"description": "",
168+
"external_document_upload_url": "",
169+
"document_upload_enabled": False,
170+
"contact_form_enabled": False,
171+
"contact_subject_code": "",
172+
"relevante_zaakperiode": None,
173+
},
174+
},
175+
{
176+
"model": "openzaak.zaaktypeinformatieobjecttypeconfig",
177+
"fields": {
178+
"zaaktype_config": ["ztc-id-a-0", "DM-0", "123456789"],
179+
"informatieobjecttype_url": "https://foo.0.maykinmedia.nl",
180+
"omschrijving": "informatieobject",
181+
"zaaktype_uuids": '["a1591906-3368-470a-a957-4b8634c275a1"]',
182+
"document_upload_enabled": False,
183+
"document_notification_enabled": False,
184+
},
185+
},
186+
{
187+
"model": "openzaak.zaaktypestatustypeconfig",
188+
"fields": {
189+
"zaaktype_config": ["ztc-id-a-0", "DM-0", "123456789"],
190+
"statustype_url": "https://foo.0.maykinmedia.nl",
191+
"omschrijving": "status omschrijving",
192+
"statustekst": "",
193+
"zaaktype_uuids": '["a1591906-3368-470a-a957-4b8634c275a1"]',
194+
"status_indicator": "",
195+
"status_indicator_text": "",
196+
"document_upload_description": "",
197+
"description": "status",
198+
"notify_status_change": True,
199+
"action_required": False,
200+
"document_upload_enabled": True,
201+
"call_to_action_url": "",
202+
"call_to_action_text": "",
203+
"case_link_text": "",
204+
},
205+
},
206+
{
207+
"model": "openzaak.zaaktyperesultaattypeconfig",
208+
"fields": {
209+
"zaaktype_config": ["ztc-id-a-0", "DM-0", "123456789"],
210+
"resultaattype_url": "https://foo.0.maykinmedia.nl",
211+
"omschrijving": "resultaat",
212+
"zaaktype_uuids": '["a1591906-3368-470a-a957-4b8634c275a1"]',
213+
"description": "",
214+
},
215+
},
216+
]
217+
218+
self.assertEqual(rows, expected)
219+
220+
151221
class TestCatalogusExport(TestCase):
152222
def setUp(self):
153223
self.mocks = [
@@ -156,7 +226,7 @@ def setUp(self):
156226
]
157227

158228
def test_export_catalogus_configs(self):
159-
export = CatalogusConfigExport.from_catalogus_configs(
229+
export = ZGWConfigExport.from_catalogus_configs(
160230
CatalogusConfig.objects.filter(pk=self.mocks[0].catalogus.pk)
161231
)
162232
rows = export.as_dicts()
@@ -233,9 +303,7 @@ def test_export_catalogus_configs(self):
233303
self.assertEqual(rows, expected)
234304

235305
def test_export_catalogus_configs_as_jsonl(self):
236-
export = CatalogusConfigExport.from_catalogus_configs(
237-
CatalogusConfig.objects.all()
238-
)
306+
export = ZGWConfigExport.from_catalogus_configs(CatalogusConfig.objects.all())
239307
rows = list(export.as_jsonl_iter())
240308

241309
expected = [
@@ -585,9 +653,7 @@ def setUp(self):
585653
ZGWExportImportMockData()
586654

587655
def test_exports_can_be_imported(self):
588-
export = CatalogusConfigExport.from_catalogus_configs(
589-
CatalogusConfig.objects.all()
590-
)
656+
export = ZGWConfigExport.from_catalogus_configs(CatalogusConfig.objects.all())
591657
import_result = CatalogusConfigImport.from_jsonl_stream_or_string(
592658
export.as_jsonl()
593659
)

0 commit comments

Comments
 (0)