UNPKG

@dasch-swiss/dsp-js

Version:
534 lines 26.6 kB
import { catchError, map, mergeMap } from 'rxjs'; import { DataError } from '../../../models/data-error'; import { Constants } from '../../../models/v2/Constants'; import { OntologyConversionUtil } from '../../../models/v2/ontologies/OntologyConversionUtil'; import { CreateResourceClassPayload, } from '../../../models/v2/ontologies/create/create-resource-class'; import { CreateResourcePropertyPayload, } from '../../../models/v2/ontologies/create/create-resource-property'; import { DeleteOntologyResponse } from '../../../models/v2/ontologies/delete/delete-ontology-response'; import { OntologyMetadata } from '../../../models/v2/ontologies/ontology-metadata'; import { CanDoResponse } from '../../../models/v2/ontologies/read/can-do-response'; import { CardinalityUtil } from '../../../models/v2/resources/cardinality-util'; import { Endpoint } from '../../endpoint'; const jsonld = require('jsonld/dist/jsonld.js'); /** * Handles requests to the ontologies route of the Knora API. * * @category Endpoint V2 */ export class OntologiesEndpointV2 extends Endpoint { /** * Requests metadata about all ontologies from Knora. */ getOntologiesMetadata() { return this.httpGet('/metadata').pipe(mergeMap(ajaxResponse => { // TODO: @rosenth Adapt context object // TODO: adapt getOntologyIriFromEntityIri return jsonld.compact(ajaxResponse.response, {}); }), map((jsonldobj) => { return OntologyConversionUtil.convertOntologiesList(jsonldobj, this.jsonConvert); }), catchError(error => { return this.handleError(error); })); } /** * Requests an ontology from Knora. * * @param ontologyIri the IRI of the ontology to be requested. * @param allLanguages gets labels and comments in all languages, if set to true. */ getOntology(ontologyIri, allLanguages = false) { let allLangSegment = ''; if (allLanguages) { allLangSegment = '?allLanguages=true'; } // TODO: Do not hard-code the URL and http call params, generate this from Knora return this.httpGet(`/allentities/${encodeURIComponent(ontologyIri)}${allLangSegment}`).pipe(mergeMap(ajaxResponse => { // TODO: @rosenth Adapt context object // TODO: adapt getOntologyIriFromEntityIri return jsonld.compact(ajaxResponse.response, {}); }), map((jsonldobj) => { return OntologyConversionUtil.convertOntology(jsonldobj, this.jsonConvert, this.knoraApiConfig, allLanguages); }), catchError(error => { return this.handleError(error); })); } /** * Requests metadata about all ontologies from a specific project. * * @param projectIri the IRI of the project. */ getOntologiesByProjectIri(projectIri) { return this.httpGet(`/metadata/${encodeURIComponent(projectIri)}`).pipe(mergeMap(ajaxResponse => { // TODO: @rosenth Adapt context object // TODO: adapt getOntologyIriFromEntityIri return jsonld.compact(ajaxResponse.response, {}); }), map((jsonldobj) => { return OntologyConversionUtil.convertOntologiesList(jsonldobj, this.jsonConvert); }), catchError(error => { return this.handleError(error); })); } /** * Creates a new ontology. * * @param ontology The ontology to be created */ createOntology(ontology) { const onto = this.jsonConvert.serializeObject(ontology); return this.httpPost('', onto).pipe(mergeMap(ajaxResponse => { // TODO: @rosenth Adapt context object // TODO: adapt getOntologyIriFromEntityIri return jsonld.compact(ajaxResponse.response, {}); }), map((jsonldobj) => { return this.jsonConvert.deserializeObject(jsonldobj, OntologyMetadata); }), catchError(error => { return this.handleError(error); })); } /** * Checks whether an existing ontology can be deleted. * * @param ontologyIri the Iri of the ontology to be checked. */ canDeleteOntology(ontologyIri) { return this.httpGet(`/candeleteontology/${encodeURIComponent(ontologyIri)}`).pipe(mergeMap(ajaxResponse => { // TODO: @rosenth Adapt context object // TODO: adapt getOntologyIriFromEntityIri return jsonld.compact(ajaxResponse.response, {}); }), map((jsonldobj) => { return this.jsonConvert.deserializeObject(jsonldobj, CanDoResponse); }), catchError(error => { return this.handleError(error); })); } /** * Deletes an ontology. * * @param ontology the ontology to be deleted. */ deleteOntology(ontology) { const path = `/${encodeURIComponent(ontology.id)}?lastModificationDate=${encodeURIComponent(ontology.lastModificationDate)}`; return this.httpDelete(path).pipe(mergeMap(ajaxResponse => { // TODO: @rosenth Adapt context object // TODO: adapt getOntologyIriFromEntityIri return jsonld.compact(ajaxResponse.response, {}); }), map(jsonldobj => { return this.jsonConvert.deserializeObject(jsonldobj, DeleteOntologyResponse); }), catchError(error => this.handleError(error))); } /** * Updates the metadata of an ontology. * * @param ontologyMetadata The ontology metadata to be updated */ updateOntology(ontologyMetadata) { // label and comment cannot both be undefined if (ontologyMetadata.label === undefined && ontologyMetadata.comment === undefined) { throw new Error('Label and comment cannot both be undefined. At least one must be defined.'); } // label cannot be an empty string if (ontologyMetadata.label !== undefined && ontologyMetadata.label.trim() === '') { throw new Error('Label cannot be an empty string.'); } // comment can be an empty string but we must make an additional API request to remove the comment if (ontologyMetadata.comment !== undefined && ontologyMetadata.comment.trim() === '') { // set the comment to undefined because the API will not accept an empty string ontologyMetadata.comment = undefined; // request to remove the comment return this.deleteOntologyComment(ontologyMetadata).pipe(mergeMap((res) => { // update the lastModificationDate since the DELETE request changed it if (res.lastModificationDate) { ontologyMetadata.lastModificationDate = res.lastModificationDate; } // update the metadata, which in this case is only the label return this.updateOntologyMetadata(ontologyMetadata); })); } else { // if label and/or comment are defined and not empty strings, make the API request to update the metadata return this.updateOntologyMetadata(ontologyMetadata); } } /** * Removes the comment from the metadata of an ontology. * * @param ontologyMetadata The ontology metadata to be updated */ deleteOntologyComment(ontologyMetadata) { if (ontologyMetadata.id === undefined || ontologyMetadata.lastModificationDate === undefined) { throw new Error('Missing IRI or lastModificationDate'); } return this.httpDelete(`/comment/${encodeURIComponent(ontologyMetadata.id)}?lastModificationDate=${encodeURIComponent(ontologyMetadata.lastModificationDate)}`).pipe(mergeMap(ajaxResponse => { // TODO: @rosenth Adapt context object // TODO: adapt getOntologyIriFromEntityIri return jsonld.compact(ajaxResponse.response, {}); }), map((jsonldobj) => { return this.jsonConvert.deserializeObject(jsonldobj, OntologyMetadata); })); } /** * The PUT request for updating the metadata of an ontology. * * @param ontologyMetadata The ontology metadata to be updated */ updateOntologyMetadata(ontologyMetadata) { const onto = this.jsonConvert.serializeObject(ontologyMetadata); return this.httpPut('/metadata', onto).pipe(mergeMap(ajaxResponse => { // TODO: @rosenth Adapt context object // TODO: adapt getOntologyIriFromEntityIri return jsonld.compact(ajaxResponse.response, {}); }), map((jsonldobj) => { return this.jsonConvert.deserializeObject(jsonldobj, OntologyMetadata); }), catchError(error => { return this.handleError(error); })); } /** * Creates a resource class without cardinalities. * * @param resourceClass The resource class to be created. */ createResourceClass(resourceClass) { const resClassPay = new CreateResourceClassPayload(); resClassPay.id = resourceClass.id + Constants.HashDelimiter + resourceClass.entity.name; resClassPay.label = resourceClass.entity.label; resClassPay.comment = resourceClass.entity.comment?.length ? resourceClass.entity.comment : undefined; resClassPay.subClassOf = resourceClass.entity.subClassOf; resClassPay.type = Constants.Class; const ontoPayload = this.jsonConvert.serializeObject(resourceClass); ontoPayload['@graph'] = [this.jsonConvert.serializeObject(resClassPay)]; return this.httpPost('/classes', ontoPayload).pipe(mergeMap(ajaxResponse => { // TODO: @rosenth Adapt context object // TODO: adapt getOntologyIriFromEntityIri return jsonld.compact(ajaxResponse.response, {}); }), map((jsonldobj) => { return OntologyConversionUtil.convertResourceClassResponse(jsonldobj, this.jsonConvert); }), catchError(error => { return this.handleError(error); })); } /** * Updates a resource class's label or comment. * * @param updateResourceClass the new label or comment. */ updateResourceClass(updateResourceClass) { const ontoPayload = this.jsonConvert.serializeObject(updateResourceClass); ontoPayload['@graph'] = [this.jsonConvert.serializeObject(updateResourceClass.entity)]; return this.httpPut('/classes', ontoPayload).pipe(mergeMap(ajaxResponse => { // TODO: @rosenth Adapt context object // TODO: adapt getOntologyIriFromEntityIri return jsonld.compact(ajaxResponse.response, {}); }), map((jsonldobj) => { return OntologyConversionUtil.convertResourceClassResponse(jsonldobj, this.jsonConvert); }), catchError(error => { return this.handleError(error); })); } /** * Updates a property's label or comment. * * @param updateProperty the new label or comment. */ updateResourceProperty(updateProperty) { const ontoPayload = this.jsonConvert.serializeObject(updateProperty); ontoPayload['@graph'] = [this.jsonConvert.serializeObject(updateProperty.entity)]; return this.httpPut('/properties', ontoPayload).pipe(mergeMap(ajaxResponse => { // TODO: @rosenth Adapt context object // TODO: adapt getOntologyIriFromEntityIri return jsonld.compact(ajaxResponse.response, {}); }), map((jsonldobj) => { return OntologyConversionUtil.convertResourcePropertyResponse(jsonldobj, this.jsonConvert); }), catchError(error => { return this.handleError(error); })); } /** * Checks whether an existing resource class can be deleted. * * @param resourceClassIri the iri of the resource class to be checked. */ canDeleteResourceClass(resourceClassIri) { return this.httpGet(`/candeleteclass/${encodeURIComponent(resourceClassIri)}`).pipe(mergeMap(ajaxResponse => { // TODO: @rosenth Adapt context object // TODO: adapt getOntologyIriFromEntityIri return jsonld.compact(ajaxResponse.response, {}); }), map((jsonldobj) => { return this.jsonConvert.deserializeObject(jsonldobj, CanDoResponse); }), catchError(error => { return this.handleError(error); })); } /** * Deletes a resource class. * * @param deleteResourceClass with class IRI. */ deleteResourceClass(deleteResourceClass) { const path = `/classes/${encodeURIComponent(deleteResourceClass.id)}?lastModificationDate=${encodeURIComponent(deleteResourceClass.lastModificationDate)}`; return this.httpDelete(path).pipe(mergeMap(ajaxResponse => { // TODO: @rosenth Adapt context object // TODO: adapt getOntologyIriFromEntityIri return jsonld.compact(ajaxResponse.response, {}); }), map(jsonldobj => { return this.jsonConvert.deserializeObject(jsonldobj, OntologyMetadata); }), catchError(error => this.handleError(error))); } /** * Deletes a resource class's comment * * @param deleteResourceClassComment with class IRI and lastModificationDate */ deleteResourceClassComment(deleteResourceClassComment) { const path = `/classes/comment/${encodeURIComponent(deleteResourceClassComment.id)}?lastModificationDate=${encodeURIComponent(deleteResourceClassComment.lastModificationDate)}`; return this.httpDelete(path).pipe(mergeMap(ajaxResponse => { return jsonld.compact(ajaxResponse.response, {}); }), map((jsonldobj) => { return OntologyConversionUtil.convertResourceClassResponse(jsonldobj, this.jsonConvert); }), catchError(error => this.handleError(error))); } /** * Creates a resource property. * * @param resourceProperties the resource property to be created. */ createResourceProperty(resourceProperties) { const resPropPay = new CreateResourcePropertyPayload(); resPropPay.id = resourceProperties.id + Constants.HashDelimiter + resourceProperties.entity.name; resPropPay.label = resourceProperties.entity.label; resPropPay.comment = resourceProperties.entity.comment?.length ? resourceProperties.entity.comment : undefined; resPropPay.subPropertyOf = resourceProperties.entity.subPropertyOf; resPropPay.subjectType = resourceProperties.entity.subjectType; resPropPay.objectType = resourceProperties.entity.objectType; if (resourceProperties.entity.guiElement) { resPropPay.guiElement = resourceProperties.entity.guiElement; } if (resourceProperties.entity.guiAttributes) { resPropPay.guiAttributes = resourceProperties.entity.guiAttributes; } const ontoPayload = this.jsonConvert.serializeObject(resourceProperties); ontoPayload['@graph'] = [this.jsonConvert.serializeObject(resPropPay)]; return this.httpPost('/properties', ontoPayload).pipe(mergeMap(ajaxResponse => { // TODO: @rosenth Adapt context object // TODO: adapt getOntologyIriFromEntityIri return jsonld.compact(ajaxResponse.response, {}); }), map((jsonldobj) => { return OntologyConversionUtil.convertResourcePropertyResponse(jsonldobj, this.jsonConvert); }), catchError(error => { return this.handleError(error); })); } /** * Updates the GUI element and/or the GUI attributes of a property * @param replaceGuiElement */ replaceGuiElementOfProperty(replaceGuiElement) { const ontoPayload = this.jsonConvert.serializeObject(replaceGuiElement); ontoPayload['@graph'] = [this.jsonConvert.serializeObject(replaceGuiElement.entity)]; return this.httpPut('/properties/guielement', ontoPayload).pipe(mergeMap(ajaxResponse => { return jsonld.compact(ajaxResponse.response, {}); }), map((jsonldobj) => { return OntologyConversionUtil.convertResourcePropertyResponse(jsonldobj, this.jsonConvert); }), catchError(error => { return this.handleError(error); })); } /** * Checks whether an existing property can be deleted. * * @param propertyIri the iri of the property to be checked. */ canDeleteResourceProperty(propertyIri) { return this.httpGet(`/candeleteproperty/${encodeURIComponent(propertyIri)}`).pipe(mergeMap(ajaxResponse => { // TODO: @rosenth Adapt context object // TODO: adapt getOntologyIriFromEntityIri return jsonld.compact(ajaxResponse.response, {}); }), map((jsonldobj) => { return this.jsonConvert.deserializeObject(jsonldobj, CanDoResponse); }), catchError(error => { return this.handleError(error); })); } /** * Deletes a resource property. * * @param deleteResourceProperty with property IRI. */ deleteResourceProperty(deleteResourceProperty) { const path = `/properties/${encodeURIComponent(deleteResourceProperty.id)}?lastModificationDate=${encodeURIComponent(deleteResourceProperty.lastModificationDate)}`; return this.httpDelete(path).pipe(mergeMap(ajaxResponse => { // TODO: @rosenth Adapt context object // TODO: adapt getOntologyIriFromEntityIri return jsonld.compact(ajaxResponse.response, {}); }), map(jsonldobj => { return this.jsonConvert.deserializeObject(jsonldobj, OntologyMetadata); }), catchError(error => this.handleError(error))); } /** * Deletes a resource property's comment * * @param deleteResourcePropertyComment with property IRI and lastModificationDate */ deleteResourcePropertyComment(deleteResourcePropertyComment) { const path = `/properties/comment/${encodeURIComponent(deleteResourcePropertyComment.id)}?lastModificationDate=${encodeURIComponent(deleteResourcePropertyComment.lastModificationDate)}`; return this.httpDelete(path).pipe(mergeMap(ajaxResponse => { return jsonld.compact(ajaxResponse.response, {}); }), map((jsonldobj) => { return OntologyConversionUtil.convertResourcePropertyResponse(jsonldobj, this.jsonConvert); }), catchError(error => this.handleError(error))); } /** * Adds cardinalities for properties to a resource class. * * @param addCardinalityToResourceClass the cardinalities to be added. */ addCardinalityToResourceClass(addCardinalityToResourceClass) { if (addCardinalityToResourceClass.entity.cardinalities.length === 0) { throw new Error('At least one cardinality must be defined.'); } const onto = this.jsonConvert.serializeObject(addCardinalityToResourceClass); const cardinalities = this.jsonConvert.serializeObject(addCardinalityToResourceClass.entity); onto['@graph'] = [cardinalities]; return this.httpPost('/cardinalities', onto).pipe(mergeMap(ajaxResponse => { // TODO: @rosenth Adapt context object // TODO: adapt getOntologyIriFromEntityIri return jsonld.compact(ajaxResponse.response, {}); }), map((jsonldobj) => { return OntologyConversionUtil.convertResourceClassResponse(jsonldobj, this.jsonConvert); }), catchError(error => { return this.handleError(error); })); } /** * Checks whether existing cardinalities can be replaced for a given resource class. * * @deprecated use canReplaceCardinalityOfResourceClassWith instead * @param resourceClassIri the iri of the resource class to be checked. */ canReplaceCardinalityOfResourceClass(resourceClassIri) { return this.httpGet(`/canreplacecardinalities/${encodeURIComponent(resourceClassIri)}`).pipe(mergeMap(ajaxResponse => { // TODO: @rosenth Adapt context object // TODO: adapt getOntologyIriFromEntityIri return jsonld.compact(ajaxResponse.response, {}); }), map((jsonldobj) => { return this.jsonConvert.deserializeObject(jsonldobj, CanDoResponse); }), catchError(error => { return this.handleError(error); })); } /** * Checks whether existing cardinalities can be replaced for a given resource class, propertyIri, and desired cardinality * * @param resourceClassIri the iri of the resource class to be checked. * @param propertyIri the iri of the property to be checked. * @param desiredCardinality the desired cardinality. */ canReplaceCardinalityOfResourceClassWith(resourceClassIri, propertyIri, desiredCardinality) { const card = CardinalityUtil.cardinalities.get(desiredCardinality); return this.httpGet(`/canreplacecardinalities/${encodeURIComponent(resourceClassIri)}?propertyIri=${encodeURIComponent(propertyIri)}&newCardinality=${card}`).pipe(mergeMap(ajaxResponse => { return jsonld.compact(ajaxResponse.response, {}); }), map((jsonldobj) => { return this.jsonConvert.deserializeObject(jsonldobj, CanDoResponse); }), catchError(error => { return this.handleError(error); })); } /** * Replaces cardinalities for properties to a resource class. * * @param replaceCardinalityOfResourceClass the cardinalities to be added. */ replaceCardinalityOfResourceClass(replaceCardinalityOfResourceClass) { const onto = this.jsonConvert.serializeObject(replaceCardinalityOfResourceClass); const numberOfCards = replaceCardinalityOfResourceClass.entity.cardinalities.length; const cardinalities = this.jsonConvert.serializeObject(replaceCardinalityOfResourceClass.entity); // remove subClassOf if no cards are provided // all cards will be removed from resource class if (numberOfCards === 0) { delete cardinalities[Constants.SubClassOf]; } onto['@graph'] = [cardinalities]; return this.httpPut('/cardinalities', onto).pipe(mergeMap(ajaxResponse => { // TODO: @rosenth Adapt context object // TODO: adapt getOntologyIriFromEntityIri return jsonld.compact(ajaxResponse.response, {}); }), map((jsonldobj) => { return OntologyConversionUtil.convertResourceClassResponse(jsonldobj, this.jsonConvert); }), catchError(error => { return this.handleError(error); })); } /** * Checks wether a cardinality can be removed from a class even in presence of resources of this class. * A cardinality can be removed in the case that the property is not used in any resources. * For now, DSP-API allows only one cardinality at a time to delete. * @param deleteCardinalitiesFromClass the cardinalities that need to be checked. */ canDeleteCardinalityFromResourceClass(deleteCardinalityFromClass) { const deleteCardinalityFromClassRequest = this.jsonConvert.serializeObject(deleteCardinalityFromClass); const numberOfCardinalities = deleteCardinalityFromClass.entity.cardinalities.length; if (numberOfCardinalities > 1) { // only one cardinality at a time can be deleted; return an error return this._badCardinalityRequest('canDeleteCardinalityFromClass'); } const cardinalities = this.jsonConvert.serializeObject(deleteCardinalityFromClass.entity); deleteCardinalityFromClassRequest['@graph'] = [cardinalities]; return this.httpPost('/candeletecardinalities', deleteCardinalityFromClassRequest).pipe(mergeMap(ajaxResponse => { return jsonld.compact(ajaxResponse.response, {}); }), map((jsonldobj) => { return this.jsonConvert.deserializeObject(jsonldobj, CanDoResponse); }), catchError(error => { return this.handleError(error); })); } /** * Deletes cardinalities from a class even in presence of resources of this class. * A cardinality can be removed in the case that the property is not used in any resources. * For now, DSP-API allows only one cardinality at a time to be deleted. * @param deleteCardinalitiesFromClass the cardinalities that need to be checked. */ deleteCardinalityFromResourceClass(deleteCardinalityFromClass) { const deleteCardinalityFromClassRequest = this.jsonConvert.serializeObject(deleteCardinalityFromClass); const numberOfCardinalities = deleteCardinalityFromClass.entity.cardinalities.length; if (numberOfCardinalities > 1) { // only one cardinality at a time can be deleted; return an error return this._badCardinalityRequest('deleteCardinalityFromClass'); } const cardinalities = this.jsonConvert.serializeObject(deleteCardinalityFromClass.entity); deleteCardinalityFromClassRequest['@graph'] = [cardinalities]; return this.httpPatch('/cardinalities', deleteCardinalityFromClassRequest).pipe(mergeMap(ajaxResponse => { return jsonld.compact(ajaxResponse.response, {}); }), map((jsonldobj) => { return OntologyConversionUtil.convertResourceClassResponse(jsonldobj, this.jsonConvert); }), catchError(error => { return this.handleError(error); })); } /** * Updates gui order of cardinalities * @param replaceGuiOrder */ replaceGuiOrderOfCardinalities(replaceGuiOrder) { const onto = this.jsonConvert.serializeObject(replaceGuiOrder); const cardinalities = this.jsonConvert.serializeObject(replaceGuiOrder.entity); onto['@graph'] = [cardinalities]; return this.httpPut('/guiorder', onto).pipe(mergeMap(ajaxResponse => { return jsonld.compact(ajaxResponse.response, {}); }), map((jsonldobj) => { return OntologyConversionUtil.convertResourceClassResponse(jsonldobj, this.jsonConvert); }), catchError(error => { return this.handleError(error); })); } _badCardinalityRequest(method) { const response = { error: 'Only one cardinality can be deleted at a time.', url: '/cardinalities', status: 400, method, }; const error = new DataError('Bad request', response); return this.handleError(error); } } //# sourceMappingURL=ontologies-endpoint-v2.js.map