Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support for delete signatures #101

Merged
merged 9 commits into from
Jun 8, 2023
227 changes: 227 additions & 0 deletions models/signed-resource.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
// @ts-ignore
import { prefixMap } from '../support/prefixes';
import { query, sparqlEscapeUri } from 'mu';

export default class SignedResource {
static async findURI(uri) {
const queryString = `
${prefixMap.get('mu').toSparqlString()}
${prefixMap.get('sign').toSparqlString()}
${prefixMap.get('dct').toSparqlString()}
${prefixMap.get('publicationStatus').toSparqlString()}
${prefixMap.get('ext').toSparqlString()}
SELECT DISTINCT *
WHERE {
BIND(${sparqlEscapeUri(uri)} as ?uri)
?uri a sign:SignedResource;
mu:uuid ?uuid;
sign:text ?html;
sign:hashValue ?hashValue;
sign:hashAlgorithm ?hashAlgorithm;
dct:created ?created;
sign:signatoryRoles ?signatoryRole.

?uri sign:status ?blockchainStatus;
sign:signatory ?signatory.

?blockchainStatus mu:uuid ?blockchainStatusUuid.
Copy link
Member

@nvdk nvdk Jun 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd consider blockchainStatus and uuid legacy and no longer required. little value in adding them as this hasn't been used in over 4 years.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in the interest of limiting scope, OK to leave it for now and open a separate pr to clean up obsolete stuff?

?signatory mu:uuid ?signatoryUuid.

OPTIONAL { ?uri ext:deleted ?deleted. }
OPTIONAL {
?uri ext:signsAgenda ?agenda.
?agenda mu:uuid ?agendaUuid.
}
OPTIONAL {
?uri ext:signsBesluitenlijst ?versionedBesluitenLijst.
?versionedBesluitenLijst mu:uuid ?versionedBesluitenLijstUuid.
}
OPTIONAL {
?uri ext:signsNotulen ?versionedNotulen.
?versionedNotulen mu:uuid ?versionedNotulenUuid.
}
OPTIONAL {
?uri ext:signsBehandeling ?versionedBehandeling.
?versionedBehandeling mu:uuid ?versionedBehandelingUuid.
}
} ORDER BY DESC (?created)
`;
try {
const result = await query(queryString);
if (result.results.bindings.length === 1) {
const sr = SignedResource.fromBinding(result.results.bindings[0]);
return sr;
} else if (result.results.bindings.length > 1) {
console.warn(
`Found ${result.results.bindings.length} SignedResources for one URI, this is unexpected. Returning the newest one`
);
// console.warn("bindings:", result.results.bindings);
const sr = SignedResource.fromBinding(result.results.bindings[0]);
return sr;
} else {
throw `did not find signed resource with uri ${uri}`;
}
} catch (e) {
console.error(e);
throw `failed to retrieve signed resource with uri ${uri}`;
}
}

static fromBinding({
uri,
uuid,
html,
hashValue,
hashAlgorithm,
created,
signatoryRole,
deleted,
blockchainStatus,
signatory,
blockchainStatusUuid,
signatoryUuid,
agenda,
versionedBesluitenLijst,
versionedNotulen,
versionedBehandeling,
agendaUuid,
versionedBesluitenLijstUuid,
versionedNotulenUuid,
versionedBehandelingUuid,
}) {
return new SignedResource({
uri: uri.value,
uuid: uuid.value,
html: html.value,
hashValue: hashValue.value,
hashAlgorithm: hashAlgorithm.value,
created: created.value,
signatoryRole: signatoryRole.value,
deleted: deleted?.value,
blockchainStatus: blockchainStatus.value,
signatory: signatory.value,
blockchainStatusUuid: blockchainStatusUuid.value,
signatoryUuid: signatoryUuid.value,
agenda: agenda?.value,
versionedBesluitenLijst: versionedBesluitenLijst?.value,
versionedNotulen: versionedNotulen?.value,
versionedBehandeling: versionedBehandeling?.value,
agendaUuid: agendaUuid?.value,
versionedBesluitenLijstUuid: versionedBesluitenLijstUuid?.value,
versionedNotulenUuid: versionedNotulenUuid?.value,
versionedBehandelingUuid: versionedBehandelingUuid?.value,
});
}

constructor({
uri,
uuid,
html,
hashValue,
hashAlgorithm,
created,
signatoryRole,
deleted,
blockchainStatus,
signatory,
blockchainStatusUuid,
signatoryUuid,
agenda,
versionedBesluitenLijst,
versionedNotulen,
versionedBehandeling,
agendaUuid,
versionedBesluitenLijstUuid,
versionedNotulenUuid,
versionedBehandelingUuid,
}) {
this.uuid = uuid;
this.uri = uri;
this.html = html;
this.signatory = signatory;
this.created = created;
this.signatoryRole = signatoryRole;
this.hashAlgorithm = hashAlgorithm;
this.hashValue = hashValue;
this.deleted = deleted;
this.blockchainStatus = blockchainStatus;
this.blockchainStatusUuid = blockchainStatusUuid;
this.signatoryUuid = signatoryUuid;
this.agenda = agenda;
this.versionedBesluitenLijst = versionedBesluitenLijst;
this.versionedNotulen = versionedNotulen;
this.versionedBehandeling = versionedBehandeling;
this.agendaUuid = agendaUuid;
this.versionedBesluitenLijstUuid = versionedBesluitenLijstUuid;
this.versionedNotulenUuid = versionedNotulenUuid;
this.versionedBehandelingUuid = versionedBehandelingUuid;
}

/**
* Convert into a json-api compliant model according to the mu-cl-resource config
*/
toMuResourceModel() {
// required relationships
const relationships = {
'blockchain-status': {
data: {
type: 'blockchain-statuses',
id: this.blockchainStatusUuid,
},
},
gebruiker: {
data: { type: 'gebruikers', id: this.signatoryUuid },
},
};
// optional relationships
if (this.agendaUuid) {
relationships.agenda = {
data: {
type: 'agendas',
id: this.agendaUuid,
},
};
}
if (this.versionedBesluitenLijstUuid) {
relationships['versioned-besluiten-lijst'] = {
data: {
type: 'versioned-besluiten-lijsten',
id: this.versionedBesluitenLijstUuid,
},
};
}
if (this.versionedNotulenUuid) {
relationships['versioned-notulen'] = {
data: {
type: 'versioned-notulen',
id: this.versionedNotulenUuid,
},
};
}
if (this.versionedBehandelingUuid) {
relationships['versioned-behandeling'] = {
data: {
type: 'versioned-behandelingen',
id: this.versionedBehandelingUuid,
},
};
}
return {
data: {
id: this.uuid,
type: 'signed-resources',
attributes: {
uri: this.uri,
content: this.html,
'hash-value': this.hashValue,
'created-on': this.created,
deleted: this.deleted,
},
relationships,
links: {
self: '/signed-resources/' + this.uuid,
},
},
};
}
}
48 changes: 48 additions & 0 deletions models/treatment.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,53 @@ export default class Treatment {
}
}

static async findUri(uri) {
const queryString = `
${prefixMap.get('besluit').toSparqlString()}
${prefixMap.get('dct').toSparqlString()}
${prefixMap.get('schema').toSparqlString()}
${prefixMap.get('mu').toSparqlString()}
${prefixMap.get('skos').toSparqlString()}
${prefixMap.get('ext').toSparqlString()}
${prefixMap.get('pav').toSparqlString()}
SELECT * WHERE {
BIND(${sparqlEscapeUri(uri)} as ?uri)
?meeting a besluit:Zitting;
besluit:behandelt ?agendapoint.
?agendapoint schema:position ?position.
?uri a besluit:BehandelingVanAgendapunt;
mu:uuid ?uuid;
dct:subject ?agendapoint;
besluit:openbaar ?isPublic;
ext:hasDocumentContainer ?container.
?container pav:hasCurrentVersion ?editorDocument.
?editorDocument <http://mu.semte.ch/vocabularies/core/uuid> ?editorDocumentUuid.
OPTIONAL {
?uri besluit:gebeurtNa ?executedAfter.
}
OPTIONAL {
?uri besluit:heeftVoorzitter ?chairman.
}
OPTIONAL {
?uri besluit:heeftSecretaris ?secretary.
}
}
`;
try {
const result = await query(queryString);
if (result.results.bindings.length === 1) {
const treatment = Treatment.fromBinding(result.results.bindings[0]);
await treatment.getAttachments();
return treatment;
} else {
throw `did not find treatment with uri ${uri}`;
}
} catch (e) {
console.error(e);
throw `failed to retrieve treatment with uri ${uri}`;
}
}

static async find(treatmentUuid) {
const queryString = `
${prefixMap.get('besluit').toSparqlString()}
Expand Down Expand Up @@ -155,6 +202,7 @@ export default class Treatment {
this.secretary = secretary;
this.documentContainerUri = documentContainerUri;
}

async getAttachments() {
const queryString = `
${prefixMap.get('ext').toSparqlString()}
Expand Down
8 changes: 5 additions & 3 deletions models/versioned-agenda.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ export default class VersionedAgenda {
WHERE {
BIND(${sparqlEscapeString(agendaType)} as ?agendaType)
?uri
a bv:Agenda;
ext:renderedContent ?html;
bv:isAgendaVoor ?meeting;
a bv:Agenda;
ext:renderedContent ?html;
bv:isAgendaVoor ?meeting;
bv:agendaType ?agendaType.
?meeting mu:uuid ${sparqlEscapeString(meetingUuid)}.
FILTER NOT EXISTS { ?uri ext:deleted "true"^^<http://mu.semte.ch/vocabularies/typed-literals/boolean> }
} LIMIT 1
`);
if (result.results.bindings.length === 0) {
Expand Down Expand Up @@ -51,6 +52,7 @@ export default class VersionedAgenda {
ext:renderedContent ${hackedSparqlEscapeString(html)};
bv:isAgendaVoor ${sparqlEscapeUri(meeting)};
mu:uuid ${sparqlEscapeString(agendaUuid)};
ext:deleted "false"^^<http://mu.semte.ch/vocabularies/typed-literals/boolean>;
bv:agendaType ${sparqlEscapeString(agendaType)}.
}`);
await update(`
Expand Down
53 changes: 50 additions & 3 deletions models/versioned-behandeling.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,53 @@
// @ts-ignore
import { uuid, query, sparqlEscapeString, update, sparqlEscapeUri } from 'mu';
import { query, sparqlEscapeString, sparqlEscapeUri, update, uuid } from 'mu';
import { hackedSparqlEscapeString } from '../support/pre-importer';
import { prefixMap } from '../support/prefixes';

// using the english name here, but the model is in dutch
export default class VersionedExtract {
static async find(uuid) {
const queryString = `
${prefixMap.get('besluit').toSparqlString()}
${prefixMap.get('dct').toSparqlString()}
${prefixMap.get('schema').toSparqlString()}
${prefixMap.get('mu').toSparqlString()}
${prefixMap.get('skos').toSparqlString()}
${prefixMap.get('ext').toSparqlString()}
${prefixMap.get('pav').toSparqlString()}
SELECT * WHERE {
BIND(${sparqlEscapeString(uuid)} as ?uuid)

?uri a ext:VersionedBehandeling ;
mu:uuid ?uuid ;
ext:behandeling ?treatment;
ext:content ?html.
OPTIONAL {
?uri ext:stateString ?state .
}
FILTER NOT EXISTS { ?uri ext:deleted "true"^^<http://mu.semte.ch/vocabularies/typed-literals/boolean> }

}
`;
try {
const result = await query(queryString);
const bindings = result.results.bindings;
if (bindings.length > 0) {
const binding = bindings[0];
return new VersionedExtract({
uri: binding.uri.value,
html: binding.html.value,
treatment: binding.treatment.value,
state: binding.state?.value,
});
} else {
throw `did not find versionedTreatment with uuid ${uuid}`;
}
} catch (e) {
console.error(e);
throw `failed to retrieve versionedTreatment with uuid ${uuid}`;
}
}

static async query({ treatmentUuid }) {
const r = await query(`
PREFIX ext: <http://mu.semte.ch/vocabularies/ext/>
Expand All @@ -18,6 +62,7 @@ export default class VersionedExtract {
ext:content ?html;
ext:behandeling ?treatment.
?treatment mu:uuid ${sparqlEscapeString(treatmentUuid)}.
FILTER NOT EXISTS { ?uri ext:deleted "true"^^<http://mu.semte.ch/vocabularies/typed-literals/boolean> }
}
`);
const bindings = r.results.bindings;
Expand Down Expand Up @@ -47,7 +92,8 @@ export default class VersionedExtract {
a ext:VersionedBehandeling;
ext:content ${hackedSparqlEscapeString(html)};
mu:uuid ${sparqlEscapeString(versionedExtractUuid)};
ext:behandeling ${sparqlEscapeUri(treatment.uri)}.
ext:behandeling ${sparqlEscapeUri(treatment.uri)};
ext:deleted "false"^^<http://mu.semte.ch/vocabularies/typed-literals/boolean>.
${sparqlEscapeUri(
meeting.uri
)} ext:hasVersionedBehandeling ${sparqlEscapeUri(versionedExtractUri)}.
Expand All @@ -59,9 +105,10 @@ export default class VersionedExtract {
});
}

constructor({ uri, html = null, treatment }) {
constructor({ uri, html = null, treatment, state = null }) {
this.uri = uri;
this.html = html;
this.treatment = treatment;
this.state = state;
}
}
Loading