From 09688f5d4bd85e9544807328ee51b222d8b4732b Mon Sep 17 00:00:00 2001 From: Balduin Landolt <33053745+BalduinLandolt@users.noreply.github.com> Date: Mon, 27 Jun 2022 09:15:19 +0200 Subject: [PATCH] fix(ontology): link value property is not editable after editing the property metadata (DEV-1037) (#2084) * improve error message * write test that reproduces the bug * fix: ensure that link value properties are editable too * remove TODO --- .../ontologymessages/OntologyMessagesV2.scala | 4 +- .../responders/v2/OntologyResponderV2.scala | 1 + .../webapi/e2e/v2/OntologyV2R2RSpec.scala | 90 +++++++++++++++++-- 3 files changed, 89 insertions(+), 6 deletions(-) diff --git a/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/ontologymessages/OntologyMessagesV2.scala b/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/ontologymessages/OntologyMessagesV2.scala index b85c6023ab..b2dba2e3b3 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/ontologymessages/OntologyMessagesV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/ontologymessages/OntologyMessagesV2.scala @@ -297,7 +297,9 @@ object OntologyUpdateHelper { } if (inputOntologyV2.properties.size != 1) { - throw BadRequestException(s"Only one property can be created or modified per request") + throw BadRequestException( + s"Only one property can be created or modified per request. Requested to update ${inputOntologyV2.properties.size} properties." + ) } val propertyInfoContent = inputOntologyV2.properties.values.head diff --git a/webapi/src/main/scala/org/knora/webapi/responders/v2/OntologyResponderV2.scala b/webapi/src/main/scala/org/knora/webapi/responders/v2/OntologyResponderV2.scala index af961d3ea6..bf56abd169 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/v2/OntologyResponderV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/v2/OntologyResponderV2.scala @@ -2983,6 +2983,7 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon maybeUnescapedNewLinkValuePropertyDef.map { unescapedNewLinkPropertyDef => unescapedNewLinkPropertyDef.propertyIri -> ReadPropertyInfoV2( entityInfoContent = unescapedNewLinkPropertyDef, + isEditable = true, isResourceProp = true, isLinkValueProp = true ) diff --git a/webapi/src/test/scala/org/knora/webapi/e2e/v2/OntologyV2R2RSpec.scala b/webapi/src/test/scala/org/knora/webapi/e2e/v2/OntologyV2R2RSpec.scala index 73b32d5ea4..e73fc0d2ff 100644 --- a/webapi/src/test/scala/org/knora/webapi/e2e/v2/OntologyV2R2RSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/e2e/v2/OntologyV2R2RSpec.scala @@ -1696,6 +1696,86 @@ class OntologyV2R2RSpec extends R2RSpec { ) iris should equal(expectedIris) + + val isEditable = hasOtherNothingValue.requireBoolean(OntologyConstants.KnoraApiV2Complex.IsEditable) + isEditable shouldBe (true) + } + } + + "update the property label and comment and check if the property is still correctly marked as `isEditable: true`" in { + // update label and comment of a property + val ontoIri = SharedOntologyTestDataADM.ANYTHING_ONTOLOGY_IRI_LocalHost + val propertyIri = ontoIri + "#hasOtherNothing" + val propertyValueIri = ontoIri + "#hasOtherNothingValue" + val newLabel = "updated label" + + val params = + s""" + |{ + | "@id" : "$ontoIri", + | "@type": "owl:Ontology", + | "knora-api:lastModificationDate" : { + | "@type" : "xsd:dateTimeStamp", + | "@value" : "$anythingLastModDate" + | }, + | "@graph": [ + | { + | "@id": "$propertyIri", + | "@type" : "owl:ObjectProperty", + | "rdfs:label": { + | "@language": "en", + | "@value": "$newLabel" + | } + | } + | ], + | "@context" : { + | "rdf" : "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + | "knora-api" : "http://api.knora.org/ontology/knora-api/v2#", + | "owl" : "http://www.w3.org/2002/07/owl#", + | "xsd" : "http://www.w3.org/2001/XMLSchema#", + | "rdfs" : "http://www.w3.org/2000/01/rdf-schema#" + | } + |} + """.stripMargin + + Put("/v2/ontologies/properties", HttpEntity(RdfMediaTypes.`application/ld+json`, params)) ~> addCredentials( + BasicHttpCredentials(anythingUsername, password) + ) ~> ontologiesPath ~> check { + val responseStr = responseAs[String] + + assert(status == StatusCodes.OK, response.toString) + val responseJsonDoc = JsonLDUtil.parseJsonLD(responseStr) + val updatedOntologyIri = responseJsonDoc.body.value("@id").asInstanceOf[JsonLDString].value + assert(updatedOntologyIri == ontoIri) + val graph = responseJsonDoc.body.requireArray("@graph").value + val property = graph.head.asInstanceOf[JsonLDObject] + val returnedPropertyIri = property.requireString("@id") + returnedPropertyIri should equal(propertyIri) + val returnedLabel = property.requireObject(OntologyConstants.Rdfs.Label).requireString("@value") + returnedLabel should equal(newLabel) + val lastModDate = responseJsonDoc.body.requireDatatypeValueInObject( + key = OntologyConstants.KnoraApiV2Complex.LastModificationDate, + expectedDatatype = OntologyConstants.Xsd.DateTimeStamp.toSmartIri, + validationFun = stringFormatter.xsdDateTimeStampToInstant + ) + + assert(lastModDate.isAfter(fooLastModDate)) + anythingLastModDate = lastModDate + + // load back the ontology to verify that the updated property still is editable + val encodedIri = URLEncoder.encode(s"${SharedOntologyTestDataADM.ANYTHING_ONTOLOGY_IRI_LocalHost}", "UTF-8") + Get( + s"/v2/ontologies/allentities/${encodedIri}" + ) ~> ontologiesPath ~> check { + val responseStr: String = responseAs[String] + assert(status == StatusCodes.OK, response.toString) + val responseJsonDoc = JsonLDUtil.parseJsonLD(responseStr) + + val graph = responseJsonDoc.body.requireArray("@graph").value.map(_.asInstanceOf[JsonLDObject]) + val nothingValue = graph.filter(_.requireString("@id") == propertyValueIri).head + val isEditableMaybe = nothingValue.maybeBoolean(OntologyConstants.KnoraApiV2Complex.IsEditable) + isEditableMaybe should equal(Some(true)) + } } } @@ -2244,7 +2324,7 @@ class OntologyV2R2RSpec extends R2RSpec { | "knora-api": "${OntologyConstants.KnoraApiV2Complex.KnoraApiV2PrefixExpansion}" | } |} - """.stripMargin + """.stripMargin Post("/v2/ontologies", HttpEntity(RdfMediaTypes.`application/ld+json`, createOntologyJson)) ~> addCredentials( BasicHttpCredentials(superUsername, password) @@ -2302,7 +2382,7 @@ class OntologyV2R2RSpec extends R2RSpec { | "useless" : "${uselessIri.get}#" | } |} - """.stripMargin + """.stripMargin // Convert the submitted JSON-LD to an InputOntologyV2, without SPARQL-escaping, so we can compare it to the response. val paramsAsInput: InputOntologyV2 = @@ -2590,7 +2670,7 @@ class OntologyV2R2RSpec extends R2RSpec { | "anything" : "${SharedOntologyTestDataADM.ANYTHING_ONTOLOGY_IRI_LocalHost}#" | } |} - """.stripMargin + """.stripMargin Post( "/v2/ontologies/cardinalities", @@ -2642,7 +2722,7 @@ class OntologyV2R2RSpec extends R2RSpec { | "anything" : "${SharedOntologyTestDataADM.ANYTHING_ONTOLOGY_IRI_LocalHost}#" | } |} - """.stripMargin + """.stripMargin Put("/v2/ontologies/cardinalities", HttpEntity(RdfMediaTypes.`application/ld+json`, params)) ~> addCredentials( BasicHttpCredentials(anythingUsername, password) @@ -2873,7 +2953,7 @@ class OntologyV2R2RSpec extends R2RSpec { | "freetest" : "${SharedOntologyTestDataADM.FREETEST_ONTOLOGY_IRI_LocalHost}#" | } |} - """.stripMargin + """.stripMargin CollectClientTestData("candeletecardinalities-true-request", params)