From d5b48db1528d3a8f0c0d3f08bc97564d01e383ce Mon Sep 17 00:00:00 2001 From: Balduin Landolt <33053745+BalduinLandolt@users.noreply.github.com> Date: Tue, 26 Jul 2022 19:22:08 +0200 Subject: [PATCH] fix(ontology): link value property is still not editable after updating the property metadata (DEV-1116) (#2133) * write tests to reproduce the bug * fix the bug * streamline tests a bit --- .../responders/v2/OntologyResponderV2.scala | 2 + .../webapi/e2e/v2/OntologyV2R2RSpec.scala | 227 ++++++++++++++++-- 2 files changed, 211 insertions(+), 18 deletions(-) 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 58f61fc23f..ee63fdd4e6 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 @@ -2753,6 +2753,7 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon maybeUnescapedNewLinkValuePropertyDef.map { unescapedNewLinkPropertyDef => unescapedNewLinkPropertyDef.propertyIri -> ReadPropertyInfoV2( entityInfoContent = unescapedNewLinkPropertyDef, + isEditable = true, isResourceProp = true, isLinkValueProp = true ) @@ -3277,6 +3278,7 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon maybeNewLinkValuePropertyDef.map { newLinkPropertyDef: PropertyInfoContentV2 => newLinkPropertyDef.propertyIri -> ReadPropertyInfoV2( entityInfoContent = newLinkPropertyDef, + 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 edf4878060..d206710a16 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 @@ -216,6 +216,10 @@ class OntologyV2R2RSpec extends R2RSpec { private val incunabulaPartOf = URLEncoder.encode(SharedOntologyTestDataADM.INCUNABULA_PartOf_Property_LocalHost, "UTF-8") + private val anythingOntoLocalhostIri = SharedOntologyTestDataADM.ANYTHING_ONTOLOGY_IRI_LocalHost + private val hasOtherNothingIri = anythingOntoLocalhostIri + "#hasOtherNothing" + private val hasOtherNothingValueIri = anythingOntoLocalhostIri + "#hasOtherNothingValue" + // The URLs and expected response files for each HTTP GET test. private val httpGetTests = Seq( HttpGetTest( @@ -1747,17 +1751,13 @@ class OntologyV2R2RSpec extends R2RSpec { } } - "update the property label and comment and check if the property is still correctly marked as `isEditable: true`" in { + "update the property label 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 newLabel = "updated label" val params = s""" |{ - | "@id" : "$ontoIri", + | "@id" : "$anythingOntoLocalhostIri", | "@type": "owl:Ontology", | "knora-api:lastModificationDate" : { | "@type" : "xsd:dateTimeStamp", @@ -1765,7 +1765,7 @@ class OntologyV2R2RSpec extends R2RSpec { | }, | "@graph": [ | { - | "@id": "$propertyIri", + | "@id": "$hasOtherNothingIri", | "@type" : "owl:ObjectProperty", | "rdfs:label": { | "@language": "en", @@ -1780,8 +1780,7 @@ class OntologyV2R2RSpec extends R2RSpec { | "xsd" : "http://www.w3.org/2001/XMLSchema#", | "rdfs" : "http://www.w3.org/2000/01/rdf-schema#" | } - |} - """.stripMargin + |}""".stripMargin Put("/v2/ontologies/properties", HttpEntity(RdfMediaTypes.`application/ld+json`, params)) ~> addCredentials( BasicHttpCredentials(anythingUsername, password) @@ -1791,11 +1790,11 @@ class OntologyV2R2RSpec extends R2RSpec { assert(status == StatusCodes.OK, response.toString) val responseJsonDoc = JsonLDUtil.parseJsonLD(responseStr) val updatedOntologyIri = responseJsonDoc.body.value("@id").asInstanceOf[JsonLDString].value - assert(updatedOntologyIri == ontoIri) + assert(updatedOntologyIri == anythingOntoLocalhostIri) val graph = responseJsonDoc.body.requireArray("@graph").value val property = graph.head.asInstanceOf[JsonLDObject] val returnedPropertyIri = property.requireString("@id") - returnedPropertyIri should equal(propertyIri) + returnedPropertyIri should equal(hasOtherNothingIri) val returnedLabel = property.requireObject(OntologyConstants.Rdfs.Label).requireString("@value") returnedLabel should equal(newLabel) val lastModDate = responseJsonDoc.body.requireDatatypeValueInObject( @@ -1817,7 +1816,199 @@ class OntologyV2R2RSpec extends R2RSpec { val responseJsonDoc = JsonLDUtil.parseJsonLD(responseStr) val graph = responseJsonDoc.body.requireArray("@graph").value.map(_.asInstanceOf[JsonLDObject]) - val nothingValue = graph.filter(_.requireString("@id") == propertyValueIri).head + val nothingValue = graph.filter(_.requireString("@id") == hasOtherNothingValueIri).head + val isEditableMaybe = nothingValue.maybeBoolean(OntologyConstants.KnoraApiV2Complex.IsEditable) + isEditableMaybe should equal(Some(true)) + } + } + } + + "update the property comment and check if the property is still correctly marked as `isEditable: true`" in { + // update label and comment of a property + val newComment = "updated comment" + + val params = + s""" + |{ + | "@id" : "$anythingOntoLocalhostIri", + | "@type": "owl:Ontology", + | "knora-api:lastModificationDate" : { + | "@type" : "xsd:dateTimeStamp", + | "@value" : "$anythingLastModDate" + | }, + | "@graph": [ + | { + | "@id": "$hasOtherNothingIri", + | "@type" : "owl:ObjectProperty", + | "rdfs:comment": { + | "@language": "en", + | "@value": "$newComment" + | } + | } + | ], + | "@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 == anythingOntoLocalhostIri) + val graph = responseJsonDoc.body.requireArray("@graph").value + val property = graph.head.asInstanceOf[JsonLDObject] + val returnedPropertyIri = property.requireString("@id") + returnedPropertyIri should equal(hasOtherNothingIri) + val returnedComment = property.requireObject(OntologyConstants.Rdfs.Comment).requireString("@value") + returnedComment should equal(newComment) + 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") == hasOtherNothingValueIri).head + val isEditableMaybe = nothingValue.maybeBoolean(OntologyConstants.KnoraApiV2Complex.IsEditable) + isEditableMaybe should equal(Some(true)) + } + } + } + + "delete the property comment and check if the property is still correctly marked as `isEditable: true`" in { + // update label and comment of a property + val propertyIriEncoded = URLEncoder.encode(hasOtherNothingIri, "UTF-8") + + Delete( + s"/v2/ontologies/properties/comment/$propertyIriEncoded?lastModificationDate=$anythingLastModDate" + ) ~> 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 == anythingOntoLocalhostIri) + val graph = responseJsonDoc.body.requireArray("@graph").value + val property = graph.head.asInstanceOf[JsonLDObject] + val returnedPropertyIri = property.requireString("@id") + returnedPropertyIri should equal(hasOtherNothingIri) + assert(property.value.get(OntologyConstants.Rdfs.Comment) == None) + 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") == hasOtherNothingValueIri).head + val isEditableMaybe = nothingValue.maybeBoolean(OntologyConstants.KnoraApiV2Complex.IsEditable) + isEditableMaybe should equal(Some(true)) + } + } + } + + "update the property guiElement and check if the property is still correctly marked as `isEditable: true`" in { + // update label and comment of a property + + val params = + s""" + |{ + | "@id" : "$anythingOntoLocalhostIri", + | "@type": "owl:Ontology", + | "knora-api:lastModificationDate" : { + | "@type" : "xsd:dateTimeStamp", + | "@value" : "$anythingLastModDate" + | }, + | "@graph": [ + | { + | "@id": "$hasOtherNothingIri", + | "@type" : "owl:ObjectProperty", + | "salsah-gui:guiElement": { + | "@id": "salsah-gui:Searchbox" + | } + | } + | ], + | "@context" : { + | "rdf" : "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + | "knora-api" : "http://api.knora.org/ontology/knora-api/v2#", + | "salsah-gui": "http://api.knora.org/ontology/salsah-gui/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/guielement", + 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 == anythingOntoLocalhostIri) + val graph = responseJsonDoc.body.requireArray("@graph").value + val property = graph.head.asInstanceOf[JsonLDObject] + val returnedPropertyIri = property.requireString("@id") + returnedPropertyIri should equal(hasOtherNothingIri) + 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") == hasOtherNothingValueIri).head val isEditableMaybe = nothingValue.maybeBoolean(OntologyConstants.KnoraApiV2Complex.IsEditable) isEditableMaybe should equal(Some(true)) } @@ -2369,7 +2560,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) @@ -2427,7 +2618,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 = @@ -2715,7 +2906,7 @@ class OntologyV2R2RSpec extends R2RSpec { | "anything" : "${SharedOntologyTestDataADM.ANYTHING_ONTOLOGY_IRI_LocalHost}#" | } |} - """.stripMargin + """.stripMargin Post( "/v2/ontologies/cardinalities", @@ -2767,7 +2958,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) @@ -2998,7 +3189,7 @@ class OntologyV2R2RSpec extends R2RSpec { | "freetest" : "${SharedOntologyTestDataADM.FREETEST_ONTOLOGY_IRI_LocalHost}#" | } |} - """.stripMargin + """.stripMargin CollectClientTestData("candeletecardinalities-true-request", params)