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

feat(ontology): Add support for additional ontologies (DEV-512) #2029

Merged
merged 16 commits into from Apr 6, 2022
Merged
2 changes: 1 addition & 1 deletion build.sbt
Expand Up @@ -171,7 +171,7 @@ lazy val webapi: Project = Project(id = "webapi", base = file("webapi"))
Docker / dockerRepository := Some("daschswiss"),
Docker / packageName := "knora-api",
dockerUpdateLatest := true,
dockerBaseImage := "eclipse-temurin:11-jre-focal",
dockerBaseImage := "eclipse-temurin:17-jre-focal",
Docker / maintainer := "support@dasch.swiss",
Docker / dockerExposedPorts ++= Seq(3333),
Docker / defaultLinuxInstallLocation := "/opt/docker",
Expand Down
23 changes: 23 additions & 0 deletions test_data/ontologies/freetest-onto.ttl
Expand Up @@ -148,6 +148,18 @@
rdfs:comment """A comment for FTRC."""@de .


:FreeTestSubClassOfFoafPerson
rdf:type owl:Class ;
rdfs:subClassOf foaf:Person,
knora-base:Resource,
[ rdf:type owl:Restriction ;
owl:onProperty :hasFoafName ;
owl:minCardinality "0"^^xsd:nonNegativeInteger ;
salsah-gui:guiOrder "1"^^xsd:nonNegativeInteger ] ;
rdfs:label "FTRCFoafPerson en"@en ;
rdfs:comment """A comment for FTRCFoafPerson."""@de .


:Author
rdf:type owl:Class ;
rdfs:subClassOf knora-base:Resource,
Expand Down Expand Up @@ -299,3 +311,14 @@
knora-base:objectClassConstraint
knora-base:TextValue ;
salsah-gui:guiElement salsah-gui:Richtext .

:hasFoafName
rdf:type owl:ObjectProperty ;
rdfs:subPropertyOf knora-base:hasValue,
foaf:name ;
rdfs:label "FoafName"@en ;
knora-base:subjectClassConstraint :FreeTestSubClassOfFoafPerson ;
knora-base:objectClassConstraint knora-base:TextValue ;
salsah-gui:guiElement salsah-gui:SimpleText ;
salsah-gui:guiAttribute "size=80",
"maxlength=255" .
irinaschubert marked this conversation as resolved.
Show resolved Hide resolved
Expand Up @@ -956,11 +956,15 @@ object OntologyHelpers {
directCardinalities = internalClassDef.directCardinalities ++ linkValuePropCardinalitiesToAdd
)

// Get the cardinalities that the class can inherit.
// Get the cardinalities that the class can inherit. If the ontology of the base class can't be found, it's assumed to be an external ontology (p.ex. foaf).

val cardinalitiesAvailableToInherit: Map[SmartIri, KnoraCardinalityInfo] =
classDefWithAddedLinkValueProps.subClassOf.flatMap { baseClassIri =>
cacheData.ontologies(baseClassIri.getOntologyFromEntity).classes(baseClassIri).allCardinalities
val ontology = cacheData.ontologies.getOrElse(baseClassIri.getOntologyFromEntity, None)
ontology match {
case ontology: ReadOntologyV2 => ontology.classes(baseClassIri).allCardinalities
case _ => None
}
}.toMap

// Check that the cardinalities directly defined on the class are compatible with any inheritable
Expand Down
Expand Up @@ -61,7 +61,11 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) {
override lazy val rdfDataObjects: List[RdfDataObject] = List(
RdfDataObject(path = "test_data/all_data/incunabula-data.ttl", name = "http://www.knora.org/data/0803/incunabula"),
RdfDataObject(path = "test_data/demo_data/images-demo-data.ttl", name = "http://www.knora.org/data/00FF/images"),
RdfDataObject(path = "test_data/all_data/anything-data.ttl", name = "http://www.knora.org/data/0001/anything")
RdfDataObject(path = "test_data/all_data/anything-data.ttl", name = "http://www.knora.org/data/0001/anything"),
RdfDataObject(
path = "test_data/ontologies/freetest-onto.ttl",
name = "http://www.knora.org/ontology/0001/freetest"
)
)

private val instanceChecker: InstanceChecker = InstanceChecker.getJsonLDChecker
Expand Down Expand Up @@ -181,7 +185,11 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) {
val responseAsString = responseToString(response)
assert(response.status == StatusCodes.OK, responseAsString)
val expectedAnswerJSONLD =
readOrWriteTextFile(responseAsString, Paths.get("..", "test_data/resourcesR2RV2/AThing.jsonld"), writeTestDataFiles)
readOrWriteTextFile(
responseAsString,
Paths.get("..", "test_data/resourcesR2RV2/AThing.jsonld"),
writeTestDataFiles
)
compareJSONLDForResourcesResponse(expectedJSONLD = expectedAnswerJSONLD, receivedJSONLD = responseAsString)

clientTestDataCollector.addFile(
Expand Down Expand Up @@ -476,7 +484,11 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) {
val responseAsString = responseToString(response)
assert(response.status == StatusCodes.OK, responseAsString)
val expectedAnswerJSONLD =
readOrWriteTextFile(responseAsString, Paths.get("..", "test_data/resourcesR2RV2/Testding.jsonld"), writeTestDataFiles)
readOrWriteTextFile(
responseAsString,
Paths.get("..", "test_data/resourcesR2RV2/Testding.jsonld"),
writeTestDataFiles
)
compareJSONLDForResourcesResponse(expectedJSONLD = expectedAnswerJSONLD, receivedJSONLD = responseAsString)

clientTestDataCollector.addFile(
Expand Down Expand Up @@ -1008,6 +1020,74 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) {
assert(text == "this is text with standoff")
}

"create a resource and a property with references to an external ontology (FOAF)" in {
val createResourceWithRefToFoaf: String =
"""{
| "@type" : "freetest:FreeTestSubClassOfFoafPerson",
| "freetest:hasFoafName" : {
| "@type" : "knora-api:TextValue",
| "knora-api:valueAsString" : "this is a foaf name"
| },
| "knora-api:attachedToProject" : {
| "@id" : "http://rdfh.ch/projects/0001"
| },
| "rdfs:label" : "Test foaf Person",
| "@context" : {
| "rdf" : "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
| "knora-api" : "http://api.knora.org/ontology/knora-api/v2#",
| "rdfs" : "http://www.w3.org/2000/01/rdf-schema#",
| "xsd" : "http://www.w3.org/2001/XMLSchema#",
| "freetest" : "http://0.0.0.0:3333/ontology/0001/freetest/v2#"
| }
|}""".stripMargin

val request = Post(
s"$baseApiUrl/v2/resources",
HttpEntity(RdfMediaTypes.`application/ld+json`, createResourceWithRefToFoaf)
) ~> addCredentials(BasicHttpCredentials(anythingUserEmail, password))
val response: HttpResponse = singleAwaitingRequest(request)
assert(response.status == StatusCodes.OK, response.toString)
val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response)
val resourceIri: IRI =
responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri)
assert(resourceIri.toSmartIri.isKnoraDataIri)

// Request the newly created resource in the complex schema, and check that it matches the ontology.
val resourceComplexGetRequest = Get(
s"$baseApiUrl/v2/resources/${URLEncoder.encode(resourceIri, "UTF-8")}"
) ~> addCredentials(BasicHttpCredentials(anythingUserEmail, password))
val resourceComplexGetResponse: HttpResponse = singleAwaitingRequest(resourceComplexGetRequest)
val resourceComplexGetResponseAsString = responseToString(resourceComplexGetResponse)

instanceChecker.check(
instanceResponse = resourceComplexGetResponseAsString,
expectedClassIri = "http://0.0.0.0:3333/ontology/0001/freetest/v2#FreeTestSubClassOfFoafPerson".toSmartIri,
knoraRouteGet = doGetRequest
)

// Request the newly created resource in the simple schema, and check that it matches the ontology.
val resourceSimpleGetRequest = Get(s"$baseApiUrl/v2/resources/${URLEncoder.encode(resourceIri, "UTF-8")}")
.addHeader(new SchemaHeader(RouteUtilV2.SIMPLE_SCHEMA_NAME)) ~> addCredentials(
BasicHttpCredentials(anythingUserEmail, password)
)
val resourceSimpleGetResponse: HttpResponse = singleAwaitingRequest(resourceSimpleGetRequest)
val resourceSimpleGetResponseAsString = responseToString(resourceSimpleGetResponse)

instanceChecker.check(
instanceResponse = resourceSimpleGetResponseAsString,
expectedClassIri =
"http://0.0.0.0:3333/ontology/0001/freetest/simple/v2#FreeTestSubClassOfFoafPerson".toSmartIri,
knoraRouteGet = doGetRequest
)

// Check that the value is correct in the simple schema.
val resourceSimpleAsJsonLD: JsonLDDocument = JsonLDUtil.parseJsonLD(resourceSimpleGetResponseAsString)
println(resourceSimpleAsJsonLD.body)
val foafName: String =
resourceSimpleAsJsonLD.body.requireString("http://0.0.0.0:3333/ontology/0001/freetest/simple/v2#hasFoafName")
assert(foafName == "this is a foaf name")
}

"create a resource whose label contains a Unicode escape and quotation marks" in {
val jsonLDEntity: String =
FileUtil.readTextFile(Paths.get("..", "test_data/resourcesR2RV2/ThingWithUnicodeEscape.jsonld"))
Expand Down Expand Up @@ -1566,7 +1646,8 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) {
}

"create a resource containing escaped text" in {
val jsonLDEntity = FileUtil.readTextFile(Paths.get("..", "test_data/resourcesR2RV2/CreateResourceWithEscape.jsonld"))
val jsonLDEntity =
FileUtil.readTextFile(Paths.get("..", "test_data/resourcesR2RV2/CreateResourceWithEscape.jsonld"))
val request = Post(
s"$baseApiUrl/v2/resources",
HttpEntity(RdfMediaTypes.`application/ld+json`, jsonLDEntity)
Expand Down Expand Up @@ -2205,7 +2286,11 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) {
val responseJson: JsValue = JsonParser(responseStr)

val expectedJson: JsValue = JsonParser(
readOrWriteTextFile(responseStr, Paths.get("..", "test_data/resourcesR2RV2/IIIFManifest.jsonld"), writeTestDataFiles)
readOrWriteTextFile(
responseStr,
Paths.get("..", "test_data/resourcesR2RV2/IIIFManifest.jsonld"),
writeTestDataFiles
)
)

assert(responseJson == expectedJson)
Expand Down