diff --git a/appinfo/routes.php b/appinfo/routes.php
index 3a3e2056..a14b912e 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -14,6 +14,7 @@
['name' => 'dashboard#page', 'url' => '/', 'verb' => 'GET'],
['name' => 'metadata#page', 'url' => '/metadata', 'verb' => 'GET'],
['name' => 'publications#page', 'url' => '/publications', 'verb' => 'GET'],
+ ['name' => 'publications#attachments', 'url' => '/api/publications/{id}/attachments', 'verb' => 'GET', 'requirements' => ['id' => '.+']],
['name' => 'catalogi#page', 'url' => '/catalogi', 'verb' => 'GET'],
['name' => 'search#index', 'url' => '/search', 'verb' => 'GET'],
['name' => 'search#index', 'url' => '/api/search', 'verb' => 'GET'],
diff --git a/docs/.gitbook/assets/Metadata_modal.png b/docs/.gitbook/assets/Metadata_modal.png
new file mode 100644
index 00000000..15e00a34
Binary files /dev/null and b/docs/.gitbook/assets/Metadata_modal.png differ
diff --git a/docs/.gitbook/assets/Screenshot 2024-08-08 113242.png b/docs/.gitbook/assets/Screenshot 2024-08-08 113242.png
new file mode 100644
index 00000000..73388011
Binary files /dev/null and b/docs/.gitbook/assets/Screenshot 2024-08-08 113242.png differ
diff --git a/docs/.gitbook/assets/Screenshot 2024-08-08 142036.png b/docs/.gitbook/assets/Screenshot 2024-08-08 142036.png
new file mode 100644
index 00000000..03ba470a
Binary files /dev/null and b/docs/.gitbook/assets/Screenshot 2024-08-08 142036.png differ
diff --git a/docs/.gitbook/assets/bijlage_toevoegen.png b/docs/.gitbook/assets/bijlage_toevoegen.png
new file mode 100644
index 00000000..dd356668
Binary files /dev/null and b/docs/.gitbook/assets/bijlage_toevoegen.png differ
diff --git a/docs/.gitbook/assets/bijlage_toevoegen_actieknop.png b/docs/.gitbook/assets/bijlage_toevoegen_actieknop.png
new file mode 100644
index 00000000..c697705c
Binary files /dev/null and b/docs/.gitbook/assets/bijlage_toevoegen_actieknop.png differ
diff --git a/docs/.gitbook/assets/bijlage_toevoegen_drie_bolletjes.png b/docs/.gitbook/assets/bijlage_toevoegen_drie_bolletjes.png
new file mode 100644
index 00000000..a33e4c50
Binary files /dev/null and b/docs/.gitbook/assets/bijlage_toevoegen_drie_bolletjes.png differ
diff --git a/docs/.gitbook/assets/bijlage_toevoegen_modal.png b/docs/.gitbook/assets/bijlage_toevoegen_modal.png
new file mode 100644
index 00000000..d734b54f
Binary files /dev/null and b/docs/.gitbook/assets/bijlage_toevoegen_modal.png differ
diff --git a/docs/.gitbook/assets/image (1).png b/docs/.gitbook/assets/image (1).png
new file mode 100644
index 00000000..cce857e5
Binary files /dev/null and b/docs/.gitbook/assets/image (1).png differ
diff --git a/docs/.gitbook/assets/image (2).png b/docs/.gitbook/assets/image (2).png
new file mode 100644
index 00000000..e811a485
Binary files /dev/null and b/docs/.gitbook/assets/image (2).png differ
diff --git a/docs/.gitbook/assets/image.png b/docs/.gitbook/assets/image.png
new file mode 100644
index 00000000..0b00a48c
Binary files /dev/null and b/docs/.gitbook/assets/image.png differ
diff --git a/docs/.gitbook/assets/metadata-settings.png b/docs/.gitbook/assets/metadata-settings.png
new file mode 100644
index 00000000..6aff7d44
Binary files /dev/null and b/docs/.gitbook/assets/metadata-settings.png differ
diff --git a/docs/.gitbook/assets/publicatie_modal.png b/docs/.gitbook/assets/publicatie_modal.png
new file mode 100644
index 00000000..b675d97a
Binary files /dev/null and b/docs/.gitbook/assets/publicatie_modal.png differ
diff --git a/docs/.gitbook/assets/publicatie_mogelijkheden.png b/docs/.gitbook/assets/publicatie_mogelijkheden.png
new file mode 100644
index 00000000..0b412c2d
Binary files /dev/null and b/docs/.gitbook/assets/publicatie_mogelijkheden.png differ
diff --git a/docs/.gitbook/assets/publicatie_toevoegen_modal.png b/docs/.gitbook/assets/publicatie_toevoegen_modal.png
new file mode 100644
index 00000000..d45b2acc
Binary files /dev/null and b/docs/.gitbook/assets/publicatie_toevoegen_modal.png differ
diff --git a/docs/README.md b/docs/README.md
index 0efb6c7f..14317ca5 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -3,23 +3,24 @@
description: >-
Welkom bij de gebruikersdocumentatie voor de OpenCatalogi Nextcloud App. Veel
succes met het gebruik van de app.
-coverY: 0
----------
+----------------------------------
# Welkom
+***
+
Deze documentatie richt zich op het gebruik van onze beheerapplicatie, speciaal ontworpen voor het beheren van publicaties en catalogi binnen het federatief netwerk. De OpenCatalogi Nextcloud App is een eenvoudig te installeren:
-* [**Quickstart**](installatie/instructies.md)voor een test/demo-omgeving
+* [**Quickstart**](installatie/instructies.md) voor een test/demo-omgeving
* [**Quickstart** ](developers/installatie-van-nextcloud-development-omgeving.md)voor een development-omgeving
Onze app ondersteunt de Common Ground-aanpak, waardoor je snel toegang hebt tot bestaande IT-oplossingen die je kunt hergebruiken om de ontwikkeltijd te verkorten en de kosten te verlagen. In deze gids vind je stapsgewijze instructies, nuttige tips en best practices om je te helpen bij het optimaal beheren van je federatief netwerk, zoals publicaties of softwarecomponenten.
Deze documentatie is bedoeld voor diverse doelgroepen:
-* **Gebruikers:** iedereen die wilt delen binnen het netwerk.
+* **Gebruikers:** iedereen die wil delen binnen het netwerk.
* **Developers:** Ontwikkelaars die bijdragen aan de OpenCatalogi-projecten en behoefte hebben aan gedetailleerde technische informatie en API-documentatie.
-* **Beheerders:** Professionals die verantwoordelijk zijn voor het beheren en onderhouden van het federatief netwerk voor publicaites en componenten.
+* **Beheerders:** Professionals die verantwoordelijk zijn voor het beheren en onderhouden van het federatief netwerk voor publicaties en componenten.
Voor meer informatie over OpenCatalogi en onze gemeenschappelijke inspanningen, bezoek onze [documentatie-pagina](https://documentatie.opencatalogi.nl) of de officiële website op [OpenCatalogi.nl](https://opencatalogi.nl).
diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md
index 33c123b8..13d66e28 100644
--- a/docs/SUMMARY.md
+++ b/docs/SUMMARY.md
@@ -24,4 +24,4 @@
* [SAAS en Dashboarding](installatie/saas.md)
* [On-Prem server](installatie/on-prem-server.md)
* [Systeemeisen voor Nextcloud](installatie/systeemeisen-voor-nextcloud.md)
-* [Veel gestelde vragen](f-a-g.md)
+* [Veel gestelde vragen](veel-gestelde-vragen.md)
diff --git a/docs/assets/Opencatalogi CRUD.postman_collection.json b/docs/assets/Opencatalogi CRUD.postman_collection.json
new file mode 100644
index 00000000..b843d3f5
--- /dev/null
+++ b/docs/assets/Opencatalogi CRUD.postman_collection.json
@@ -0,0 +1,553 @@
+{
+ "info": {
+ "_postman_id": "f1d14358-ccc2-4650-9851-e46e2fb666e5",
+ "name": "Opencatalogi CRUD",
+ "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
+ "_exporter_id": "9365542",
+ "_collection_link": "https://conduction.postman.co/workspace/Gateway~7f74e723-2263-4ee5-855f-a2ea9cce0681/collection/9365542-f1d14358-ccc2-4650-9851-e46e2fb666e5?action=share&source=collection_link&creator=9365542"
+ },
+ "item": [
+ {
+ "name": "Search",
+ "item": [
+ {
+ "name": "General Search",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{environment}}/api/search",
+ "host": [
+ "{{environment}}"
+ ],
+ "path": [
+ "api",
+ "search"
+ ],
+ "query": [
+ {
+ "key": "_search",
+ "value": "bijzondere bijstand",
+ "description": "General search query",
+ "disabled": true
+ },
+ {
+ "key": "_queries[]",
+ "value": "data.status",
+ "description": "Define fields that should be returned with the facets (example field to be replaced)",
+ "disabled": true
+ },
+ {
+ "key": "title",
+ "value": "Kubus bijzondere bijstand",
+ "description": "Filter on specific fields.",
+ "disabled": true
+ }
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Get specific object",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{environment}}/api/search/fa393c4e-3fc2-4787-ab43-fd58ce190fb4",
+ "host": [
+ "{{environment}}"
+ ],
+ "path": [
+ "api",
+ "search",
+ "fa393c4e-3fc2-4787-ab43-fd58ce190fb4"
+ ]
+ }
+ },
+ "response": []
+ }
+ ]
+ },
+ {
+ "name": "Directory",
+ "item": [
+ {
+ "name": "List directory",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{environment}}/api/directory",
+ "host": [
+ "{{environment}}"
+ ],
+ "path": [
+ "api",
+ "directory"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Create Directory",
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\r\n \"title\": \"Test\",\r\n \"summary\": \"Test directory for federation\",\r\n \"description\": \"Test directory for federation\",\r\n \"search\": \"https://api.common-gateway.commonground.nu/api/search\",\r\n \"directory\": \"https://eo9d4l3y6q4y2vt.m.pipedream.net\",\r\n \"metadata\": [\r\n \"http://example.com\"\r\n ],\r\n \"status\": \"200\",\r\n \"lastSync\": \"2019-08-24T14:15:22Z\",\r\n \"default\": false,\r\n \"available\": true,\r\n \"_schema\": \"directory\"\r\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{environment}}/api/directory",
+ "host": [
+ "{{environment}}"
+ ],
+ "path": [
+ "api",
+ "directory"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Get Directory",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{environment}}/api/directory/96e12db1-897b-41e1-a08d-acb4e2be040b",
+ "host": [
+ "{{environment}}"
+ ],
+ "path": [
+ "api",
+ "directory",
+ "96e12db1-897b-41e1-a08d-acb4e2be040b"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Delete Directory",
+ "request": {
+ "method": "DELETE",
+ "header": [],
+ "url": {
+ "raw": "{{environment}}/api/directory/96e12db1-897b-41e1-a08d-acb4e2be040b",
+ "host": [
+ "{{environment}}"
+ ],
+ "path": [
+ "api",
+ "directory",
+ "96e12db1-897b-41e1-a08d-acb4e2be040b"
+ ]
+ }
+ },
+ "response": []
+ }
+ ]
+ },
+ {
+ "name": "Publication",
+ "item": [
+ {
+ "name": "List publications",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{environment}}/api/publications",
+ "host": [
+ "{{environment}}"
+ ],
+ "path": [
+ "api",
+ "publications"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Create Publication",
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\r\n \"title\": \"Woningoppervlaktes\",\r\n \"reference\": \"test1234\",\r\n \"description\": \"Woningoppervlaktes geeft het gebruiksoppervlakte aan woningen per gebied, geclassificeerd ten behoeve van het bepalen van de benodigde parkeercapaciteit.\",\r\n \"summary\": \"Woningoppervlaktes geeft het gebruiksoppervlakte aan woningen per gebied, geclassificeerd ten behoeve van het bepalen van de benodigde parkeercapaciteit.\",\r\n \"catalogi\": \"7a048bfd-210f-4e93-a1e8-5aa9261740b7\",\r\n \"metaData\": \"468f440f-7af0-453a-8d5f-ffe644ab0673\",\r\n \"organization\": null,\r\n \"data\": {\r\n \"id\": \"33f88aa9-6ac0-4f6c-967e-ecf787fd6a3d\",\r\n \"reference\": \"https:\\/\\/catalogus-rotterdam.dataplatform.nl\\/dataset\\/voorlopige-energielabels-met-bag-kenmerken\",\r\n \"title\": \"Input voor OpenCatalogi\",\r\n \"summary\": \"Dit is een selectie van high-value datasets in DCAT-AP 2.0 standaard x\",\r\n \"category\": \"Dataset\",\r\n \"portal\": \"https:\\/\\/catalogus-rotterdam.dataplatform.nl\\/dataset\\/voorlopige-energielabels-met-bag-kenmerken\",\r\n \"published\": \"2020-04-07\",\r\n \"modified\": \"2020-12-29\",\r\n \"featured\": false,\r\n \"schema\": \"https:\\/\\/openwoo.app\\/schemas\\/metadata.dcat_catalog.schema.json\",\r\n \"status\": \"published\",\r\n \"license\": \"CC0 1.0\",\r\n \"attachments\": [\r\n {\r\n \"id\": \"ba9e5f64-f6ee-4c62-99bd-e9176372f4c2\",\r\n \"title\": \"woningoppervlaktes feature layer\",\r\n \"description\": \"ESRI feature layer met woningoppervlaktes per TIR-buurt en per TIR-blok.\",\r\n \"license\": \"notspecified\",\r\n \"type\": \"API\",\r\n \"published\": \"24-12-2020\",\r\n \"modified\": \"30 december 2020, 11:55 (UTC+01:00)\",\r\n \"accessURL\": \"https:\\/\\/services.arcgis.com\\/zP1tGdLpGvt2qNJ6\\/arcgis\\/rest\\/services\\/Woningoppervlaktes\\/FeatureServer\",\r\n \"downloadURL\": \"https:\\/\\/services.arcgis.com\\/zP1tGdLpGvt2qNJ6\\/arcgis\\/rest\\/services\\/Woningoppervlaktes\\/FeatureServer\"\r\n }\r\n ],\r\n \"attachmentCount\": 1,\r\n \"themes\": [\r\n \"SODA\",\r\n \"kennisloods\",\r\n \"mobiliteit\",\r\n \"oppervlakte\",\r\n \"oppervlaktes\",\r\n \"parkeercapaciteit\",\r\n \"parkeren\",\r\n \"soda verblijfsobject\",\r\n \"verblijfsobjecten\",\r\n \"woning\",\r\n \"woningen\",\r\n \"woningoppervlakte\",\r\n \"woningoppervlaktes\"\r\n ],\r\n \"data\": {\r\n \"spatial\": \"[55500,428647,101033,447000]\",\r\n \"contactPoint\": {\r\n \"name\": \"gemeente Rotterdam, Stadsontwikkeling, SODA\",\r\n \"email\": \"dataSO@rotterdam.nl\"\r\n },\r\n \"qualifiedAttribution\": {\r\n \"responsible\": {\r\n \"name\": \"gemeente Rotterdam, Stadsontwikkeling, SODA\",\r\n \"email\": \"dataSO@rotterdam.nl\"\r\n },\r\n \"role\": {\r\n \"name\": \"beheerder\"\r\n }\r\n },\r\n \"accrualPeriodicity\": \"onregelmatig\"\r\n },\r\n \"anonymization\": {\r\n \"anonymized\": true\r\n },\r\n \"language\": {\r\n \"code\": \"nl-nl\",\r\n \"level\": \"A1\"\r\n }\r\n },\r\n \"attachments\": [\r\n {\r\n \"id\": \"ba9e5f64-f6ee-4c62-99bd-e9176372f4c2\",\r\n \"title\": \"woningoppervlaktes feature layer\",\r\n \"description\": \"ESRI feature layer met woningoppervlaktes per TIR-buurt en per TIR-blok.\",\r\n \"license\": \"notspecified\",\r\n \"type\": \"API\",\r\n \"published\": \"24-12-2020\",\r\n \"modified\": \"30 december 2020, 11:55 (UTC+01:00)\",\r\n \"accessURL\": \"https:\\/\\/services.arcgis.com\\/zP1tGdLpGvt2qNJ6\\/arcgis\\/rest\\/services\\/Woningoppervlaktes\\/FeatureServer\",\r\n \"downloadURL\": \"https:\\/\\/services.arcgis.com\\/zP1tGdLpGvt2qNJ6\\/arcgis\\/rest\\/services\\/Woningoppervlaktes\\/FeatureServer\"\r\n }\r\n ],\r\n \"attachmentCount\": 1,\r\n \"license\": \"notspecified\",\r\n \"modified\": \"2020-12-29\",\r\n \"publicationDate\": \"2020-04-07\",\r\n \"status\": \"published\",\r\n \"featured\": false,\r\n \"portal\": \"https:\\/\\/catalogus-rotterdam.dataplatform.nl\\/dataset\\/voorlopige-energielabels-met-bag-kenmerken\",\r\n \"category\": \"Dataset\",\r\n \"image\": \"https:\\/\\/dev.opencatalogi.nl\\/static\\/logo_OpenCatalogi-8b1b0a001c3f37dae4d3f69b5964ec72.png\",\r\n \"schema\": \"publications\",\r\n \"themes\": null,\r\n \"anonymization\": null,\r\n \"languageObject\": null\r\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{environment}}/api/publications",
+ "host": [
+ "{{environment}}"
+ ],
+ "path": [
+ "api",
+ "publications"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Get Publication",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{environment}}/api/publications/1",
+ "host": [
+ "{{environment}}"
+ ],
+ "path": [
+ "api",
+ "publications",
+ "1"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Update Publication",
+ "request": {
+ "method": "PUT",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\r\n \"title\": \"Test woningoppervlakte\"\r\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{environment}}/api/publications/1",
+ "host": [
+ "{{environment}}"
+ ],
+ "path": [
+ "api",
+ "publications",
+ "1"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Delete Directory",
+ "request": {
+ "method": "DELETE",
+ "header": [],
+ "url": {
+ "raw": "{{environment}}/api/publications/3",
+ "host": [
+ "{{environment}}"
+ ],
+ "path": [
+ "api",
+ "publications",
+ "3"
+ ]
+ }
+ },
+ "response": []
+ }
+ ]
+ },
+ {
+ "name": "Attachment",
+ "item": [
+ {
+ "name": "List publications",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{environment}}/api/publications",
+ "host": [
+ "{{environment}}"
+ ],
+ "path": [
+ "api",
+ "publications"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Create Publication",
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\r\n \"title\": \"Woningoppervlaktes\",\r\n \"reference\": \"test1234\",\r\n \"description\": \"Woningoppervlaktes geeft het gebruiksoppervlakte aan woningen per gebied, geclassificeerd ten behoeve van het bepalen van de benodigde parkeercapaciteit.\",\r\n \"summary\": \"Woningoppervlaktes geeft het gebruiksoppervlakte aan woningen per gebied, geclassificeerd ten behoeve van het bepalen van de benodigde parkeercapaciteit.\",\r\n \"catalogi\": \"7a048bfd-210f-4e93-a1e8-5aa9261740b7\",\r\n \"metaData\": \"468f440f-7af0-453a-8d5f-ffe644ab0673\",\r\n \"organization\": null,\r\n \"data\": {\r\n \"id\": \"33f88aa9-6ac0-4f6c-967e-ecf787fd6a3d\",\r\n \"reference\": \"https:\\/\\/catalogus-rotterdam.dataplatform.nl\\/dataset\\/voorlopige-energielabels-met-bag-kenmerken\",\r\n \"title\": \"Input voor OpenCatalogi\",\r\n \"summary\": \"Dit is een selectie van high-value datasets in DCAT-AP 2.0 standaard x\",\r\n \"category\": \"Dataset\",\r\n \"portal\": \"https:\\/\\/catalogus-rotterdam.dataplatform.nl\\/dataset\\/voorlopige-energielabels-met-bag-kenmerken\",\r\n \"published\": \"2020-04-07\",\r\n \"modified\": \"2020-12-29\",\r\n \"featured\": false,\r\n \"schema\": \"https:\\/\\/openwoo.app\\/schemas\\/metadata.dcat_catalog.schema.json\",\r\n \"status\": \"published\",\r\n \"license\": \"CC0 1.0\",\r\n \"attachments\": [\r\n {\r\n \"id\": \"ba9e5f64-f6ee-4c62-99bd-e9176372f4c2\",\r\n \"title\": \"woningoppervlaktes feature layer\",\r\n \"description\": \"ESRI feature layer met woningoppervlaktes per TIR-buurt en per TIR-blok.\",\r\n \"license\": \"notspecified\",\r\n \"type\": \"API\",\r\n \"published\": \"24-12-2020\",\r\n \"modified\": \"30 december 2020, 11:55 (UTC+01:00)\",\r\n \"accessURL\": \"https:\\/\\/services.arcgis.com\\/zP1tGdLpGvt2qNJ6\\/arcgis\\/rest\\/services\\/Woningoppervlaktes\\/FeatureServer\",\r\n \"downloadURL\": \"https:\\/\\/services.arcgis.com\\/zP1tGdLpGvt2qNJ6\\/arcgis\\/rest\\/services\\/Woningoppervlaktes\\/FeatureServer\"\r\n }\r\n ],\r\n \"attachmentCount\": 1,\r\n \"themes\": [\r\n \"SODA\",\r\n \"kennisloods\",\r\n \"mobiliteit\",\r\n \"oppervlakte\",\r\n \"oppervlaktes\",\r\n \"parkeercapaciteit\",\r\n \"parkeren\",\r\n \"soda verblijfsobject\",\r\n \"verblijfsobjecten\",\r\n \"woning\",\r\n \"woningen\",\r\n \"woningoppervlakte\",\r\n \"woningoppervlaktes\"\r\n ],\r\n \"data\": {\r\n \"spatial\": \"[55500,428647,101033,447000]\",\r\n \"contactPoint\": {\r\n \"name\": \"gemeente Rotterdam, Stadsontwikkeling, SODA\",\r\n \"email\": \"dataSO@rotterdam.nl\"\r\n },\r\n \"qualifiedAttribution\": {\r\n \"responsible\": {\r\n \"name\": \"gemeente Rotterdam, Stadsontwikkeling, SODA\",\r\n \"email\": \"dataSO@rotterdam.nl\"\r\n },\r\n \"role\": {\r\n \"name\": \"beheerder\"\r\n }\r\n },\r\n \"accrualPeriodicity\": \"onregelmatig\"\r\n },\r\n \"anonymization\": {\r\n \"anonymized\": true\r\n },\r\n \"language\": {\r\n \"code\": \"nl-nl\",\r\n \"level\": \"A1\"\r\n }\r\n },\r\n \"attachments\": [\r\n {\r\n \"id\": \"ba9e5f64-f6ee-4c62-99bd-e9176372f4c2\",\r\n \"title\": \"woningoppervlaktes feature layer\",\r\n \"description\": \"ESRI feature layer met woningoppervlaktes per TIR-buurt en per TIR-blok.\",\r\n \"license\": \"notspecified\",\r\n \"type\": \"API\",\r\n \"published\": \"24-12-2020\",\r\n \"modified\": \"30 december 2020, 11:55 (UTC+01:00)\",\r\n \"accessURL\": \"https:\\/\\/services.arcgis.com\\/zP1tGdLpGvt2qNJ6\\/arcgis\\/rest\\/services\\/Woningoppervlaktes\\/FeatureServer\",\r\n \"downloadURL\": \"https:\\/\\/services.arcgis.com\\/zP1tGdLpGvt2qNJ6\\/arcgis\\/rest\\/services\\/Woningoppervlaktes\\/FeatureServer\"\r\n }\r\n ],\r\n \"attachmentCount\": 1,\r\n \"license\": \"notspecified\",\r\n \"modified\": \"2020-12-29\",\r\n \"publicationDate\": \"2020-04-07\",\r\n \"status\": \"published\",\r\n \"featured\": false,\r\n \"portal\": \"https:\\/\\/catalogus-rotterdam.dataplatform.nl\\/dataset\\/voorlopige-energielabels-met-bag-kenmerken\",\r\n \"category\": \"Dataset\",\r\n \"image\": \"https:\\/\\/dev.opencatalogi.nl\\/static\\/logo_OpenCatalogi-8b1b0a001c3f37dae4d3f69b5964ec72.png\",\r\n \"schema\": \"publications\",\r\n \"themes\": null,\r\n \"anonymization\": null,\r\n \"languageObject\": null\r\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{environment}}/api/publications",
+ "host": [
+ "{{environment}}"
+ ],
+ "path": [
+ "api",
+ "publications"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Get Publication",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{environment}}/api/publications/1",
+ "host": [
+ "{{environment}}"
+ ],
+ "path": [
+ "api",
+ "publications",
+ "1"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Update Publication",
+ "request": {
+ "method": "PUT",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\r\n \"title\": \"Test woningoppervlakte\"\r\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{environment}}/api/publications/1",
+ "host": [
+ "{{environment}}"
+ ],
+ "path": [
+ "api",
+ "publications",
+ "1"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Delete Directory",
+ "request": {
+ "method": "DELETE",
+ "header": [],
+ "url": {
+ "raw": "{{environment}}/api/publications/3",
+ "host": [
+ "{{environment}}"
+ ],
+ "path": [
+ "api",
+ "publications",
+ "3"
+ ]
+ }
+ },
+ "response": []
+ }
+ ]
+ },
+ {
+ "name": "Catalogi",
+ "item": [
+ {
+ "name": "List Catalogi",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{environment}}/api/catalogi",
+ "host": [
+ "{{environment}}"
+ ],
+ "path": [
+ "api",
+ "catalogi"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Create Catalogi",
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\r\n \"title\": \"DCAT\",\r\n \"reference\": \"test1234\",\r\n \"description\": \"Test voor DCAT objecten.\",\r\n \"summary\": \"Test voor DCAT objecten.\"\r\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{environment}}/api/catalogi",
+ "host": [
+ "{{environment}}"
+ ],
+ "path": [
+ "api",
+ "catalogi"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Get Publication",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{environment}}/api/publications/1",
+ "host": [
+ "{{environment}}"
+ ],
+ "path": [
+ "api",
+ "publications",
+ "1"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Update Publication",
+ "request": {
+ "method": "PUT",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\r\n \"title\": \"Test woningoppervlakte\"\r\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{environment}}/api/publications/1",
+ "host": [
+ "{{environment}}"
+ ],
+ "path": [
+ "api",
+ "publications",
+ "1"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Delete Catalog",
+ "request": {
+ "method": "DELETE",
+ "header": [],
+ "url": {
+ "raw": "{{environment}}/api/directory/96e12db1-897b-41e1-a08d-acb4e2be040b",
+ "host": [
+ "{{environment}}"
+ ],
+ "path": [
+ "api",
+ "directory",
+ "96e12db1-897b-41e1-a08d-acb4e2be040b"
+ ]
+ }
+ },
+ "response": []
+ }
+ ]
+ }
+ ],
+ "auth": {
+ "type": "basic",
+ "basic": [
+ {
+ "key": "password",
+ "value": "admin",
+ "type": "string"
+ },
+ {
+ "key": "username",
+ "value": "admin",
+ "type": "string"
+ }
+ ]
+ },
+ "event": [
+ {
+ "listen": "prerequest",
+ "script": {
+ "type": "text/javascript",
+ "packages": {},
+ "exec": [
+ ""
+ ]
+ }
+ },
+ {
+ "listen": "test",
+ "script": {
+ "type": "text/javascript",
+ "packages": {},
+ "exec": [
+ ""
+ ]
+ }
+ }
+ ],
+ "variable": [
+ {
+ "key": "environment",
+ "value": "http://nextcloud.local/index.php/apps/opencatalogi",
+ "type": "string"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/docs/beheerders/README.md b/docs/beheerders/README.md
index 2f76a5ce..6afccf02 100644
--- a/docs/beheerders/README.md
+++ b/docs/beheerders/README.md
@@ -1 +1,13 @@
-# beheerders
+***
+
+description: >-
+De rol van een "Beheerder" binnen het platform is gericht op het beheren van
+de publicaties, catalogi en metadata, evenals de autorisatie van gebruikers.
+De verantwoordelijkheden van de beheerder:
+------------------------------------------
+
+# Beheerders
+
+* **Beheer van Publicaties:** Beheerders hebben toegang tot een overzicht van alle (concept-)publicaties, het bewerken van publicatie, verwijderen en (de)publiceren.
+* **Metadata en Thema's Beheren:** Beheerders kunnen het metadatamodel configureren, extra informatiecategorieën en thema's toevoegen en beheren. Ze kunnen deze koppelen aan publicaties voor beter beheer en toegang.
+* **Logging en Monitoring:**
diff --git a/docs/beheerders/catalogi.md b/docs/beheerders/catalogi.md
index 0d82a73b..44751e22 100644
--- a/docs/beheerders/catalogi.md
+++ b/docs/beheerders/catalogi.md
@@ -12,7 +12,7 @@ De organisatie-eigen catalogi (waartoe een gebruiker toegang heeft) zijn opgenom
## Catalogi beheren
-Catalogi kunnen worden beheerd via het menu-item Instellingen -> Catalogi.
+Catalogi kunnen worden beheerd via het menu-item Instellingen -> Catalogi en dan de drie bolletjes te selecten voor de opties.
* **Configuratie**: Onder de configuratie van een catalogus kan worden aangegeven
* Of deze actief is (anders wordt de catalogus niet getoond in het navigatiemenu en de zoekresultaten)
diff --git a/docs/developers/README.md b/docs/developers/README.md
index 4296a157..6130c59a 100644
--- a/docs/developers/README.md
+++ b/docs/developers/README.md
@@ -1 +1,11 @@
-# developers
+***
+
+description: >-
+De rol van een "Developer" binnen het publicatieplatform is voornamelijk
+gericht om bij te dragen aan de ontwikkeling aan de codebase of om
+aanpassingen te kunnen testen of demonstreren.
+----------------------------------------------
+
+# Developers
+
+In dit hoofdstuk worden de verschillende manieren gegeven om een test- of demo-omgevingen op te starten.
diff --git a/docs/developers/aan-de-slag-met-development.md b/docs/developers/aan-de-slag-met-development.md
index 78d61f16..841aa293 100644
--- a/docs/developers/aan-de-slag-met-development.md
+++ b/docs/developers/aan-de-slag-met-development.md
@@ -89,7 +89,11 @@ Als onderdeel van de CI/CD-straat voeren we een aantal tests uit, hiermee handha
### Voor de kwaliteit van de code maken we gebruik van linters
-Voor frontend is dat:
+Voorzowel de frontend als de backend geldt dat het aantal acceptabele errors 0 is.
+
+#### Frontend
+
+Voor frontend gebruiken we ESLint, de installatiehandleiding is [hier](https://www.npmjs.com/package/eslint) te vinden. Het commando om ESLint uit te voeren. ESLint is voornamelijk een linter, met enige format-functionaliteit.
```cli
npm run lint
@@ -97,19 +101,22 @@ npm run lint
![alt text](npm_lint.png)
-Voor de backend is dat:
+#### Backend
+
+Voor de backend gebruiken we PHP Code Sniffer. [Zie hier](https://dev.to/xxzeroxx/phpcs-php-code-sniffer-59f4) de handleiding voor de installatiemogelijkheden. PHP-code sniffer bestaat uit een linter ( `phpcs)` en een formatter(`phpcbf`). De formatter werkt hetzelfde als de linter en kan soms aardig wat errors wegwerken. De regels voor zowel de linter als de formatter zijn te vinden in `phpcs.xml` in de root van de applicatie.
```cli
phpcs [filename]
+phpcbf [filename]
```
-Hiervoor moet php code sniffer geïnstalleerd zijn. [Zie hier](https://dev.to/xxzeroxx/phpcs-php-code-sniffer-59f4) de handleiding ervoor
+## Voor stabiliteit gebruiken we unit tests
-Voor beide geldt dat het aantal acceptabele errors 0 is.
+Voor beide geldt dat minimale test coverage 80% is, en het aantal acceptabele errors 0.
-## Voor stabilliteit gebruiken we unit tests
+#### Frontend
-Voor frontend is dat:
+Voor het uitvoeren van de unit tests gebruiken we aan de frontend Jest. Indien je deze nog moet installeren of meer erover wilt weten, kijk dat [hier](https://www.npmjs.com/package/jest). Het uit te voeren commando is:
```cli
npm run test-coverage
@@ -117,14 +124,14 @@ npm run test-coverage
![alt text](npm_test.png)
-Voor de backend is dat:
+#### Backend:
+
+Voor het uitvoeren van de unit tests gebruiken we aan de backend PHPunit. Indien je deze nog moet installeren of meer erover wilt weten, kijk dan [hier](https://docs.phpunit.de/en/11.3/). Het uit te voeren commando is:
```cli
phpunit
```
-Voor beide geldt dat minimale test coverage 80% is, en het aantal acceptabele errors 0.
-
> **NOTE 1** We volgen de Nextcloud wijze voor unit testing, zie hier voor [de details](https://docs.nextcloud.com/server/latest/developer_manual/server/unit-testing.html), maar dit komt neer op [phpunit](https://docs.phpunit.de/en/11.3/index.html) en de juist configuratie van `phpunit.xml`en de `bootstrap.php`. Een voorbeeld van deze files zijn te vinden in de `root` van de applicatie (`phpunit.xml`) en de `/tests/unit`(`bootstrap.php`). Er zijn veel mogelijkheden om het jezelf makkelijk te maken, zoals een percentageoverzicht in de terminal. Het commando dat wij gebruiken is :
`XDEBUG_MODE=coverage phpunit --bootstrap ./tests/bootstrap.php --configuration phpunit.xml --coverage-html ./coverage --coverage-text | tee coverage.txt`
@@ -133,7 +140,7 @@ Voor beide geldt dat minimale test coverage 80% is, en het aantal acceptabele er
## Voor veiligheid gebruiken we dependency scanning
-Voor frontend is dat:
+#### Frontend:
```cli
npm audit
@@ -141,7 +148,7 @@ npm audit
![alt text](npm_audit.png)
-Voor de backend is dat:
+#### Backend
```cli
composer audit
@@ -150,3 +157,44 @@ composer audit
![alt text](composer_audit.png)
Voor beide geldt dat het aantal acceptabele critical vulnerabilities in *production packadges* 0 is.
+
+### Gebruikersdocumentatie
+
+We gebruiken Gitbook voor de gebruikersdocumentatie. Features binnen de app zouden zo veel mogelijk direct moeten doorverwijzen naar deze documentatie.
+
+Ook voor de documentatie wordt een linter gebruikt namelijk [remarklint](https://github.com/remarkjs/remark-lint).
+
+De commando's om deze linter in de CLI te gebruiken zijn [hier te vinden](https://github.com/remarkjs/remark-lint?tab=readme-ov-file#what-is-this) voor een uitgebreide output in de terminal.
+
+## API Development
+
+De ontwikkeling van de API wordt bijgehouden met de documentatietool [Stoplight.io](https://stoplight.io/), die automatisch een [OpenAPI Specificatie (OAS)](https://www.noraonline.nl/wiki/FS:Openapi-specification) genereert uit de documentatie. De Stoplight voor OpenCatalogi is [hier](https://conduction.stoplight.io/docs/open-catalogi/6yuj08rgf7w44-open-catalogi-api) te vinden.
+
+## Frontend Development
+
+### Storage en Typing
+
+Om gegevens deelbaar te maken tussen de verschillende Vue-componenten maken we gebruik van [statemanagement](https://vuejs.org/guide/scaling-up/state-management) waarbij we het Action, State, View patroon van Vue zelf volgen. Omdat de applicatie ingewikkeld begint te worden stappen we daarbij over van [simple state management](https://vuejs.org/guide/scaling-up/state-management#simple-state-management-with-reactivity-api) naar [Pinia](https://pinia.vuejs.org/), de door Vue zelf geadviseerde opvolger van [Vuex](https://vuejs.org/guide/scaling-up/state-management#pinia).
+
+Daarnaast gebruiken we Typescript voor het definiëren van entities.
+
+### Modals
+
+* Er mag altijd slechts één modal actief zijn.
+* Modals moeten abstract en overal bereikbaar zijn.
+* Modals moeten geplaatst worden in de map src/modals.
+* Modals moeten getriggerd worden via de state (zodat knoppen die modal openen overal plaatsbaar zijn).
+* Modals moeten geïmporteerd worden via `/src/modals/Modals.vue`.
+
+### Views
+
+* Views moeten dezelfde bestandsnaam hebben als de geëxporteerde naam en een correlatie hebben met de map waarin het bestand zich bevindt.
+* Bijvoorbeeld, als het bestand een detailpagina is en het zich in de map `publications` bevindt, moet het bestand de naam `PublicationDetail.vue` hebben.
+
+## Documentatie
+
+Het is goed om bij development kennnis te nemen/hebben van de volgende gebruikte Nextcloud onderdelen:
+
+* [Icons](https://pictogrammers.com/library/mdi/)
+* [Layout](https://docs.nextcloud.com/server/latest/developer_manual/design/layout.html)-
+* [Componenten](https://nextcloud-vue-components.netlify.app/)
diff --git a/docs/gebruikers/README.md b/docs/gebruikers/README.md
index def29e73..8544890f 100644
--- a/docs/gebruikers/README.md
+++ b/docs/gebruikers/README.md
@@ -1 +1,13 @@
+***
+
+description: >-
+Een "Gebruiker" binnen het Publicatieplatform heeft de primaire taak om
+publicaties te creëren en te bewerken. De rol van de gebruiker omvat de
+volgende verantwoordelijkheden en mogelijkheden:
+------------------------------------------------
+
# Gebruikers
+
+* **Creëren van Publicaties:** Gebruikers kunnen nieuwe publicaties aanmaken, afhankelijk van hun autorisaties. Ze kunnen kiezen namens welke organisatie of onderdeel ze publiceren en de juiste informatiecategorieën selecteren. Documenten kunnen worden geüpload en metadata ingevuld.
+* **Bewerken van Publicaties:** Gebruikers hebben toegang tot een overzicht van hun eigen (concept-)publicaties. Ze kunnen deze filteren, sorteren en wijzigen. Gebruikers kunnen concept-publicaties definitief maken en gepubliceerde documenten intrekken naar concept-status.
+* **Downloaden van Publicaties:** Gebruikers kunnen gepubliceerde documenten en bijbehorende metadata downloaden.
diff --git a/docs/gebruikers/dashboard.md b/docs/gebruikers/dashboard.md
index 7bbe2df1..f7594bf7 100644
--- a/docs/gebruikers/dashboard.md
+++ b/docs/gebruikers/dashboard.md
@@ -2,14 +2,18 @@
description: >-
Deze handleiding gaat ervan uit dat de gebruiker beschikt tot een werkende
-OpenCatalogi-Nextcloud app.
----------------------------
+OpenCatalogi-Nextcloud app
+--------------------------
# Dashboard
+***
+
+## Dashboard
+
Op het dashboard van OpenCatalogi vindt u handige informatie die je meteen verder helpt en in staat stelt de juiste keuzes te maken. Aan de linkerkant tref je een aantal overzichtsstatistieken en aan de rechterkant een sidebar met daarin de mogelijkheid om direct actie te ondernemen.
-## Statistieken
+### Statistieken
1. **Zoekverkeer** Het aantal zoekvragen dat er afgelopen maand aan jouw index (geheel van catalogi) is gesteld.
2. **Metadata** De verdeling over metadata-types van jouw publicaties
@@ -18,7 +22,7 @@ Op het dashboard van OpenCatalogi vindt u handige informatie die je meteen verde
![app menu](../assets/oc_dashboard.png)
-## Sidebar
+### Sidebar
Vanuit de sidebar heb je toegang tot 3 tabbladen
diff --git a/docs/gebruikers/publicaties.md b/docs/gebruikers/publicaties.md
index 341ed986..1c621746 100644
--- a/docs/gebruikers/publicaties.md
+++ b/docs/gebruikers/publicaties.md
@@ -1,6 +1,6 @@
# Publicaties
-> Publicaties zijn onderdeel van de (Open Catalogi Standaard)\[] en gebaseerd op het [publication object](https://conduction.stoplight.io/docs/open-catalogi/9bebd6bf4fe35-publication). Publicaties kennen eigenschappen zo als gedefineerd in een publicaite type en kunnen worden gekopeld aan bijlagen
+Publicaties zijn onderdeel van de [Open Catalogi Standaard](https://github.com/OpenCatalogi/.github/blob/main/docs/Standaard.md) en gebaseerd op het [publication object](https://conduction.stoplight.io/docs/open-catalogi/9bebd6bf4fe35-publication). Publicaties kennen eigenschappen zoals gedefinieerd in een publicatietype en kunnen worden gekoppeld aan bijlagen
Een publicatie representeerd iets wat je wilt publiceren, het beschrijft de handeling van publiceren en de spelregels waaronder iets gepubliceerd wordt.het is een soort "verpakking" of "omhulsel" dat zowel de kerngegevens (data) als aanvullende informatie over die gegevens (metadata) bevat.
@@ -14,29 +14,27 @@ Publicaties zijn altijd onderdeel van een collectie in de vorm van een [catalogu
Publicaties kunnen worden toegevoegd via:
-* De publicatie toeveogen knop boven aan het hoofd menu (links)
-* Een catalogus geselecteerd in het hoofd menu (via het hamburger menu achter de zoekbalk)
-* Een catalogus detail pagina
+* De publicatie toevoegen knop boven aan het hoofd menu (links)
+* Een catalogus geselecteerd in het hoofdmenu (via het hamburgermenu achter de zoekbalk)
+* Een catalogus detailpagina
-Een publicatie leeft altijd binnen één catalogus en word gedefineerd door één publicatie type. Omdat catalogi bepalen welke publicatie typen beschickbaar zijn voor die catalogi moet er eerst een catalogus worden gekozen voordat er een metadata type kan worden gekozen. Daarmee word de volgorde bij het aanmaken van een publicatie:
+Een publicatie leeft altijd binnen één catalogus en wordt gedefinieerd door één publicatietype. Omdat catalogi bepalen welke publicatietypen beschikbaar zijn voor die catalogi moet er eerst een catalogus worden gekozen voordat er een metadatatype kan worden gekozen. Daarmee wordt de volgorde bij het aanmaken van een publicatie:
1. Catalogus kiezen (indien niet opgestart vanuit een specifieke catalogus)
2. Publicatietype kiezen
-3. Publicatie detalis aanvullen
+3. Publicatiedetails aanvullen
-Eigenschapen en bijlagen kunnen worden toegevoegd nadat de publicatie is toegevoegd.
+Eigenschappen en bijlagen kunnen worden toegevoegd nadat de publicatie is toegevoegd.
## Publicaties beheren
-De gebruikersbeheerinterface werkt intuïtief. Aan de linkerkant van de pagina bevindt zich een overzicht van catalogi. Met de blauwe knop bovenaan kun je een publicatie aanmaken. Dit opent een modal genaamd "Publicatie toevoegen".
+De gebruikersbeheerinterface werkt intuïtief. Aan de linkerkant van de pagina bevindt zich een overzicht van catalogi. Met de blauwe knop bovenaan kun je een publicatie aanmaken. Dit opent een modal genaamd "Publicatie toevoegen". Er wordt eerst gevraagd aan welke catalogus deze behoort en welke publicatietype het heeft (metadata)
Hieronder is een voorbeeld van een ingevulde modal voor het aanmaken van een Woo-publicatie.
-
+
-
-
-
+
@@ -64,4 +62,20 @@ Naast een bestand kan een bijlage (per verwijzing) bijvoorbeeld ook een website
Een tweede manier om informatie op te nemen in een publicaite is via eigenschappen. Eigenschappen zijn voor gedefineerde opties (via [publicatie type](../beheerders/metadata.md)) waar een waarde aan kan worden toegekend.
+## Bijlagen
+
![alt text](image-2.png)
+
+Publicaties hebben vaak bijlagen, zoals een verslag of een besluit. Deze zijn eenvoudig toe te voegen door op de Actie-knop te klikken bij een geselecteerde publicatie, of de drie bolletjes naast een publicatie. Dit opent de Bijlage toevoegen modal.
+
+
+
+
+
+
+
+
+
+In de `Bijlage toevoegen`-modal worden er gevraagd om een aantal velden. Er zijn twee mogelijkheden een bijlage toe te voegen. De eerste manier is via een `Toegangs URL`. Dit zorgt ervoor dat het bestand vanuit een andere plek automatisch gedownload wordt. Een `Titel` is dan verplicht.
+
+De tweede manier is door zelf een bestand up te loaden. De bestandsnaam wordt dan meegegeven.
diff --git a/docs/gebruikers/tutorial.md b/docs/gebruikers/tutorial.md
index 8a90e4f8..35708faf 100644
--- a/docs/gebruikers/tutorial.md
+++ b/docs/gebruikers/tutorial.md
@@ -1,14 +1,14 @@
# Tutorial
1. Zorg dat je Nextcloud hebt geïnstalleerd [link naar installatiehandleiding](https://cloud.nextcloud.com/s/iyNGp8ryWxc7Efa?path=%2F1%20Setting%20up%20a%20development%20environment).
-2. De OpenCatalogi code is de `apps-extra`-folder hebt. [link naar de app toevoegen](../developers/installatie-van-nextcloud-development-omgeving.md)
+2. De OpenCatalogi code is de `apps-extra`-folder hebt. [link naar de app ](../developers/installatie-van-nextcloud-development-omgeving.md)code
3. Zorg dat je de app geactiveerd hebt [link naar configuratie](../developers/de-opencatalogi-app-toevoegen-aan-nextcloud.md).
-Nadat de app succesvol is geconfigureerd, vindt u deze terug in het app-menu van Nextcloud. Klik op het 'open catalogi'-icoon om de app te openen. De tutorial gaat uit van een lege installatie.
+Nadat de app succesvol is geconfigureerd, vind je deze terug in het app-menu van Nextcloud. Klik op het 'OpenCatalogi'-icoon om de app te openen. De tutorial gaat uit van een lege installatie.
-![app menu](<../assets/nc_app_menu (1).png>)
+![OpenCatalogi-logo in het app menu](<../assets/nc_app_menu (1).png>)
-## Directory (moet)
+## Directory
Een OpenCatalogi-installatie is bedoeld om onderdeel te zijn van een federatief netwerk van catalogi. Deze kunt u terugvinden onder Instellingen -> Directory. In de directory staan alle bij deze installatie bekende catalogi die zich in andere installaties bevinden. OpenCatalogi-installaties wisselen onderling hun directory uit, dus om onderdeel te worden van het federatieve netwerk moet er minimaal één andere catalogus bekend zijn.
@@ -22,40 +22,86 @@ Catalogi worden gedefinieerd aan de hand van de plek waar ze leven op het intern
![directory toevoegen formulier](../assets/oc_directory_toevoegen_form.png)
-## Zoeken (moet)
+## Zoeken
Nadat je de app geïnstalleerd hebt, kun je het zoekscherm gebruiken om te zoeken naar gegevens bij andere organisaties. Ga hiervoor naar het menu-item 'Zoeken'.
-Aan de linkerkant worden gevonden publicaties weergegeven, aan de rechterkant treft u in tabbladen zoekmiddelen met daarin:
+Aan de linkerkant worden de gevonden publicaties weergegeven, terwijl aan de rechterkant in tabbladen de zoekmiddelen beschikbaar zijn:
* **Zoeken**: Het algemene zoekveld en de zoekknop.
-* **Catalogi**: Hierin kunt u aangeven in welke voor uw organisatie actieve catalogi u wilt zoeken.
-* **Metadata**: Hierin kunt u aangeven naar welke voor uw organisatie actieve metadatatypes u wilt zoeken.
+* **Catalogi**: Hierin kun je aangeven in welke actieve catalogi je wilt zoeken die relevant zijn voor jouw organisatie.
+* **Metadata**: Hierin kun je aangeven naar welke actieve metadatatypes je wilt zoeken die relevant zijn voor jouw organisatie.
-### Catalogus (moet)
+### Catalogus
Publicaties worden in OpenCatalogi onderverdeeld in catalogi.
-Stukje tekst met screenshots over het aanmaken van catalogi.
+Het aanmaken van een eigen catalogus kan eenvoudig door te navigeren naar `Instellingen` en te kiezen voor Catalogi. Aan de linkerzijde zie je de knop `Catalogi toevoegen`. Voor het aanmaken van een Catalogus is alleen een `titel` verplicht.
-Het aanmaken van een catalogus wordt gedaan in de `Instellingen`.
+
-* Maak een catalogus aan.
+
-## Metadata (moet)
+
-Stukje tekst met screenshots over het aanmaken van metadata.
+
-* Maak een metadatabeschrijving aan.
-* Voeg aan de metadatabeschrijving een aantal eigenschappen toe.
+## Metadatabeschrijving
-## Publicatie (moet)
+Metadata beschrijft een publicatie. Er wordt er informatie meegegeven over het publicatietype.
-Stukje tekst met screenshots over het aanmaken van publicaties.
-Stukje tekst met screenshots over het toevoegen van gegevens aan publicaties.
-Stukje tekst met screenshots over het toevoegen van bestanden aan publicaties.
+Het aanmaken van een eigen catalogus kan eenvoudig door te navigeren naar `Instellingen` en te kiezen voor `Metadata`. Aan de linkerzijde zie je de knop `Metadatabeschrijving toevoegen`. Voor het aanmaken van `Metadata` is alleen een `titel` verplicht.
-## Delen (moet)
+
-Stukje tekst met screenshots over het publiceren van publicaties.
-Stukje tekst over het terugtrekken van een publicatie.
+
+
+
+
+
+
+## Publicatie
+
+Aan de linkerkant bevindt zich een navigatiebalk met verschillende menuopties. Bovenaan de navigatiebalk is een blauwe knop zichtbaar met de tekst `Publicatie Aanmaken`.
+
+In het hoofdgedeelte van het scherm, aan de rechterkant, is er een melding die aangeeft dat er nog geen publicatie is geselecteerd, met de tekst `Geen publicatie`. Onder deze melding staat een blauwe knop met de tekst `Publicatie toevoegen`.
+
+Bovenaan het hoofdgedeelte is er een zoekbalk met een vergrootglas-icoon en een tekstveld om zoekopdrachten in te voeren. Rechts naast de zoekbalk is er een icoon met drie verticale puntjes.
+
+Het scherm is gebruiksvriendelijk ontworpen en biedt eenvoudige navigatie en duidelijke opties voor het aanmaken en toevoegen van publicaties.\
+\
+Bij het aanmaken van een publicatie zijn een aantal zaken van belang. Een publicatie behoort altijd tot een catalogus, dus die moet geselecteerd worden, net als metadata.
+
+
+
+
+
+
+
+
+
+## Bijlagen toevoegen
+
+Sommige publicaites hebben een bijlagen, zoals bijvoorbeeld voor convenanten het geval is. Een bijlage toevoegen aan een publicatie wordt gedaan door te klikken op de `Actie`-knop die rechtsboven te vinden is bij het klikken op een publicatie. Een van die opties is `Bijlage toevoegen`. Dit zorgt voor het tonen van de `Bijlage toevoegen`-modal. Hier kan via `url` of door een bestand toe te voegen vanaf de harde schrijf.
+
+
+
+
+
+
+
+
+
+## Delen
+
+Stukje tekst met screenshots over het publiceren van publicaties. Stukje tekst over het terugtrekken van een publicatie.\
+\
+Na het aanmaken van een publicatie is een publicatie makkelijk te delen (publiceren) door deze openbaar te maken. Dit kan door naar de drie bolletjes te gaan naast de publicatie en te kiezen voor `publiceren`. \
+\
+Op dezelfde plek is de optie `depubliceren` te vinden. Dit is gebeurd in het onderstaande screenshot, waar ook de status `retracted` te zien is.
+
+
+
+
+
+
diff --git a/docs/installatie/instructies.md b/docs/installatie/instructies.md
index 9ebca127..b8e32380 100644
--- a/docs/installatie/instructies.md
+++ b/docs/installatie/instructies.md
@@ -10,20 +10,22 @@ Volg deze stappen om Nextcloud eenvoudig te installeren en te gebruiken:
* We hebben gekozen voor TheGoodCloud, zonder enige voorkeur.
* Je ontvangt een activatiemail, dit kan tot 6 uur duren. Zoals altijd, check ook de spambox.
* Eenmaal ingelogd ziet het scherm er zo uit:\
- \
- ![](<../.gitbook/assets/image (4) (1).png>) \\
+ \\
+
+
2. **Nextcloud-app installeren via de appstore**:
Let op! Je hebt hier een admin-account voor nodig. Dit werkt mogelijk niet met trail-versies.
* Navigeer naar jouw profiel log, rechts in de Nextcloud app. Klik erop en kies "Apps" .
-\
-![](<../.gitbook/assets/image (1) (1) (1) (1) (1) (1) (1).png>)
+\\
+
+
3. **OpenCatalogi installeren**:
-* Nadat je bent ingelogd in de Nextcloud-app, ga naar de app store binnen de Nextcloud-omgeving.
+* Nadat je bent ingelogd in de Nextcloud-app, ga naar de appstore binnen de Nextcloud-omgeving.
* Zoek naar "OpenCatalogi" en installeer de app.
* Volg de instructies om OpenCatalogi te configureren en te gebruiken.
diff --git a/docs/installatie/logging.md b/docs/installatie/logging.md
index 526a66c6..1e08c3e7 100644
--- a/docs/installatie/logging.md
+++ b/docs/installatie/logging.md
@@ -1,28 +1,28 @@
-# Logging
+# Audit en logging
-Voor logging maken we gebruik van de ingeboude admin\_audit systemetiek van next cloud, meer daarover kan je [hier](https://docs.nextcloud.com/server/29/admin_manual/configuration_server/logging_configuration.html#admin-audit-log) vinden.
+Voor logging maken we gebruik van de ingebouwde admin\_audit systematiek van next cloud, meer daarover kan je [hier](https://docs.nextcloud.com/server/29/admin_manual/configuration_server/logging_configuration.html#admin-audit-log) vinden.
## System logging
-Als audit trails aanstaan worden automatisch alle systeem fouten gelogd, die kunnen vervolgens worden ingezien met [log reader](https://github.com/nextcloud/logreader) (admin->logging)
+Als audit trails aanstaan worden automatisch alle systeemfouten gelogd, die kunnen vervolgens worden ingezien met [log reader](https://github.com/nextcloud/logreader) (admin->logging)
![alt text](image.png)
-## Change loging
+## Change logging
-Wijziging's (pogingen) worden gelogd via api calls. Dit vanwege twee reden:
+Wijzigings- (pogingen) worden gelogd via API calls. Dit vanwege twee reden:
1. Zo loggen we alle pogingen, ongeacht of ze via de functioneel beheer omgeving of een specifieke afhandel applicatie zijn gemaakt
2. We loggen pogingen, dus ook mislukte wijzigingen (bijvoorbeeld vanwege foutieve invoer of rechten) worden bijgehouden
-Deze logs zijn generiek in te zien via [log reader](https://github.com/nextcloud/logreader) of speciefiek via de functioneel beheer interface.
+Deze logs zijn generiek in te zien via [log reader](https://github.com/nextcloud/logreader) of specifiek via de functioneel beheer interface.
## Security logging
-Foutieve inlogpogingen, overmatige bevragingen, ongeldige invoer etc worden allemaal weggeschreven naar de logs zijn daarin dus terug te vinden via log reader of te exporteren naar een dashboard dat meerdere installaties volgt.
+Foutieve inlogpogingen, overmatige bevragingen, ongeldige invoer etc. worden allemaal weggeschreven naar de logs zijn daarin dus terug te vinden via log reader of te exporteren naar een dashboard dat meerdere installaties volgt.
## Via Loki, Prometheus en Grafana
-We raden sterk aan om op saas omgevingen gebruik te maken van dashboard om (verdacht) gedrag van gebruiker te volgen naar de algemene gezondheid van de installatie. Dit is zeker raadsaam binnen [saas omgevingen](saas.md) waarbij er doorgaan gebruik wordt gemaakt van één installatie per tenant (klant). Overzicht houden wordt dan snel moelijk tot onmogenlijk en op performance en security wil je pro actief acteren.
+We raden sterk aan om op SaaS-omgevingen gebruik te maken van dashboard om (verdacht) gedrag van gebruiker te volgen naar de algemene gezondheid van de installatie. Dit is zeker raadzaam binnen S[aaS-omgevingen](saas.md) waarbij er doorgaan gebruik wordt gemaakt van één installatie per tenant (klant). Overzicht houden wordt dan snel moeilijk tot onmogelijk en op performance en security wil je proactief acteren.
-Vanuit de nextcloud community is er een mooie [tutorial](https://okxo.de/monitor-your-nextcloud-logs-for-suspicious-activities/) beschickbaar over hoe je de nextcloud audit trails kan overbrengen naar je grafana dashboard zodat je zicht hebt op (bijvoorbeeld) mislukte inlog pogingen.
+Vanuit de Nextcloud-community is er een mooie [tutorial](https://okxo.de/monitor-your-nextcloud-logs-for-suspicious-activities/) beschikbaar over hoe je de Nextcloud-audit trails kan overbrengen naar je Grafana-dashboard zodat je zicht hebt op (bijvoorbeeld) mislukte inlog pogingen.
diff --git a/docs/installatie/on-prem-server.md b/docs/installatie/on-prem-server.md
index f00533c0..bd2bf3cc 100644
--- a/docs/installatie/on-prem-server.md
+++ b/docs/installatie/on-prem-server.md
@@ -7,12 +7,16 @@ is zeker niet nodig voor het gebruik van de OpenCatalogi Nextcloud-app
# On-Prem server
+***
+
+## On-Prem server
+
Hoewel niet elke (semi-)overheidsinstelling een eigen Nextcloud-server nodig heeft, is het voor sommigen een aantrekkelijke optie vanwege specifieke voordelen. Deze instellingen kunnen onder andere zijn:
1. **Overheidsinstanties**: Organisaties die strikte regelgeving omtrent gegevensbeveiliging en -opslag moeten naleven.
2. **Organisaties die verdere configuratie vereisen**: Bedrijven en instellingen die specifieke configuraties en integraties nodig hebben om aan hun unieke operationele eisen te voldoen.
-#### Voordelen van een eigen Nextcloud-server
+**Voordelen van een eigen Nextcloud-server**
1. **Gegevenscontrole en -beveiliging**: Volledige controle over waar gegevens worden opgeslagen en wie er toegang toe heeft, wat essentieel is voor het beschermen van gevoelige informatie.
2. **Aanpasbaarheid**: Mogelijkheid om de Nextcloud-omgeving aan te passen aan specifieke behoeften en te integreren met andere systemen die de organisatie gebruikt.
@@ -20,7 +24,7 @@ Hoewel niet elke (semi-)overheidsinstelling een eigen Nextcloud-server nodig hee
4. **Offline toegang**: Toegang tot gegevens en applicaties, zelfs zonder internetverbinding, wat belangrijk kan zijn in noodgevallen of afgelegen locaties.
5. **Compliantie**: Voldoen aan wettelijke en sectorale eisen voor gegevensopslag en -beveiliging, zoals de AVG (GDPR) in Europa.
-#### Systeemeisen voor een Nextcloud-server
+**Systeemeisen voor een Nextcloud-server**
De systeemeisen voor het draaien van een eigen Nextcloud-server kunnen variëren afhankelijk van de schaal en het gebruik. Enkele basisvereisten zijn:
diff --git a/docs/installatie/saas.md b/docs/installatie/saas.md
index bf7473c5..856e6273 100644
--- a/docs/installatie/saas.md
+++ b/docs/installatie/saas.md
@@ -1,10 +1,10 @@
# SAAS en Dashboarding
-De open catalogi nextcloud app is ontworpen om als SAAS dienst te worden aangeboden aan overheden,
+De OpenCatalogi-Nextcloud app is ontworpen om als SaaS-dienst te worden aangeboden aan overheden,
-## Multy tenancy by installion
+## Multi-tenancy by installion
-Meerdere tenants in apparte namespaces
+Meerdere tenants in aparte namespaces
# Dashboarding
diff --git a/docs/installatie/systeemeisen-voor-nextcloud.md b/docs/installatie/systeemeisen-voor-nextcloud.md
index 00bd5ce8..a311ac40 100644
--- a/docs/installatie/systeemeisen-voor-nextcloud.md
+++ b/docs/installatie/systeemeisen-voor-nextcloud.md
@@ -8,6 +8,10 @@ functionaliteit.
# Systeemeisen voor Nextcloud
+***
+
+## Systeemeisen voor Nextcloud
+
**Desktop Client**
* **Besturingssysteem:**
@@ -46,6 +50,6 @@ functionaliteit.
* **Netwerk:** Actieve internetverbinding om toegang te krijgen tot Nextcloud server en synchronisatie uit te voeren.
* **Veiligheid:** Gebruik van HTTPS wordt aanbevolen voor veilige gegevensoverdracht.
-#### Opmerkingen
+**Opmerkingen**
Het wordt aanbevolen om regelmatig de laatste updates van het besturingssysteem en de Nextcloud-app te installeren voor optimale prestaties en veiligheid.
diff --git a/docs/veel-gestelde-vragen.md b/docs/veel-gestelde-vragen.md
new file mode 100644
index 00000000..92a26148
--- /dev/null
+++ b/docs/veel-gestelde-vragen.md
@@ -0,0 +1 @@
+# Veel gestelde vragen
diff --git a/lib/Controller/AttachmentsController.php b/lib/Controller/AttachmentsController.php
index be2e3d88..c7776c8c 100644
--- a/lib/Controller/AttachmentsController.php
+++ b/lib/Controller/AttachmentsController.php
@@ -9,6 +9,7 @@
use OCA\OpenCatalogi\Service\FileService;
use OCA\OpenCatalogi\Service\ObjectService;
use OCP\AppFramework\Controller;
+use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Http\JSONResponse;
use OCP\IAppConfig;
@@ -99,7 +100,7 @@ public function index(ObjectService $objectService): JSONResponse
if ($this->config->hasKey(app: $this->appName, key: 'mongoStorage') === false
|| $this->config->getValueString(app: $this->appName, key: 'mongoStorage') !== '1'
) {
- return new JSONResponse(['results' =>$this->attachmentMapper->findAll()]);
+ return new JSONResponse(['results' => $this->attachmentMapper->findAll()]);
}
$dbConfig['base_uri'] = $this->config->getValueString(app: $this->appName, key: 'mongodbLocation');
$dbConfig['headers']['api-key'] = $this->config->getValueString(app: $this->appName, key: 'mongodbKey');
@@ -131,7 +132,11 @@ public function show(string|int $id, ObjectService $objectService): JSONResponse
if ($this->config->hasKey(app: $this->appName, key: 'mongoStorage') === false
|| $this->config->getValueString(app: $this->appName, key: 'mongoStorage') !== '1'
) {
- return new JSONResponse($this->attachmentMapper->find(id: (int) $id));
+ try {
+ return new JSONResponse($this->attachmentMapper->find(id: (int) $id));
+ } catch (DoesNotExistException $exception) {
+ return new JSONResponse(data: ['error' => 'Not Found'], statusCode: 404);
+ }
}
$dbConfig['base_uri'] = $this->config->getValueString(app: $this->appName, key: 'mongodbLocation');
$dbConfig['headers']['api-key'] = $this->config->getValueString(app: $this->appName, key: 'mongodbKey');
@@ -156,7 +161,7 @@ private function checkUploadedFile(): JSONResponse|array
$uploadedFile = $this->request->getUploadedFile(key: '_file');
if (empty($uploadedFile) === true) {
- return new JSONResponse(data: ['error' => 'No file uploaded for key "_file"'], statusCode: 400);
+ return new JSONResponse(data: ['error' => 'Please upload a file using key "_file" or give a "downloadUrl"'], statusCode: 400);
}
// Check for upload errors
@@ -168,14 +173,14 @@ private function checkUploadedFile(): JSONResponse|array
}
/**
- * Gets all params from the request body and then validates if the URL fields are actual valid urls (or null).
+ * Validates if the URL fields are actual valid urls (or null).
+ *
+ * @param array $data The form-data fields and their values (/request body).
*
* @return JSONResponse|array An error response if there are validation errors or an array containing all request body params.
*/
- private function checkRequestBody(): JSONResponse|array
+ private function checkRequestBody(array $data): JSONResponse|array
{
- $data = $this->request->getParams();
-
$errorMsg = [];
if (empty($data['accessUrl']) === false && filter_var(value: $data['accessUrl'], filter: FILTER_VALIDATE_URL) === false) {
$errorMsg[] = "accessUrl is not a valid url";
@@ -226,7 +231,7 @@ private function handleFile(array $uploadedFile): JSONResponse|string
/**
- * Adds information about the uploaded file to the appropriate Attachment fields. And removes fields we do not want to post.
+ * Adds information about the uploaded file to the appropriate Attachment fields.
*
* @param array $data The form-data fields and their values (/request body) that we are going to update before posting the Attachment.
* @param array $uploadedFile Information about the uploaded file from the request body.
@@ -252,14 +257,8 @@ private function AddFileInfoToData(array $data, array $uploadedFile, string $fil
if (empty($data['accessUrl']) === true) {
$data['accessUrl'] = $shareLink;
}
- $data['downloadUrl'] = "$shareLink/download";
-
- // Remove fields we should never post
- unset($data['id']);
- foreach($data as $key => $value) {
- if(str_starts_with(haystack: $key, needle: '_')) {
- unset($data[$key]);
- }
+ if (empty($data['downloadUrl']) === true) {
+ $data['downloadUrl'] = "$shareLink/download";
}
return $data;
@@ -274,26 +273,40 @@ private function AddFileInfoToData(array $data, array $uploadedFile, string $fil
*/
public function create(ObjectService $objectService, ElasticSearchService $elasticSearchService): JSONResponse
{
- // Check if a file was uploaded
- $uploadedFile = $this->checkUploadedFile();
- if ($uploadedFile instanceof JSONResponse) {
- return $uploadedFile;
+ $data = $this->request->getParams();
+ // Uploaded _file and downloadURL are mutually exclusive
+ if (empty($data['downloadUrl']) === true) {
+ // Check if a file was uploaded
+ $uploadedFile = $this->checkUploadedFile();
+ if ($uploadedFile instanceof JSONResponse) {
+ return $uploadedFile;
+ }
}
- // Get form-data field/request body.
- $data = $this->checkRequestBody();
+ // Get form-data field/request body and validate the input.
+ $data = $this->checkRequestBody($data);
if ($data instanceof JSONResponse) {
return $data;
}
- // Handle saving the uploaded file in NextCloud
- $filePath = $this->handleFile(uploadedFile: $uploadedFile);
- if ($filePath instanceof JSONResponse) {
- return $filePath;
+ if (empty($uploadedFile) === false) {
+ // Handle saving the uploaded file in NextCloud
+ $filePath = $this->handleFile(uploadedFile: $uploadedFile);
+ if ($filePath instanceof JSONResponse) {
+ return $filePath;
+ }
+
+ // Update Attachment data
+ $data = $this->AddFileInfoToData(data: $data, uploadedFile: $uploadedFile, filePath: $filePath);
}
- // Update Attachment data
- $data = $this->AddFileInfoToData(data: $data, uploadedFile: $uploadedFile, filePath: $filePath);
+ // Remove fields we should never post
+ unset($data['id']);
+ foreach($data as $key => $value) {
+ if(str_starts_with(haystack: $key, needle: '_')) {
+ unset($data[$key]);
+ }
+ }
if ($this->config->hasKey(app: $this->appName, key: 'mongoStorage') === false
|| $this->config->getValueString(app: $this->appName, key: 'mongoStorage') !== '1'
diff --git a/lib/Controller/CatalogiController.php b/lib/Controller/CatalogiController.php
index e964309a..83f26a89 100644
--- a/lib/Controller/CatalogiController.php
+++ b/lib/Controller/CatalogiController.php
@@ -7,6 +7,7 @@
use OCA\OpenCatalogi\Service\ObjectService;
use OCA\OpenCatalogi\Service\SearchService;
use OCP\AppFramework\Controller;
+use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Http\JSONResponse;
use OCP\IAppConfig;
@@ -81,7 +82,11 @@ public function show(string|int $id, ObjectService $objectService): JSONResponse
if($this->config->hasKey($this->appName, 'mongoStorage') === false
|| $this->config->getValueString($this->appName, 'mongoStorage') !== '1'
) {
- return new JSONResponse($this->catalogMapper->find(id: (int) $id));
+ try {
+ return new JSONResponse($this->catalogMapper->find(id: (int) $id));
+ } catch (DoesNotExistException $exception) {
+ return new JSONResponse(data: ['error' => 'Not Found'], statusCode: 404);
+ }
}
try {
diff --git a/lib/Controller/DirectoryController.php b/lib/Controller/DirectoryController.php
index b6af3038..53f32965 100644
--- a/lib/Controller/DirectoryController.php
+++ b/lib/Controller/DirectoryController.php
@@ -7,6 +7,7 @@
use OCA\OpenCatalogi\Service\ObjectService;
use OCA\OpenCatalogi\Service\SearchService;
use OCP\AppFramework\Controller;
+use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Http\JSONResponse;
use OCP\IAppConfig;
@@ -115,7 +116,11 @@ public function show(string|int $id, ObjectService $objectService, DirectoryServ
if($this->config->hasKey($this->appName, 'mongoStorage') === false
|| $this->config->getValueString($this->appName, 'mongoStorage') !== '1'
) {
- return new JSONResponse($this->listingMapper->find(id: (int) $id));
+ try {
+ return new JSONResponse($this->listingMapper->find(id: (int) $id));
+ } catch (DoesNotExistException $exception) {
+ return new JSONResponse(data: ['error' => 'Not Found'], statusCode: 404);
+ }
}
$dbConfig['base_uri'] = $this->config->getValueString(app: $this->appName, key: 'mongodbLocation');
$dbConfig['headers']['api-key'] = $this->config->getValueString(app: $this->appName, key: 'mongodbKey');
diff --git a/lib/Controller/MetaDataController.php b/lib/Controller/MetaDataController.php
index ace7db19..282ac304 100644
--- a/lib/Controller/MetaDataController.php
+++ b/lib/Controller/MetaDataController.php
@@ -6,6 +6,7 @@
use OCA\OpenCatalogi\Service\ObjectService;
use OCA\OpenCatalogi\Service\SearchService;
use OCP\AppFramework\Controller;
+use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Http\JSONResponse;
use OCP\IAppConfig;
@@ -84,7 +85,11 @@ public function show(string|int $id, ObjectService $objectService): JSONResponse
if($this->config->hasKey($this->appName, 'mongoStorage') === false
|| $this->config->getValueString($this->appName, 'mongoStorage') !== '1'
) {
- return new JSONResponse($this->metaDataMapper->find(id: (int) $id));
+ try {
+ return new JSONResponse($this->metaDataMapper->find(id: (int) $id));
+ } catch (DoesNotExistException $exception) {
+ return new JSONResponse(data: ['error' => 'Not Found'], statusCode: 404);
+ }
}
$dbConfig['base_uri'] = $this->config->getValueString(app: $this->appName, key: 'mongodbLocation');
$dbConfig['headers']['api-key'] = $this->config->getValueString(app: $this->appName, key: 'mongodbKey');
diff --git a/lib/Controller/OrganisationsController.php b/lib/Controller/OrganisationsController.php
index 04cbbaf8..5039a395 100644
--- a/lib/Controller/OrganisationsController.php
+++ b/lib/Controller/OrganisationsController.php
@@ -6,6 +6,7 @@
use OCA\OpenCatalogi\Service\ObjectService;
use OCP\AppFramework\Controller;
use OCA\OpenCatalogi\Service\SearchService;
+use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Http\JSONResponse;
use OCP\IAppConfig;
@@ -93,7 +94,11 @@ public function show(string $id, ObjectService $objectService): JSONResponse
if($this->config->hasKey($this->appName, 'mongoStorage') === false
|| $this->config->getValueString($this->appName, 'mongoStorage') !== '1'
) {
- return new JSONResponse($this->organisationMapper->find(id: (int) $id));
+ try {
+ return new JSONResponse($this->organisationMapper->find(id: (int) $id));
+ } catch (DoesNotExistException $exception) {
+ return new JSONResponse(data: ['error' => 'Not Found'], statusCode: 404);
+ }
}
try {
diff --git a/lib/Controller/PublicationsController.php b/lib/Controller/PublicationsController.php
index 6534ff1d..3111b16e 100644
--- a/lib/Controller/PublicationsController.php
+++ b/lib/Controller/PublicationsController.php
@@ -2,14 +2,15 @@
namespace OCA\OpenCatalogi\Controller;
-use Elastic\Elasticsearch\Client;
use GuzzleHttp\Exception\GuzzleException;
+use OCA\OpenCatalogi\Db\AttachmentMapper;
use OCA\opencatalogi\lib\Db\Publication;
use OCA\OpenCatalogi\Db\PublicationMapper;
use OCA\OpenCatalogi\Service\ElasticSearchService;
use OCA\OpenCatalogi\Service\ObjectService;
use OCA\OpenCatalogi\Service\SearchService;
use OCP\AppFramework\Controller;
+use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Http\JSONResponse;
use OCP\IAppConfig;
@@ -24,6 +25,7 @@ public function __construct
$appName,
IRequest $request,
private readonly PublicationMapper $publicationMapper,
+ private readonly AttachmentMapper $attachmentMapper,
private readonly IAppConfig $config
)
{
@@ -83,17 +85,17 @@ public function page(?string $getParameter)
* @NoCSRFRequired
*/
public function catalog(string|int $id): TemplateResponse
- {
- // The TemplateResponse loads the 'main.php'
- // defined in our app's 'templates' folder.
- // We pass the $getParameter variable to the template
- // so that the value is accessible in the template.
- return new TemplateResponse(
- $this->appName,
- 'PublicationsIndex',
- []
- );
- }
+ {
+ // The TemplateResponse loads the 'main.php'
+ // defined in our app's 'templates' folder.
+ // We pass the $getParameter variable to the template
+ // so that the value is accessible in the template.
+ return new TemplateResponse(
+ $this->appName,
+ 'PublicationsIndex',
+ []
+ );
+ }
/**
* @NoAdminRequired
@@ -112,7 +114,7 @@ public function index(ObjectService $objectService, SearchService $searchService
$sort = $searchService->createSortForMySQL(filters: $filters);
$filters = $searchService->unsetSpecialQueryParams(filters: $filters);
- return new JSONResponse(['results' => $this->publicationMapper->findAll(limit: null, offset: null, filters: $filters, searchConditions: $searchConditions, searchParams: $searchParams, sort: $sort)]);
+ return new JSONResponse(['results' => $this->publicationMapper->findAll(filters: $filters, searchConditions: $searchConditions, searchParams: $searchParams, sort: $sort)]);
}
$filters = $searchService->createMongoDBSearchFilter(filters: $filters, fieldsToSearch: $fieldsToSearch);
@@ -133,16 +135,55 @@ public function index(ObjectService $objectService, SearchService $searchService
return new JSONResponse($results);
}
+ /**
+ * @NoAdminRequired
+ * @NoCSRFRequired
+ */
+ public function attachments(string|int $id, ObjectService $objectService): JSONResponse
+ {
+ $publication = $this->show($id, $objectService)->getData();
+ if ($this->config->hasKey(app: $this->appName, key: 'mongoStorage') === false
+ || $this->config->getValueString(app: $this->appName, key: 'mongoStorage') !== '1'
+ ) {
+ $publication = $publication->jsonSerialize();
+ }
+
+ $attachments = $publication['attachments'];
+
+ if ($this->config->hasKey($this->appName, 'mongoStorage') === false
+ || $this->config->getValueString($this->appName, 'mongoStorage') !== '1'
+ ) {
+ return new JSONResponse(['results' => $this->attachmentMapper->findMultiple($attachments)]);
+ }
+
+ $filters = [];
+ $filters['id']['$in'] = $attachments;
+
+ $dbConfig['base_uri'] = $this->config->getValueString(app: $this->appName, key: 'mongodbLocation');
+ $dbConfig['headers']['api-key'] = $this->config->getValueString(app: $this->appName, key: 'mongodbKey');
+ $dbConfig['mongodbCluster'] = $this->config->getValueString(app: $this->appName, key: 'mongodbCluster');
+
+ $filters['_schema'] = 'attachment';
+
+ $result = $objectService->findObjects(filters: $filters, config: $dbConfig);
+
+ return new JSONResponse(['results' => $result['documents']]);
+ }
+
/**
* @NoAdminRequired
* @NoCSRFRequired
*/
public function show(string|int $id, ObjectService $objectService): JSONResponse
{
- if($this->config->hasKey($this->appName, 'mongoStorage') === false
+ if ($this->config->hasKey($this->appName, 'mongoStorage') === false
|| $this->config->getValueString($this->appName, 'mongoStorage') !== '1'
) {
- return new JSONResponse($this->publicationMapper->find(id: (int) $id));
+ try {
+ return new JSONResponse($this->publicationMapper->find(id: (int) $id));
+ } catch (DoesNotExistException $exception) {
+ return new JSONResponse(data: ['error' => 'Not Found'], statusCode: 404);
+ }
}
$dbConfig['base_uri'] = $this->config->getValueString(app: $this->appName, key: 'mongodbLocation');
diff --git a/lib/Controller/SearchController.php b/lib/Controller/SearchController.php
index 7e4fcb90..7eca2aa4 100644
--- a/lib/Controller/SearchController.php
+++ b/lib/Controller/SearchController.php
@@ -101,8 +101,8 @@ public function index(SearchService $searchService): JSONResponse
$searchParams = $searchService->createMySQLSearchParams(filters: $filters);
$searchConditions = $searchService->createMySQLSearchConditions(filters: $filters, fieldsToSearch: $fieldsToSearch);
- $limit = null;
- $offset = null;
+ $limit = 30;
+ $offset = 0;
if(isset($filters['_limit']) === true) {
$limit = $filters['_limit'];
@@ -114,9 +114,19 @@ public function index(SearchService $searchService): JSONResponse
$filters = $searchService->unsetSpecialQueryParams(filters: $filters);
-
-
- return new JSONResponse(['results' => $this->publicationMapper->findAll(limit: $limit, offset: $offset, filters: $filters, searchConditions: $searchConditions, searchParams: $searchParams)]);
+ $total = $this->publicationMapper->count($filters);
+ $results = $this->publicationMapper->findAll(limit: $limit, offset: $offset, filters: $filters, searchConditions: $searchConditions, searchParams: $searchParams);
+ $pages = (int) ceil($total / $limit);
+
+ return new JSONResponse([
+ 'results' => $results,
+ 'facets' => [],
+ 'count' => count($results),
+ 'limit' => $limit,
+ 'page' => isset($filters['_page']) === true ? $filters['_page'] : 1,
+ 'pages' => $pages === 0 ? 1 : $pages,
+ 'total' => $total
+ ]);
}
//@TODO: find a better way to get query params. This fixes it for now.
diff --git a/lib/Controller/ThemesController.php b/lib/Controller/ThemesController.php
index 308c92c6..16454ac4 100644
--- a/lib/Controller/ThemesController.php
+++ b/lib/Controller/ThemesController.php
@@ -6,6 +6,7 @@
use OCA\OpenCatalogi\Service\ObjectService;
use OCA\OpenCatalogi\Service\SearchService;
use OCP\AppFramework\Controller;
+use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Http\JSONResponse;
use OCP\IAppConfig;
@@ -107,7 +108,11 @@ public function show(string $id, ObjectService $objectService): JSONResponse
if($this->config->hasKey($this->appName, 'mongoStorage') === false
|| $this->config->getValueString($this->appName, 'mongoStorage') !== '1'
) {
- return new JSONResponse($this->themeMapper->find(id: (int) $id));
+ try {
+ return new JSONResponse($this->themeMapper->find(id: (int) $id));
+ } catch (DoesNotExistException $exception) {
+ return new JSONResponse(data: ['error' => 'Not Found'], statusCode: 404);
+ }
}
try {
diff --git a/lib/Db/AttachmentMapper.php b/lib/Db/AttachmentMapper.php
index 9e97af7e..9c32b8b6 100644
--- a/lib/Db/AttachmentMapper.php
+++ b/lib/Db/AttachmentMapper.php
@@ -28,6 +28,17 @@ public function find(int $id): Attachment
return $this->findEntity(query: $qb);
}
+ public function findMultiple(array $ids): array
+ {
+ $qb = $this->db->getQueryBuilder();
+
+ $qb->select('*')
+ ->from('attachments')
+ ->where($qb->expr()->in('id', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)));
+
+ return $this->findEntities(query: $qb);
+ }
+
public function findAll($limit = null, $offset = null): array
{
$qb = $this->db->getQueryBuilder();
diff --git a/lib/Db/Catalog.php b/lib/Db/Catalog.php
index 05958101..320b0aac 100644
--- a/lib/Db/Catalog.php
+++ b/lib/Db/Catalog.php
@@ -42,12 +42,6 @@ public function getJsonFields(): array
public function hydrate(array $object): self
{
-
-
- if(isset($object['metadata']) === false) {
- $object['metadata'] = [];
- }
-
$jsonFields = $this->getJsonFields();
foreach($object as $key => $value) {
diff --git a/lib/Db/PublicationMapper.php b/lib/Db/PublicationMapper.php
index 74f6f0fd..9aa60c71 100644
--- a/lib/Db/PublicationMapper.php
+++ b/lib/Db/PublicationMapper.php
@@ -28,14 +28,78 @@ public function find(int $id): Publication
return $this->findEntity(query: $qb);
}
- public function findAll(
- ?int $limit = null,
- ?int $offset = null,
- ?array $filters = [],
- ?array $searchConditions = [],
- ?array $searchParams = [],
- ?array $sort = []
- ): array {
+ private function parseComplexFilter(IQueryBuilder $queryBuilder, array $filter, string $name): IQueryBuilder
+ {
+ foreach($filter as $key => $value) {
+ switch($key) {
+ case '>=':
+ case 'after':
+ $queryBuilder->andWhere($queryBuilder->expr()->gte($name, $queryBuilder->createNamedParameter($value)));
+ break;
+ case '>':
+ case 'strictly_after':
+ $queryBuilder->andWhere($queryBuilder->expr()->gt($name, $queryBuilder->createNamedParameter($value)));
+ break;
+ case '<=':
+ case 'before':
+ $queryBuilder->andWhere($queryBuilder->expr()->lte($name, $queryBuilder->createNamedParameter($value)));
+ break;
+ case '<':
+ case 'strictly_before':
+ $queryBuilder->andWhere($queryBuilder->expr()->lt($name, $queryBuilder->createNamedParameter($value)));
+ break;
+ default:
+ $queryBuilder->andWhere($queryBuilder->expr()->eq($name, $queryBuilder->createNamedParameter($filter)));
+ }
+ }
+
+ return $queryBuilder;
+ }
+
+ private function addFilters(IQueryBuilder $queryBuilder, array $filters): IQueryBuilder
+ {
+ foreach($filters as $key => $filter) {
+ if(is_array($filter) === false) {
+ $queryBuilder->andWhere($queryBuilder->expr()->eq($key, $queryBuilder->createNamedParameter($key)));
+ $queryBuilder->setParameter($key, $filter);
+ continue;
+ }
+
+ $queryBuilder = $this->parseComplexFilter(queryBuilder: $queryBuilder, filter: $filter, name: $key);
+ }
+
+ return $queryBuilder;
+ }
+
+ public function count(?array $filters = [], ?array $searchConditions = [], ?array $searchParams = []): int
+ {
+
+
+ $qb = $this->db->getQueryBuilder();
+
+ $qb->selectAlias($qb->createFunction('COUNT(*)'), 'count')
+ ->from('publications');
+
+
+ $qb = $this->addFilters(queryBuilder: $qb, filters: $filters);
+
+
+ if (!empty($searchConditions)) {
+ $qb->andWhere('(' . implode(' OR ', $searchConditions) . ')');
+ foreach ($searchParams as $param => $value) {
+ $qb->setParameter($param, $value);
+ }
+ }
+
+ $cursor = $qb->execute();
+ $row = $cursor->fetch();
+ $cursor->closeCursor();
+
+ return $row['count'];
+ }
+
+ public function findAll(?int $limit = null, ?int $offset = null, ?array $filters = [], ?array $searchConditions = [], ?array $searchParams = [], ?array $sort = []): array
+ {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
@@ -43,15 +107,7 @@ public function findAll(
->setMaxResults($limit)
->setFirstResult($offset);
- foreach($filters as $filter => $value) {
- if ($value === 'IS NOT NULL') {
- $qb->andWhere($qb->expr()->isNotNull($filter));
- } elseif ($value === 'IS NULL') {
- $qb->andWhere($qb->expr()->isNull($filter));
- } else {
- $qb->andWhere($qb->expr()->eq($filter, $qb->createNamedParameter($value)));
- }
- }
+ $qb = $this->addFilters(queryBuilder: $qb, filters: $filters);
if (empty($searchConditions) === false) {
$qb->andWhere('(' . implode(' OR ', $searchConditions) . ')');
@@ -66,7 +122,7 @@ public function findAll(
$qb->addOrderBy($field, $direction);
}
}
-
+
return $this->findEntities(query: $qb);
}
diff --git a/lib/Migration/Version6Date20240723125106.php b/lib/Migration/Version6Date20240723125106.php
index d12ccc8d..b04a1818 100644
--- a/lib/Migration/Version6Date20240723125106.php
+++ b/lib/Migration/Version6Date20240723125106.php
@@ -80,18 +80,18 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
'notnull' => false,
]
);
- $table->addColumn(name: 'organization', typeName: TYPES::JSON, options: [
- 'default' => 'a:0:{}',
+ $organization = $table->addColumn(name: 'organization', typeName: TYPES::JSON, options: [
'notnull' => false,
]);
- $table->addColumn(name: 'data', typeName: TYPES::JSON, options: [
- 'default' => 'a:0:{}',
+ $organization->setDefault('{}');
+ $data = $table->addColumn(name: 'data', typeName: TYPES::JSON, options: [
'notnull' => false,
]);
- $table->addColumn(name: 'attachments', typeName: TYPES::JSON, options: [
- 'default' => 'a:0:{}',
+ $data->setDefault('{}');
+ $attachments = $table->addColumn(name: 'attachments', typeName: TYPES::JSON, options: [
'notnull' => false,
]);
+ $attachments->setDefault('{}');
$table->addColumn(name: 'attachment_count', typeName: TYPES::INTEGER);
$table->addColumn(name: 'schema', typeName: TYPES::STRING);
$table->addColumn(name: 'status', typeName: TYPES::STRING);
diff --git a/lib/Migration/Version6Date20240808085441.php b/lib/Migration/Version6Date20240808085441.php
index 28e43b3a..c1a2bea2 100644
--- a/lib/Migration/Version6Date20240808085441.php
+++ b/lib/Migration/Version6Date20240808085441.php
@@ -53,13 +53,13 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
]);
}
if($table->hasColumn(name: 'metadata') === false) {
- $table->addColumn(
+ $metadata = $table->addColumn(
name: 'metadata',
typeName: Types::JSON,
options: [
'notNull' => false,
- 'default' => 'a:0:{}'
]);
+ $metadata->setDefault('{}');
}
}
diff --git a/lib/Service/SearchService.php b/lib/Service/SearchService.php
index d31d18b1..36e5c759 100644
--- a/lib/Service/SearchService.php
+++ b/lib/Service/SearchService.php
@@ -74,6 +74,7 @@ public function sortResultArray(array $a, array $b): int
return $a['_score'] <=> $b['_score'];
}
+
/**
*
*/
@@ -96,13 +97,14 @@ public function search(array $parameters, array $elasticConfig, array $dbConfig,
// $directory = $this->objectService->findObjects(filters: ['_schema' => 'directory'], config: $dbConfig);
if(count($directory) === 0) {
+ $pages = (int) ceil($totalResults / $limit);
return [
'results' => $localResults['results'],
'facets' => $localResults['facets'],
'count' => count($localResults['results']),
'limit' => $limit,
'page' => $page,
- 'pages' => ceil($totalResults / $limit),
+ 'pages' => $pages === 0 ? 1 : $pages,
'total' => $totalResults
];
}
@@ -155,13 +157,15 @@ public function search(array $parameters, array $elasticConfig, array $dbConfig,
}
}
+ $pages = (int) ceil($totalResults / $limit);
+
return [
'results' => $results,
'facets' => $aggregations,
'count' => count($results),
'limit' => $limit,
'page' => $page,
- 'pages' => ceil($totalResults / $limit),
+ 'pages' => $pages === 0 ? 1 : $pages,
'total' => $totalResults
];
}
diff --git a/src/dialogs/catalogiMetadata/DeleteCatalogiMetadata.vue b/src/dialogs/catalogiMetadata/DeleteCatalogiMetadata.vue
index fb97f08b..a4b86a17 100644
--- a/src/dialogs/catalogiMetadata/DeleteCatalogiMetadata.vue
+++ b/src/dialogs/catalogiMetadata/DeleteCatalogiMetadata.vue
@@ -5,13 +5,13 @@ import { navigationStore, catalogiStore, metadataStore } from '../../store/store
Wil je {{ metadataStore.metaDataItem?.title }} verwijderen van {{ catalogiStore.catalogiItem?.title }}?