Compare commits

...

30 Commits

Author SHA1 Message Date
mirdono
8e2dc898f5 chore: release v1.35.0 2025-08-04 18:56:51 +02:00
mirdono
de5bb3e392 chore: bump frontend 2025-08-04 14:23:30 +02:00
mirdono
6ef9690647 chore: pre-release v1.35.0-0 2025-08-04 14:14:16 +02:00
wolfez
b6bdd5b067 update changelog 2025-08-04 13:06:56 +02:00
wolfderechter
97263fe7ae Merge pull request #566 from lblod/feature/remove-duplicate-memberships
add duplicate memberships cleanup migration
2025-08-01 10:03:51 +02:00
wolfez
2ef1d8ab7b use specific graphs 2025-08-01 10:02:49 +02:00
Kike Franssen
3e7d92624c OP-3560 Fix Kbo organisations date formats (#567)
- Added a migration to change (only for KboOrganisaties) all dates/strings for modified and startDate to dateTime according to comment in ticket
- Added a comment to remind to bump version of kbo-data-sync when the kbo-data-sync PR is merged.
- Added to changelog
2025-07-31 13:04:22 +02:00
wolfez
9dffe4b223 Add migration to fix reversed memberships with no correct membership 2025-07-31 11:32:24 +02:00
wolfez
6f2db80f50 use meaningful variableNames 2025-07-31 11:01:07 +02:00
mirdono
8308644e82 chore: bump scope-of-operation service 2025-07-30 17:27:10 +02:00
wolfez
7ac0394d2f Merge remote-tracking branch 'origin/development' into feature/remove-duplicate-memberships 2025-07-28 11:22:47 +02:00
wolfez
215deda183 add duplicate memberships cleanup migration 2025-07-25 13:54:23 +02:00
Claire Lovisa
729bee7f14 Merge branch 'datafix/dev-addresses-linked-to-site-and-mandataris' into development 2025-07-25 11:14:27 +02:00
Claire Lovisa
8146686b48 Restore wrongly deleted entry in changelog 2025-07-25 11:04:59 +02:00
Claire Lovisa
8d133fd1c9 Merge pull request #564 from lblod/datafix/dev-addresses-linked-to-site-and-mandataris
Add migration to fix dev addresses
2025-07-25 11:01:19 +02:00
Claire Lovisa
101618c156 Merge branch 'development' into datafix/dev-addresses-linked-to-site-and-mandataris 2025-07-25 11:01:08 +02:00
wolfderechter
b51293ca3a Merge pull request #565 from lblod/feature/cleanup-general-memberships-in-favor-of-specific
add migration to cleanup general memberships if specific ones exist
2025-07-23 10:15:15 +02:00
Claire Lovisa
e1eca4b185 Add cleanup of addresses graph and move to regular migrations 2025-07-22 12:01:01 +02:00
wolfez
1c46d49976 add migration to cleanup general memberships if specific ones exist 2025-07-18 15:06:53 +02:00
Claire Lovisa
68cbd39c9d Add migration to fix dev addresses 2025-07-14 16:23:22 +02:00
mirdono
4982224a78 chore: corrected command in deploy notes 2025-07-11 16:00:30 +02:00
mirdono
cbf320711d chore: update changelog
Co-authored-by: @cecemel
2025-07-11 15:37:22 +02:00
mirdono
6dfb0a656f feat: add project script to correct aggregate location labels
The previously added migrations can create new aggregate location resources for
worship administrative units that have multiple locations as scope of
operation. While those migrations did insert a label for these new location
resources, the contained names are typically not sorted alphabetically as
`GROUP_CONCAT` does not provide guarantees on sorting.

This script allows to generate additional migrations to correct those labels.

Co-authored-by: @cecemel
2025-07-11 15:35:29 +02:00
mirdono
387ef1eeea feat: set scope of operation for worship administrative units
Add migrations to set the initial scope of operation for worship administrative
units. These migrations work in several steps:
1. Extract the necessary relations between worship administrative units and
   locations based on the rules provided by business and insert this data in a
   temporary graph.
2. For worship administrative units related to only a single location. Simply
   add the triple setting that location as its scope of operation.
3. For worship administrative units related to multiple locations. Create new
   location resources that aggregates all locations linked to a single worship
   administrative unit and set this new location resource as scope of operation.
4. Clear the temporary graph.
2025-07-11 15:29:03 +02:00
mirdono
5a3ae13eb0 chore: bump scope of operation service 2025-07-11 15:26:40 +02:00
mirdono
57dca52171 chore: update changelog 2025-07-11 15:26:34 +02:00
mirdono
e7e76c187b feat: allow a location to be within multiple other locations
Due to the restriction that an organisation can have only 1
location (nl. werkingsgebied) we need to create ad-hoc locations containing
multiple locations. As such enforcing that a location can only be contained in a
single other location is too restrictive. For example, this would prevent the
same municipality location to be within two (or more) different locations for
different organisations.
2025-07-11 15:07:57 +02:00
mirdono
6a85ec7c96 refactor: move prov:Location to public types
In #542 the location data was moved to the public graph. This ensures that
resources type is readable from that graph.
2025-07-11 15:07:57 +02:00
mirdono
b272e1500c feat: dispatch requests to the scope of operation service 2025-07-11 15:07:57 +02:00
mirdono
7c2a54264a feat: add scope-of-operation-service to stack
This service provides functionality to manage an organisation's scope of
operation. To this end it facilitates that each organisation can be linked with
exactly one location resources as scope of operation, internally creating and
linking the appropriate resources.
2025-07-11 15:07:57 +02:00
18 changed files with 540 additions and 8 deletions

View File

@@ -1,6 +1,34 @@
# Changelog
## Unreleased
## v1.35.0 (2025-08-04)
### Frontend
- Bump to [v1.34.0](https://github.com/lblod/frontend-organization-portal/releases/tag/v1.34.0)
### Backend
- Add a service to manage organisation's their scope of operation [OP-3205]
- datamodel: Allow a location to be within multiple other locations [OP-3205]
- datafix: set scope of operation for worship administrative units [OP-3626]
- Clean addresses linked to both sites and contact points of mandatarissen and addresses that are in the wrong graph (admin unit graph but linked to a contact point in the worship graph) [DL-6701]
- datafix: cleanup of general memberships if specific ones exist [OP-3640]
- datafix: cleanup of duplicate memberships [OP-3634]
- Fix KBO organizations' date formats [OP-3560]
### Deploy notes
```
drc pull scope-of-operation; drc up -d scope-of-operation
drc restart db resource dispatcher
drc pull frontend; drc up -d frontend
drc restart migrations; drc logs -ft --tail=200 migrations
drc up -d kbo-data-sync
```
The labels for new location resources created when setting the scope of operation for worship services are not necessarily alphabetically sorted. To correct this run the `correct-location-labels` project script using [mu-cli](https://github.com/mu-semtech/mu-cli) and restart the migrations service once more to execute the generated local migrations.
```
mu script project-scripts correct-location-labels
drc restart migrations; drc logs -ft --tail=200 migrations
```
## v1.34.0 (2025-07-11)
### Frontend
- Bump to version [v1.33.0](https://github.com/lblod/frontend-organization-portal/releases/tag/v1.33.0)

View File

@@ -53,7 +53,8 @@ defmodule Acl.UserGroups.Config do
"http://lblod.data.gift/vocabularies/organisatie/VoorwaardenBedienaarCriterium",
"http://lblod.data.gift/vocabularies/organisatie/BedienaarCriteriumBewijsstuk",
"http://lblod.data.gift/vocabularies/organisatie/EredienstBeroepen",
"http://lblod.data.gift/vocabularies/organisatie/Rechtsvormtype"
"http://lblod.data.gift/vocabularies/organisatie/Rechtsvormtype",
"http://www.w3.org/ns/prov#Location"
]
@org_type [
@@ -80,11 +81,10 @@ defmodule Acl.UserGroups.Config do
"http://data.lblod.info/vocabularies/contacthub/AgentInPositie",
"http://mu.semte.ch/vocabularies/ext/KboOrganisatie",
"http://www.w3.org/ns/org#Membership",
"http://www.w3.org/2006/time#ProperInterval"
"http://www.w3.org/2006/time#ProperInterval",
]
@shared_protected_type [
"http://www.w3.org/ns/prov#Location",
"http://xmlns.com/foaf/0.1/Image",
"http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#FileDataObject"
]
@@ -117,7 +117,7 @@ defmodule Acl.UserGroups.Config do
?account <http://mu.semte.ch/vocabularies/ext/sessionRole> ?session_role.
FILTER( ?session_role = \"dashboard-user\" )
}"
}
}
end
def user_groups do
@@ -256,7 +256,7 @@ defmodule Acl.UserGroups.Config do
"http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#FileDataObject"
]
}
},
}
]
},

View File

@@ -393,6 +393,10 @@ defmodule Dispatcher do
forward(conn, path, "http://kbo-data-sync/sync-kbo-data/")
end
match "/scope-of-operation/*path", %{layer: api_services, accept: %{json: true}} do
forward(conn, path, "http://scope-of-operation/")
end
get "/ldes/*path", %{layer: :api_services} do
forward(conn, path, "http://ldes-backend/")
end

View File

@@ -0,0 +1,112 @@
PREFIX ere: <http://data.lblod.info/vocabularies/erediensten/>
PREFIX org: <http://www.w3.org/ns/org#>
PREFIX besluit: <http://data.vlaanderen.be/ns/besluit#>
# This migration extracts the relations between (central) worship services and
# their locations according to the rules provided by business. These links are
# inserted into a temporary graph for further processing.
# Worship services
## Municipality organised
INSERT {
GRAPH <http://mu.semte.ch/graphs/temp-for-worship-organizations-scope> {
?ws besluit:werkingsgebied ?scope .
}
} WHERE {
GRAPH <http://mu.semte.ch/graphs/worship-service> {
?ws a ere:BestuurVanDeEredienst ;
ere:typeEredienst ?worshipType .
VALUES ?worshipType {
<http://lblod.data.gift/concepts/99536dd6eb0d2ef38a89efafb17e7389> # Anglicaans
<http://lblod.data.gift/concepts/1a1abeafc973d27cebcb2d7a15b2d823> # Israëlitisch
<http://lblod.data.gift/concepts/e8cba1540b35a32e9cb45126c38c03c6> # Protestants
<http://lblod.data.gift/concepts/b13d1d623626bc1ee75c7d20bc60e3c0> # Rooms-Katholiek
}
?involvement a ere:BetrokkenLokaleBesturen ;
org:organization ?ws ;
ere:typebetrokkenheid ?involvementType .
VALUES ?involvementType {
<http://lblod.data.gift/concepts/86fcbbbff764f1cba4c7e10dbbae578e> # Mede-financierend
<http://lblod.data.gift/concepts/ac400cc9f135ac7873fb3e551ec738c1> # Toezichthoudend
}
?org ere:betrokkenBestuur ?involvement .
}
GRAPH <http://mu.semte.ch/graphs/administrative-unit> {
?org besluit:werkingsgebied ?scope .
}
}
;
## Province organised
INSERT {
GRAPH <http://mu.semte.ch/graphs/temp-for-worship-organizations-scope> {
?ws besluit:werkingsgebied ?scope .
}
} WHERE {
GRAPH <http://mu.semte.ch/graphs/worship-service> {
?ws a ere:BestuurVanDeEredienst ;
ere:typeEredienst ?worshipType .
VALUES ?worshipType {
<http://lblod.data.gift/concepts/9d8bd472a00bf0a5c7b7186606365a52> # Islamitisch
<http://lblod.data.gift/concepts/84bcd6896f575bae4857ff8d2764bed8> # Orthodox
}
?involvement a ere:BetrokkenLokaleBesturen ;
org:organization ?ws ;
ere:typebetrokkenheid ?involvementType .
VALUES ?involvementType {
<http://lblod.data.gift/concepts/0f845f00ee76099c89518cbaf6a7b77f> # Adviserend
}
?org ere:betrokkenBestuur ?involvement .
}
GRAPH <http://mu.semte.ch/graphs/administrative-unit> {
?org besluit:werkingsgebied ?scope .
}
}
;
# Central worship services
## Municipality organised
INSERT {
GRAPH <http://mu.semte.ch/graphs/temp-for-worship-organizations-scope> {
?ws besluit:werkingsgebied ?scope .
}
} WHERE {
GRAPH <http://mu.semte.ch/graphs/worship-service> {
?ws a ere:CentraalBestuurVanDeEredienst ;
ere:typeEredienst ?worshipType .
VALUES ?worshipType {
<http://lblod.data.gift/concepts/b13d1d623626bc1ee75c7d20bc60e3c0> # Rooms-Katholiek
}
?involvement a ere:BetrokkenLokaleBesturen ;
org:organization ?ws ;
ere:typebetrokkenheid ?involvementType .
VALUES ?involvementType {
<http://lblod.data.gift/concepts/ac400cc9f135ac7873fb3e551ec738c1> # Toezichthoudend
}
?org ere:betrokkenBestuur ?involvement .
}
GRAPH <http://mu.semte.ch/graphs/administrative-unit> {
?org besluit:werkingsgebied ?scope .
}
}
;
## Province organised
## Note: Business requested to use the location for the municipality of Ghent as
## default value. They will update it manually afterwards.
INSERT {
GRAPH <http://mu.semte.ch/graphs/temp-for-worship-organizations-scope> {
?ws besluit:werkingsgebied ?locationGhent .
}
} WHERE {
GRAPH <http://mu.semte.ch/graphs/worship-service> {
?ws a ere:CentraalBestuurVanDeEredienst ;
ere:typeEredienst ?worshipType .
VALUES ?worshipType {
<http://lblod.data.gift/concepts/9d8bd472a00bf0a5c7b7186606365a52> # Islamitisch
<http://lblod.data.gift/concepts/84bcd6896f575bae4857ff8d2764bed8> # Orthodox
}
BIND(URI("http://data.lblod.info/id/werkingsgebieden/ce94eeae827cdc5c00f3f2f4276ff628580edefb3aa5861e4669b0c5d93adc57") AS ?locationGhent)
}
}

View File

@@ -0,0 +1,24 @@
PREFIX besluit: <http://data.vlaanderen.be/ns/besluit#>
# This migration sets the scope of operation for worship organisations that have
# single, already existing, location as scope. This migration depends on
# `20250707132349-chore--extract-scopes-for-worship-organisations` being
# executed first, as it uses the data created by the migration.
INSERT {
GRAPH <http://mu.semte.ch/graphs/worship-service> {
?ws besluit:werkingsgebied ?scope .
}
} WHERE {
{
SELECT DISTINCT ?ws (count(DISTINCT ?scope) as ?count)
WHERE {
GRAPH <http://mu.semte.ch/graphs/temp-for-worship-organizations-scope> {
?ws besluit:werkingsgebied ?scope .
}
}
}
FILTER (?count = 1)
GRAPH <http://mu.semte.ch/graphs/temp-for-worship-organizations-scope> {
?ws besluit:werkingsgebied ?scope .
}
}

View File

@@ -0,0 +1,49 @@
PREFIX prov: <http://www.w3.org/ns/prov#>
PREFIX mu: <http://mu.semte.ch/vocabularies/core/>
PREFIX ext: <http://mu.semte.ch/vocabularies/ext/>
PREFIX geo: <http://www.opengis.net/ont/geosparql#>
PREFIX besluit: <http://data.vlaanderen.be/ns/besluit#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
# This migration sets the scope of operation for worship organisations that have
# multiple location as scope. It creates new aggregate locations to contain the
# already existing municipality/province level ones. This migration depends on
# `20250707132349-chore--extract-scopes-for-worship-organisations` being
# executed first, as it uses the data created by the migration.
INSERT {
GRAPH <http://mu.semte.ch/graphs/public> {
?location a prov:Location ;
mu:uuid ?locationUuid ;
rdfs:label ?scopeLabel ;
ext:werkingsgebiedNiveau """Samengesteld werkingsgebied""" .
?scope geo:sfWithin ?location .
}
GRAPH <http://mu.semte.ch/graphs/worship-service> {
?ws besluit:werkingsgebied ?location .
}
} WHERE {
{
SELECT DISTINCT ?ws (count(DISTINCT ?scope) AS ?count) (GROUP_CONCAT(?uuid," ") AS ?scopeUuids) (GROUP_CONCAT(?label,", ") AS ?scopeLabel)
WHERE {
GRAPH <http://mu.semte.ch/graphs/temp-for-worship-organizations-scope> {
?ws besluit:werkingsgebied ?scope .
}
GRAPH <http://mu.semte.ch/graphs/public> {
?scope mu:uuid ?uuid ;
rdfs:label ?label .
}
}
}
FILTER (?count > 1)
GRAPH <http://mu.semte.ch/graphs/temp-for-worship-organizations-scope> {
?ws besluit:werkingsgebied ?scope .
}
# NOTE (10/07/2025): The SPARQL specification does not specify any order for
# `GROUP_CONCAT`. But virtuoso does seem to concatenate elements always in the
# same order. Therefore, this way of generating a UUID is a bit of a hack to
# ensure that new locations that contain the same locations will receive the
# same UUUID, which results in the same location resource being inserted
# twice.
BIND (STR(SHA256(?scopeUuids)) AS ?locationUuid)
BIND (URI(CONCAT("http://data.lblod.info/id/werkingsgebieden/", ?locationUuid)) AS ?location)
}

View File

@@ -0,0 +1 @@
CLEAR GRAPH <http://mu.semte.ch/graphs/temp-for-worship-organizations-scope>

View File

@@ -0,0 +1,30 @@
DELETE {
GRAPH ?h {
?site <https://data.vlaanderen.be/ns/organisatie#bestaatUit> ?oldAddressUri .
}
} INSERT {
GRAPH ?g {
?newAddressUri a <http://www.w3.org/ns/locn#Address> ;
<http://mu.semte.ch/vocabularies/core/uuid> ?newAddressUuid ;
?p ?o .
?site <https://data.vlaanderen.be/ns/organisatie#bestaatUit> ?newAddressUri .
}
} WHERE {
GRAPH ?g {
?oldAddressUri a <http://www.w3.org/ns/locn#Address> ;
?p ?o .
FILTER (?p NOT IN (<http://mu.semte.ch/vocabularies/core/uuid>))
}
?mandatarisContact <http://www.w3.org/ns/locn#address> ?oldAddressUri .
GRAPH ?h {
?site a <http://www.w3.org/ns/org#Site>;
<https://data.vlaanderen.be/ns/organisatie#bestaatUit> ?oldAddressUri .
}
BIND(MD5(CONCAT(?oldAddressUri,"NEW_ADDRESS")) AS ?newAddressUuid) .
BIND(IRI(CONCAT("http://data.lblod.info/id/adressen/", STR(?newAddressUuid))) AS ?newAddressUri) .
}

View File

@@ -0,0 +1,33 @@
PREFIX org: <http://www.w3.org/ns/org#>
PREFIX mu: <http://mu.semte.ch/vocabularies/core/>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
DELETE {
GRAPH ?g {
?membership ?p ?o .
}
}
WHERE {
GRAPH ?g {
# Find memberships that use the general 'gerelateerd' role
?membership a org:Membership ;
org:role <http://data.lblod.info/id/rollen/4ec7d5c39bdc4e84b4174379b9e22ad8> ;
org:member ?orgMember ;
org:organization ?organization .
# Only delete if there's a specific role for the inverse membership
FILTER EXISTS {
?specific_membership a org:Membership ;
org:member ?organization ;
org:organization ?orgMember ;
org:role ?specificRole .
VALUES ?specificRole {
<http://data.lblod.info/id/rollen/2152eb830b1143bfb97a7dd9596d6c63> # participant
<http://data.lblod.info/id/rollen/73d5e1cf250d42fab15926771f07505a> # stichtend lid
}
}
?membership ?p ?o .
}
}

View File

@@ -0,0 +1,18 @@
DELETE {
GRAPH <http://mu.semte.ch/graphs/administrative-unit> {
?address ?p ?o .
}
} INSERT {
GRAPH <http://mu.semte.ch/graphs/worship-service> {
?address ?p ?o .
}
} WHERE {
GRAPH <http://mu.semte.ch/graphs/worship-service> {
?contactPoint a <http://schema.org/ContactPoint> ;
<http://www.w3.org/ns/locn#address> ?address .
}
GRAPH <http://mu.semte.ch/graphs/administrative-unit> {
?address ?p ?o .
}
}

View File

@@ -0,0 +1,40 @@
PREFIX org: <http://www.w3.org/ns/org#>
PREFIX mu: <http://mu.semte.ch/vocabularies/core/>
DELETE {
GRAPH <http://mu.semte.ch/graphs/administrative-unit> {
?membership org:organization ?ocmw ;
org:member ?municipality .
}
}
INSERT {
GRAPH <http://mu.semte.ch/graphs/administrative-unit> {
?membership org:organization ?municipality ;
org:member ?ocmw .
}
}
WHERE {
GRAPH <http://mu.semte.ch/graphs/administrative-unit> {
?membership a org:Membership ;
org:organization ?ocmw ;
org:member ?municipality ;
org:role <http://data.lblod.info/id/rollen/4ec7d5c39bdc4e84b4174379b9e22ad8> .
}
GRAPH ?graphMunicipality {
?municipality org:classification <http://data.vlaanderen.be/id/concept/BestuurseenheidClassificatieCode/5ab0e9b8a3b2ca7c5e000001> .
}
GRAPH ?graphOCMW {
?ocmw org:classification <http://data.vlaanderen.be/id/concept/BestuurseenheidClassificatieCode/5ab0e9b8a3b2ca7c5e000002> .
}
FILTER NOT EXISTS {
GRAPH <http://mu.semte.ch/graphs/administrative-unit> {
?correctMembership a org:Membership ;
org:organization ?municipality ;
org:member ?ocmw ;
org:role <http://data.lblod.info/id/rollen/4ec7d5c39bdc4e84b4174379b9e22ad8> .
}
}
}

View File

@@ -0,0 +1,33 @@
PREFIX org: <http://www.w3.org/ns/org#>
PREFIX mu: <http://mu.semte.ch/vocabularies/core/>
DELETE {
GRAPH <http://mu.semte.ch/graphs/administrative-unit> {
?duplicateMembership ?p ?o .
}
} WHERE {
GRAPH <http://mu.semte.ch/graphs/administrative-unit> {
?duplicateMembership a org:Membership ;
org:organization ?ocmw ;
org:member ?municipality ;
org:role <http://data.lblod.info/id/rollen/4ec7d5c39bdc4e84b4174379b9e22ad8> ;
?p ?o .
# Find the other memberships with swapped organizations
?correctMembership a org:Membership ;
org:organization ?municipality ;
org:member ?ocmw ;
org:role <http://data.lblod.info/id/rollen/4ec7d5c39bdc4e84b4174379b9e22ad8> .
}
GRAPH <http://mu.semte.ch/graphs/shared> {
?municipality org:classification ?municipalityClassification .
}
GRAPH <http://mu.semte.ch/graphs/administrative-unit> {
?ocmw org:classification ?ocmwClassification .
}
FILTER(?municipalityClassification = <http://data.vlaanderen.be/id/concept/BestuurseenheidClassificatieCode/5ab0e9b8a3b2ca7c5e000001>)
FILTER(?ocmwClassification = <http://data.vlaanderen.be/id/concept/BestuurseenheidClassificatieCode/5ab0e9b8a3b2ca7c5e000002>)
}

View File

@@ -0,0 +1,28 @@
DELETE {
GRAPH ?g {
?s ?p ?date .
}
}
INSERT {
GRAPH ?g {
?s ?p ?dateTime .
}
}
WHERE {
VALUES ?g {
<http://mu.semte.ch/graphs/administrative-unit>
<http://mu.semte.ch/graphs/worship-service>
}
GRAPH ?g {
?s a <http://mu.semte.ch/vocabularies/ext/KboOrganisatie> ;
?p ?date .
VALUES ?p {
<http://purl.org/dc/terms/modified>
<http://mu.semte.ch/vocabularies/ext/startDate>
}
BIND(STRDT(CONCAT(STR(?date), "T02:00:00"), xsd:dateTime) AS ?dateTime)
}
}

View File

@@ -945,7 +945,7 @@
"located-within": {
"predicate": "geo:sfWithin",
"target": "locations",
"cardinality": "one"
"cardinality": "many"
},
"locations": {
"predicate": "geo:sfWithin",

View File

@@ -74,6 +74,8 @@ services:
restart: "no"
construct-organization-relationships:
restart: "no"
scope-of-operation:
restart: "no"
mandatarissen-consumer:
restart: "no"
leidinggevenden-consumer:

View File

@@ -194,7 +194,7 @@ services:
restart: always
logging: *default-logging
frontend:
image: lblod/frontend-organization-portal:1.33.0
image: lblod/frontend-organization-portal:1.34.0
volumes:
- ./config/frontend/add-x-frame-options-header.conf:/config/add-x-frame-options.conf
environment:
@@ -285,6 +285,14 @@ services:
- "logging=true"
restart: always
logging: *default-logging
scope-of-operation:
image: lblod/scope-of-operation-service:0.1.1
links:
- db:database
labels:
- "logging=true"
restart: always
logging: *default-logging
report-generation:
image: lblod/loket-report-generation-service:0.8.3
environment:
@@ -310,7 +318,7 @@ services:
restart: always
logging: *default-logging
kbo-data-sync:
image: lblod/sync-wegwijs-organization-service:2.0.3
image: lblod/sync-wegwijs-organization-service:2.0.4
links:
- db:database
labels:

View File

@@ -17,6 +17,22 @@
"app": "/app/"
}
},
{
"documentation": {
"command": "correct-location-labels",
"description": "generate migrations to correct the labels of aggregated locations",
"arguments": []
},
"environment": {
"image": "nvdk/ruby-semantic-works-cli",
"interactive": true,
"script": "correct-location-labels/run.rb",
"join_networks": true
},
"mounts": {
"app": "/app/"
}
},
{
"documentation": {
"command": "mu-search-delta",

View File

@@ -0,0 +1,106 @@
#!/usr/bin/env ruby
require 'date'
require 'rdf/turtle'
require 'fileutils'
$stdout.sync = true
ENV['LOG_SPARQL_ALL']='false'
ENV['MU_SPARQL_ENDPOINT']='http://triplestore:8890/sparql'
ENV['MU_SPARQL_TIMEOUT']='180'
require 'mu/auth-sudo'
def ensure_dir(path)
unless Dir.exist?(path)
FileUtils.mkdir_p(path)
end
end
def sparql_escape_uri(value)
'<' + value.to_s.gsub(/[\\"<>]/) { |s| '\\' + s } + '>'
end
def sparql_escape_string(str)
'"""' + str.gsub(/[\\"]/) { |s| '\\' + s } + '"""'
end
def get_locations()
query = <<~EOF
PREFIX prov: <http://www.w3.org/ns/prov#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX ext: <http://mu.semte.ch/vocabularies/ext/>
SELECT DISTINCT ?location ?label
WHERE {
GRAPH <http://mu.semte.ch/graphs/public> {
?location a prov:Location ;
rdfs:label ?label ;
ext:werkingsgebiedNiveau """Samengesteld werkingsgebied""" .
}
}
EOF
Mu::AuthSudo.query(query)
end
def sort_literal(literal)
literal
.humanize
.split(", ")
.sort
.join(", ")
end
# Create output directory
timestamp=`date +%Y%0m%0d%0H%0M%0S`.strip.to_i
output_dir = "/app/config/migrations/local/2025/#{timestamp}-correct-labels-aggregate-locations/"
ensure_dir(output_dir)
# Generate SPARQL migration to remove existing labels
path = File.join(output_dir, "#{timestamp}-remove-labels-aggregate-locations.sparql")
File.open(path, 'w') do |file|
file.write <<EOF
PREFIX prov: <http://www.w3.org/ns/prov#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX ext: <http://mu.semte.ch/vocabularies/ext/>
DELETE {
GRAPH <http://mu.semte.ch/graphs/public> {
?location rdfs:label ?label
}
} WHERE {
GRAPH <http://mu.semte.ch/graphs/public> {
?location a prov:Location ;
rdfs:label ?label ;
ext:werkingsgebiedNiveau """Samengesteld werkingsgebied""" .
}
}
EOF
end
# Generate TTL migration to insert alphabetically sorted labels
timestamp += 1
filename = "#{timestamp}-insert-labels-aggregate-locations"
path = File.join(output_dir, "#{filename}.graph")
File.open(path, 'w') do |file|
file.write <<EOF
http://mu.semte.ch/graphs/public
EOF
end
path = File.join(output_dir, "#{filename}.ttl")
File.open(path, 'w') do |file|
file.write <<EOF
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
EOF
end
locations = get_locations()
locations.each do |location|
File.open(path, 'a') do |file|
file.write <<EOF
#{sparql_escape_uri(location[:location])} rdfs:label "#{(sort_literal(location[:label]))}" .
EOF
end
end