diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index b2ace26545..7bb4d8b458 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -6,3 +6,6 @@ # Scala Steward: Reformat with scalafmt 3.8.3 a5523a0b097ee63e511bff6abf018d5ac6740288 + +# Scala Steward: Reformat with scalafmt 3.8.4 +fb8d6ba614e93997749443355c7e59cdb12edf58 diff --git a/.github/workflows/dependency-graph.yml b/.github/workflows/dependency-graph.yml index 7633539f45..199040e24a 100644 --- a/.github/workflows/dependency-graph.yml +++ b/.github/workflows/dependency-graph.yml @@ -11,6 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - uses: sbt/setup-sbt@v1 - uses: scalacenter/sbt-dependency-submission@v2 with: ## Optional: Define the working directory of your build. diff --git a/.scalafix.conf b/.scalafix.conf index 23d26b0f7b..55bce5e1b4 100644 --- a/.scalafix.conf +++ b/.scalafix.conf @@ -15,6 +15,6 @@ OrganizeImports { importSelectorsOrder = Ascii importsOrder = Ascii preset = DEFAULT - removeUnused = false + removeUnused = true targetDialect = Scala3 } diff --git a/.scalafmt.conf b/.scalafmt.conf index 9b020a3a98..f9ae3a4f77 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -version = "3.8.3" +version = "3.8.4" runner.dialect = scala3 maxColumn = 120 align.preset = most diff --git a/CHANGELOG.md b/CHANGELOG.md index 34516fa70b..ed4f21bc91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,52 @@ # Changelog +## [31.2.1](https://github.com/dasch-swiss/dsp-api/compare/v31.2.0...v31.2.1) (2025-01-20) + + +### Maintenances + +* Add missing sbt setup (DEV-4494) ([#3463](https://github.com/dasch-swiss/dsp-api/issues/3463)) ([e73b358](https://github.com/dasch-swiss/dsp-api/commit/e73b358b735a7cafd011fe3861d82634e8ada192)) +* Dependency updates ([#3458](https://github.com/dasch-swiss/dsp-api/issues/3458)) ([f96d579](https://github.com/dasch-swiss/dsp-api/commit/f96d5798929501ba06e16cdb1d7e49579fb492de)) +* Extract TestDspIngestClient ([#3462](https://github.com/dasch-swiss/dsp-api/issues/3462)) ([05c58a7](https://github.com/dasch-swiss/dsp-api/commit/05c58a70cbec1ea79663ea9641ae42bed978f9c4)) +* Minor dependency updates ([#3457](https://github.com/dasch-swiss/dsp-api/issues/3457)) ([cf84f2d](https://github.com/dasch-swiss/dsp-api/commit/cf84f2de7936f76b7697903780f50ebce4687146)) +* Patch dependency updates ([#3456](https://github.com/dasch-swiss/dsp-api/issues/3456)) ([2340dc1](https://github.com/dasch-swiss/dsp-api/commit/2340dc1d456f60bd75ad7ccd569693fb0aeddbbe)) +* Remove unused twirl templates ([#3465](https://github.com/dasch-swiss/dsp-api/issues/3465)) ([ba04c8b](https://github.com/dasch-swiss/dsp-api/commit/ba04c8b437c673c7876a75d728bd8a98c9782364)) +* Replace query twirl template 'getProjectAdminData' with SparqlQueryBuilder ([#3466](https://github.com/dasch-swiss/dsp-api/issues/3466)) ([10ebd2f](https://github.com/dasch-swiss/dsp-api/commit/10ebd2f085c18b9366de1d655a59621b77de67dd)) +* Update dsp-app to v11.22.5 ([#3453](https://github.com/dasch-swiss/dsp-api/issues/3453)) ([c984b8c](https://github.com/dasch-swiss/dsp-api/commit/c984b8c09be500ed5b63a440ac08b26c9e536864)) +* Update scalafix to 0.14.0 and enable remove unused imports (DEFV-4296) ([#3464](https://github.com/dasch-swiss/dsp-api/issues/3464)) ([f7cf483](https://github.com/dasch-swiss/dsp-api/commit/f7cf483bc60f1ca7bb34d293e502dd81bc078d54)) + + +### Bug Fixes + +* Add rdfs:label to knora-base resources to ensure this is present for isSegmentOfValue properties (DEV-4505) ([#3455](https://github.com/dasch-swiss/dsp-api/issues/3455)) ([bc06166](https://github.com/dasch-swiss/dsp-api/commit/bc06166d6fba1f07ec168246a5f8bbe1aa1f16af)) +* Find the right doap when looking for by ForWhat ([#3460](https://github.com/dasch-swiss/dsp-api/issues/3460)) ([265cb99](https://github.com/dasch-swiss/dsp-api/commit/265cb998a93a6ea465200c12e1eb27440458156b)) + +## [31.2.0](https://github.com/dasch-swiss/dsp-api/compare/v31.1.0...v31.2.0) (2025-01-08) + + +### Maintenances + +* Minor dependency updates ([#3438](https://github.com/dasch-swiss/dsp-api/issues/3438)) ([d31a55f](https://github.com/dasch-swiss/dsp-api/commit/d31a55fc9d67052119879ad9807e2f0a9528fc0e)) +* Remove unused user argument from reloading ontology cache command ([#3447](https://github.com/dasch-swiss/dsp-api/issues/3447)) ([54033bd](https://github.com/dasch-swiss/dsp-api/commit/54033bdbfe62fd95a208052335e63c0dcddc3889)) +* Update copyright ([#3450](https://github.com/dasch-swiss/dsp-api/issues/3450)) ([23c3c6e](https://github.com/dasch-swiss/dsp-api/commit/23c3c6e7cc0b868e6bffbc9e0ab800f7b13506b1)) + + +### Documentation + +* Remove outdated statement on TEI in Standoff support ([#3452](https://github.com/dasch-swiss/dsp-api/issues/3452)) ([76f9077](https://github.com/dasch-swiss/dsp-api/commit/76f90770f214d48389bf8ba0faf7cc70aefbc16a)) + + +### Enhancements + +* Add StandoffFootnoteTag (DEV-4306, DEV-4491) ([#3443](https://github.com/dasch-swiss/dsp-api/issues/3443)) ([ed78393](https://github.com/dasch-swiss/dsp-api/commit/ed783934720bcf6e8a333e73a469551cbcbd3837)) +* Remove license and copyright from Project (DEV-4479) ([#3445](https://github.com/dasch-swiss/dsp-api/issues/3445)) ([c87233b](https://github.com/dasch-swiss/dsp-api/commit/c87233b382035a34704cc4bb9c16f59601dbe525)) +* Support JSON-LD ontology v2 change requests ([#3451](https://github.com/dasch-swiss/dsp-api/issues/3451)) ([a8b4bab](https://github.com/dasch-swiss/dsp-api/commit/a8b4bab882ba36809169c76ff83060032b53aa1c)) + + +### Tests + +* Migrate InputOntologyV2Spec to become a simple unit zio-test in the test source set ([#3449](https://github.com/dasch-swiss/dsp-api/issues/3449)) ([63aed0f](https://github.com/dasch-swiss/dsp-api/commit/63aed0f3b324bf0d43c8d772358ec3e06e8f22bd)) + ## [31.1.0](https://github.com/dasch-swiss/dsp-api/compare/v31.0.0...v31.1.0) (2024-12-16) diff --git a/build.sbt b/build.sbt index 0813eb2e8d..2a16669382 100644 --- a/build.sbt +++ b/build.sbt @@ -150,14 +150,9 @@ val customScalacOptions = Seq( "-deprecation", "-Yresolve-term-conflict:package", "-Wconf:src=target/.*:s", // silence TWIRL templates unused imports warnings - "-Wunused:imports", - "-Wunused:privates", - "-Wunused:locals", - "-Wunused:explicits", - "-Wunused:implicits", - "-Wunused:params", "-Wvalue-discard", "-Xmax-inlines:64", + "-Wunused:all", // "-Xfatal-warnings", ) diff --git a/docker-compose.yml b/docker-compose.yml index 266fa77fc5..a015da7b14 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,6 @@ services: app: - image: daschswiss/dsp-app:v11.22.1 + image: daschswiss/dsp-app:v11.22.5 ports: - "4200:4200" networks: diff --git a/docs/02-dsp-ontologies/knora-base.md b/docs/02-dsp-ontologies/knora-base.md index 8331484853..647a59a4d0 100644 --- a/docs/02-dsp-ontologies/knora-base.md +++ b/docs/02-dsp-ontologies/knora-base.md @@ -695,7 +695,7 @@ end positions of a substring in the text that has a particular attribute. The OW represents the end of a virtual (non syntactical) hierarchy. The `StandoffTag` class is not used directly in RDF data; instead, its subclasses are used. A few subclasses are -currently provided in `standoff-onto.ttl`, and more will be added to support TEI semantics. +currently provided in `standoff-onto.ttl`. Projects are able to define their own custom standoff tag classes (direct subclasses of `StandoffTag` or one of the standoff data type classes or subclasses of one of the standoff classes defined in `standoff-onto.ttl`). diff --git a/docs/03-endpoints/api-v2/text/overview.md b/docs/03-endpoints/api-v2/text/overview.md index b1d9314562..7857d7348c 100644 --- a/docs/03-endpoints/api-v2/text/overview.md +++ b/docs/03-endpoints/api-v2/text/overview.md @@ -35,6 +35,7 @@ This allows for the following markup: - horizontal rules - code blocks - block quotes + - footnotes - typographical markup - italics - bold diff --git a/docs/03-endpoints/api-v2/text/standard-standoff.md b/docs/03-endpoints/api-v2/text/standard-standoff.md index 03a2ffffe7..26f49fa55f 100644 --- a/docs/03-endpoints/api-v2/text/standard-standoff.md +++ b/docs/03-endpoints/api-v2/text/standard-standoff.md @@ -41,6 +41,7 @@ that are mapped to standoff classes and properties defined in the ontology: - `` → `standoff:StandoffCiteTag` - `
` → `standoff:StandoffBlockquoteTag` - `` → `standoff:StandoffCodeTag` +- `` → `standoff:StandoffFootnoteTag` The HTML produced by CKEditor is wrapped in an XML doctype and a pair of root tags `...` and then sent to the DSP-API. @@ -48,3 +49,13 @@ The XML sent to the GUI by the DSP-API is unwrapped accordingly. Although the GUI supports HTML5, it is treated as if it was XHTML in strict XML notation. Text with standard standoff markup can be transformed to TEI XML as described [here](tei-xml.md). + +## Footnotes + +Footnote support is currently experimental and has some limitations: + +- CKE does not support footnotes out of the box. DSP-APP uses a custom build of CKE that supports footnotes. +- The content of footnotes is not covered by the full text search. +- The content of footnotes may contain further markup, but this will internally not be converted to standoff. + For that reason, markup in footnotes can not be searched for through gravsearch + and hence outgoing and incoming links will not be displayed in DSP-APP. diff --git a/integration/src/test/scala/org/knora/webapi/E2ESpec.scala b/integration/src/test/scala/org/knora/webapi/E2ESpec.scala index a42f84fa20..ce72ef928e 100644 --- a/integration/src/test/scala/org/knora/webapi/E2ESpec.scala +++ b/integration/src/test/scala/org/knora/webapi/E2ESpec.scala @@ -32,13 +32,11 @@ import org.knora.webapi.config.AppConfig import org.knora.webapi.core.AppRouter import org.knora.webapi.core.AppServer import org.knora.webapi.core.TestStartupUtils -import org.knora.webapi.messages.store.sipimessages.SipiUploadResponse import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject import org.knora.webapi.messages.store.triplestoremessages.TriplestoreJsonProtocol import org.knora.webapi.messages.util.rdf.* import org.knora.webapi.routing.PekkoRoutesData import org.knora.webapi.routing.UnsafeZioRun -import org.knora.webapi.testservices.FileToUpload import org.knora.webapi.testservices.TestClientService import org.knora.webapi.util.FileUtil import org.knora.webapi.util.LogAspect @@ -151,9 +149,6 @@ abstract class E2ESpec protected def getResponseAsJsonLD(request: HttpRequest): JsonLDDocument = UnsafeZioRun.runOrThrow(ZIO.serviceWithZIO[TestClientService](_.getResponseJsonLD(request))) - protected def uploadToIngest(loginToken: String, filesToUpload: Seq[FileToUpload]): SipiUploadResponse = - UnsafeZioRun.runOrThrow(ZIO.serviceWithZIO[TestClientService](_.uploadToIngest(loginToken, filesToUpload))) - protected def responseToJsonLDDocument(httpResponse: HttpResponse): JsonLDDocument = { val responseBodyFuture: Future[String] = httpResponse.entity.toStrict(FiniteDuration(10L, TimeUnit.SECONDS)).map(_.data.decodeString("UTF-8")) diff --git a/integration/src/test/scala/org/knora/webapi/ITKnoraLiveSpec.scala b/integration/src/test/scala/org/knora/webapi/ITKnoraLiveSpec.scala index 6c806cb3fd..0cde65abc3 100644 --- a/integration/src/test/scala/org/knora/webapi/ITKnoraLiveSpec.scala +++ b/integration/src/test/scala/org/knora/webapi/ITKnoraLiveSpec.scala @@ -28,14 +28,14 @@ import org.knora.webapi.core.AppRouter import org.knora.webapi.core.AppServer import org.knora.webapi.core.LayersTest.DefaultTestEnvironmentWithSipi import org.knora.webapi.core.TestStartupUtils -import org.knora.webapi.messages.store.sipimessages.* import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject import org.knora.webapi.messages.store.triplestoremessages.TriplestoreJsonProtocol import org.knora.webapi.messages.util.rdf.JsonLDDocument import org.knora.webapi.messages.util.rdf.JsonLDUtil import org.knora.webapi.routing.UnsafeZioRun -import org.knora.webapi.testservices.FileToUpload import org.knora.webapi.testservices.TestClientService +import org.knora.webapi.testservices.TestDspIngestClient +import org.knora.webapi.testservices.TestDspIngestClient.UploadedFile import org.knora.webapi.util.LogAspect /** @@ -171,17 +171,8 @@ abstract class ITKnoraLiveSpec .getOrThrowFiberFailure() } - protected def uploadToIngest(loginToken: String, filesToUpload: Seq[FileToUpload]): SipiUploadResponse = - Unsafe.unsafe { implicit u => - runtime.unsafe - .run( - for { - testClient <- ZIO.service[TestClientService] - result <- testClient.uploadToIngest(loginToken, filesToUpload) - } yield result, - ) - .getOrThrow() - } + protected def uploadToIngest(fileToUpload: java.nio.file.Path): UploadedFile = + UnsafeZioRun.runOrThrow(ZIO.serviceWithZIO[TestDspIngestClient](_.uploadFile(fileToUpload))) protected def responseToString(httpResponse: HttpResponse): String = { val responseBodyFuture: Future[String] = diff --git a/integration/src/test/scala/org/knora/webapi/core/LayersTest.scala b/integration/src/test/scala/org/knora/webapi/core/LayersTest.scala index b4b32b9cd9..f1de5b0acb 100644 --- a/integration/src/test/scala/org/knora/webapi/core/LayersTest.scala +++ b/integration/src/test/scala/org/knora/webapi/core/LayersTest.scala @@ -86,6 +86,7 @@ import org.knora.webapi.testcontainers.FusekiTestContainer import org.knora.webapi.testcontainers.SharedVolumes import org.knora.webapi.testcontainers.SipiTestContainer import org.knora.webapi.testservices.TestClientService +import org.knora.webapi.testservices.TestDspIngestClient object LayersTest { @@ -93,7 +94,7 @@ object LayersTest { * The `Environment`s that we require for the tests to run - with or without Sipi */ type DefaultTestEnvironmentWithoutSipi = - LayersLive.DspEnvironmentLive & FusekiTestContainer & TestClientService + LayersLive.DspEnvironmentLive & FusekiTestContainer & TestClientService & TestDspIngestClient type DefaultTestEnvironmentWithSipi = DefaultTestEnvironmentWithoutSipi & SipiTestContainer & DspIngestTestContainer & SharedVolumes.Volumes @@ -153,6 +154,7 @@ object LayersTest { State & StringFormatter & TestClientService & + TestDspIngestClient & TriplestoreService & UserRestService & ValuesResponderV2 @@ -224,6 +226,7 @@ object LayersTest { StringFormatter.live, TapirToPekkoInterpreter.layer, TestClientService.layer, + TestDspIngestClient.layer, TriplestoreServiceLive.layer, ValuesResponderV2.layer, ) diff --git a/integration/src/test/scala/org/knora/webapi/core/TestStartupUtils.scala b/integration/src/test/scala/org/knora/webapi/core/TestStartupUtils.scala index d6bec972cb..01334efc24 100644 --- a/integration/src/test/scala/org/knora/webapi/core/TestStartupUtils.scala +++ b/integration/src/test/scala/org/knora/webapi/core/TestStartupUtils.scala @@ -9,7 +9,6 @@ import com.typesafe.scalalogging.LazyLogging import zio.* import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject -import org.knora.webapi.messages.util.KnoraSystemInstances import org.knora.webapi.slice.ontology.repo.service.OntologyCache import org.knora.webapi.store.triplestore.api.TriplestoreService @@ -32,7 +31,7 @@ trait TestStartupUtils extends LazyLogging { tss <- ZIO.service[TriplestoreService] _ <- tss.resetTripleStoreContent(rdfDataObjects).timeout(480.seconds) _ <- ZIO.logInfo("... loading test data done.") - _ <- ZIO.serviceWithZIO[OntologyCache](_.loadOntologies(KnoraSystemInstances.Users.SystemUser)).orDie + _ <- ZIO.serviceWithZIO[OntologyCache](_.loadOntologies()).orDie } yield () } diff --git a/integration/src/test/scala/org/knora/webapi/e2e/v2/ValuesRouteV2E2ESpec.scala b/integration/src/test/scala/org/knora/webapi/e2e/v2/ValuesRouteV2E2ESpec.scala index b89af6c938..c8ab4e3fe5 100644 --- a/integration/src/test/scala/org/knora/webapi/e2e/v2/ValuesRouteV2E2ESpec.scala +++ b/integration/src/test/scala/org/knora/webapi/e2e/v2/ValuesRouteV2E2ESpec.scala @@ -19,6 +19,7 @@ import java.time.Instant import java.util.UUID import scala.concurrent.Await import scala.concurrent.duration.* +import scala.xml.XML import dsp.errors.AssertionException import dsp.errors.BadRequestException @@ -1557,6 +1558,72 @@ class ValuesRouteV2E2ESpec extends E2ESpec { assert(savedTextValueAsXml.contains(expectedText)) } + "create a text value with standoff containing a footnote" in { + val resourceIri: IRI = AThing.iri + val textValueAsXml: String = + """| + |This text has a footnote containing text. + |""".stripMargin + + val propertyIri: SmartIri = "http://0.0.0.0:3333/ontology/0001/anything/v2#hasText".toSmartIri + val maybeResourceLastModDate: Option[Instant] = getResourceLastModificationDate(resourceIri, anythingUserEmail) + + val jsonLDEntity = createTextValueWithStandoffRequest( + resourceIri = resourceIri, + textValueAsXml = textValueAsXml, + mappingIri = standardMappingIri, + ) + + val request = Post( + baseApiUrl + "/v2/values", + HttpEntity(RdfMediaTypes.`application/ld+json`, jsonLDEntity), + ) ~> addCredentials(BasicHttpCredentials(anythingUserEmail, password)) + val response: HttpResponse = singleAwaitingRequest(request) + assert(response.status == StatusCodes.OK, responseToString(response)) + val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, validationFun) + val valueType: SmartIri = + responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) + valueType should ===(KnoraApiV2Complex.TextValue.toSmartIri) + + val savedValue: JsonLDObject = getValue( + resourceIri = resourceIri, + maybePreviousLastModDate = maybeResourceLastModDate, + propertyIriForGravsearch = propertyIri, + propertyIriInResult = propertyIri, + expectedValueIri = valueIri, + userEmail = anythingUserEmail, + ) + + val savedTextValueAsXml = savedValue + .getRequiredString(KnoraApiV2Complex.TextValueAsXml) + .fold(msg => throw BadRequestException(msg), XML.loadString) + assert(savedTextValueAsXml == XML.loadString(textValueAsXml)) + } + + "not create a text value with standoff containing a footnote without content" in { + val resourceIri: IRI = AThing.iri + val textValueAsXml: String = + """| + | + | This text has a footnote without content. + | + |""".stripMargin + + val jsonLDEntity = createTextValueWithStandoffRequest( + resourceIri = resourceIri, + textValueAsXml = textValueAsXml, + mappingIri = standardMappingIri, + ) + + val request = Post( + baseApiUrl + "/v2/values", + HttpEntity(RdfMediaTypes.`application/ld+json`, jsonLDEntity), + ) ~> addCredentials(BasicHttpCredentials(anythingUserEmail, password)) + val response: HttpResponse = singleAwaitingRequest(request) + assert(response.status == StatusCodes.BadRequest) + } + "create a TextValue from XML representing HTML with an attribute containing escaped quotes" in { // Create the mapping. diff --git a/integration/src/test/scala/org/knora/webapi/it/v2/KnoraSipiIntegrationV2ITSpec.scala b/integration/src/test/scala/org/knora/webapi/it/v2/KnoraSipiIntegrationV2ITSpec.scala index 0440977857..40712d921e 100644 --- a/integration/src/test/scala/org/knora/webapi/it/v2/KnoraSipiIntegrationV2ITSpec.scala +++ b/integration/src/test/scala/org/knora/webapi/it/v2/KnoraSipiIntegrationV2ITSpec.scala @@ -7,31 +7,25 @@ package org.knora.webapi.it.v2 import org.apache.pekko.http.scaladsl.model.* import org.apache.pekko.http.scaladsl.model.headers.BasicHttpCredentials -import org.apache.pekko.http.scaladsl.unmarshalling.Unmarshal import java.net.URLEncoder import java.nio.file.Paths -import scala.concurrent.Await -import scala.concurrent.duration.* import dsp.errors.AssertionException import dsp.errors.BadRequestException import dsp.valueobjects.Iri import org.knora.webapi.* import org.knora.webapi.e2e.v2.AuthenticationV2JsonProtocol -import org.knora.webapi.e2e.v2.LoginResponse import org.knora.webapi.messages.IriConversions.* import org.knora.webapi.messages.OntologyConstants import org.knora.webapi.messages.OntologyConstants.KnoraApiV2Complex.* import org.knora.webapi.messages.SmartIri import org.knora.webapi.messages.StringFormatter -import org.knora.webapi.messages.store.sipimessages.* import org.knora.webapi.messages.store.triplestoremessages.TriplestoreJsonProtocol import org.knora.webapi.messages.util.rdf.* import org.knora.webapi.models.filemodels.* import org.knora.webapi.routing.UnsafeZioRun import org.knora.webapi.sharedtestdata.SharedTestDataADM -import org.knora.webapi.testservices.FileToUpload import org.knora.webapi.util.MutableTestIri /** @@ -330,29 +324,9 @@ class KnoraSipiIntegrationV2ITSpec getResponseJsonLD(request ~> addAuthorization) "The Knora/Sipi integration" should { - var loginToken: String = "" - - "log in as a Knora user" in { - /* Correct username and correct password */ - val params = s"""{"email": "$anythingUserEmail", "password": "$password"}""" - val request = Post(baseApiUrl + s"/v2/authentication", HttpEntity(ContentTypes.`application/json`, params)) - val response = singleAwaitingRequest(request) - assert(response.status == StatusCodes.OK) - - loginToken = Await.result(Unmarshal(response.entity).to[LoginResponse], 1.seconds).token - loginToken.nonEmpty should be(true) - } - "create a resource with a still image file" in { // Upload the image to Sipi. - val sipiUploadResponse: SipiUploadResponse = - uploadToIngest( - loginToken = loginToken, - filesToUpload = - Seq(FileToUpload(path = pathToMarbles, mimeType = org.apache.http.entity.ContentType.IMAGE_TIFF)), - ) - - val uploadedFile: SipiUploadResponseEntry = sipiUploadResponse.uploadedFiles.head + val uploadedFile = uploadToIngest(pathToMarbles) uploadedFile.originalFilename should ===(marblesOriginalFilename) // Create the resource in the API. @@ -398,14 +372,7 @@ class KnoraSipiIntegrationV2ITSpec "change a still image file value" in { // Upload the image to Sipi. - val sipiUploadResponse: SipiUploadResponse = - uploadToIngest( - loginToken = loginToken, - filesToUpload = - Seq(FileToUpload(path = pathToTrp88, mimeType = org.apache.http.entity.ContentType.IMAGE_TIFF)), - ) - - val uploadedFile: SipiUploadResponseEntry = sipiUploadResponse.uploadedFiles.head + val uploadedFile = uploadToIngest(pathToTrp88) uploadedFile.originalFilename should ===(trp88OriginalFilename) // JSON describing the new image to the API. @@ -439,14 +406,7 @@ class KnoraSipiIntegrationV2ITSpec "create a resource with a PDF file" in { // Upload the file to Sipi. - val sipiUploadResponse: SipiUploadResponse = uploadToIngest( - loginToken = loginToken, - filesToUpload = Seq( - FileToUpload(path = pathToMinimalPdf, mimeType = org.apache.http.entity.ContentType.create("application/pdf")), - ), - ) - - val uploadedFile: SipiUploadResponseEntry = sipiUploadResponse.uploadedFiles.head + val uploadedFile = uploadToIngest(pathToMinimalPdf) uploadedFile.originalFilename should ===(minimalPdfOriginalFilename) // Create the resource in the API. @@ -480,14 +440,8 @@ class KnoraSipiIntegrationV2ITSpec "change a PDF file value" in { // Upload the file to Sipi. - val sipiUploadResponse: SipiUploadResponse = uploadToIngest( - loginToken = loginToken, - filesToUpload = Seq( - FileToUpload(path = pathToTestPdf, mimeType = org.apache.http.entity.ContentType.create("application/pdf")), - ), - ) + val uploadedFile = uploadToIngest(pathToTestPdf) - val uploadedFile: SipiUploadResponseEntry = sipiUploadResponse.uploadedFiles.head uploadedFile.originalFilename should ===(testPdfOriginalFilename) // Update the value. @@ -518,14 +472,7 @@ class KnoraSipiIntegrationV2ITSpec "not create a document resource if the file is actually a zip file" in { // Upload the file to Sipi. - val sipiUploadResponse: SipiUploadResponse = uploadToIngest( - loginToken = loginToken, - filesToUpload = Seq( - FileToUpload(path = pathToMinimalZip, mimeType = org.apache.http.entity.ContentType.create("application/zip")), - ), - ) - - val uploadedFile: SipiUploadResponseEntry = sipiUploadResponse.uploadedFiles.head + val uploadedFile = uploadToIngest(pathToMinimalZip) uploadedFile.originalFilename should ===(minimalZipOriginalFilename) // Create the resource in the API. @@ -540,13 +487,7 @@ class KnoraSipiIntegrationV2ITSpec "create a resource with a CSV file" in { // Upload the file to Sipi. - val sipiUploadResponse: SipiUploadResponse = uploadToIngest( - loginToken = loginToken, - filesToUpload = - Seq(FileToUpload(path = pathToCsv1, mimeType = org.apache.http.entity.ContentType.create("text/csv"))), - ) - - val uploadedFile: SipiUploadResponseEntry = sipiUploadResponse.uploadedFiles.head + val uploadedFile = uploadToIngest(pathToCsv1) uploadedFile.originalFilename should ===(csv1OriginalFilename) // Create the resource in the API. @@ -575,13 +516,7 @@ class KnoraSipiIntegrationV2ITSpec "change a CSV file value" in { // Upload the file to Sipi. - val sipiUploadResponse: SipiUploadResponse = uploadToIngest( - loginToken = loginToken, - filesToUpload = - Seq(FileToUpload(path = pathToCsv2, mimeType = org.apache.http.entity.ContentType.create("text/csv"))), - ) - - val uploadedFile: SipiUploadResponseEntry = sipiUploadResponse.uploadedFiles.head + val uploadedFile = uploadToIngest(pathToCsv2) uploadedFile.originalFilename should ===(csv2OriginalFilename) // Update the value. @@ -611,13 +546,7 @@ class KnoraSipiIntegrationV2ITSpec "not create a resource with a still image file that's actually a text file" in { // Upload the file to Sipi. - val sipiUploadResponse: SipiUploadResponse = uploadToIngest( - loginToken = loginToken, - filesToUpload = - Seq(FileToUpload(path = pathToCsv1, mimeType = org.apache.http.entity.ContentType.create("text/csv"))), - ) - - val uploadedFile: SipiUploadResponseEntry = sipiUploadResponse.uploadedFiles.head + val uploadedFile = uploadToIngest(pathToCsv1) uploadedFile.originalFilename should ===(csv1OriginalFilename) // Create the resource in the API. @@ -633,12 +562,7 @@ class KnoraSipiIntegrationV2ITSpec "create a resource with an XML file" in { // Upload the file to Sipi. - val sipiUploadResponse: SipiUploadResponse = uploadToIngest( - loginToken = loginToken, - filesToUpload = Seq(FileToUpload(path = pathToXml1, mimeType = org.apache.http.entity.ContentType.TEXT_XML)), - ) - - val uploadedFile: SipiUploadResponseEntry = sipiUploadResponse.uploadedFiles.head + val uploadedFile = uploadToIngest(pathToXml1) uploadedFile.originalFilename should ===(xml1OriginalFilename) // Create the resource in the API. @@ -673,12 +597,7 @@ class KnoraSipiIntegrationV2ITSpec "change an XML file value" in { // Upload the file to Sipi. - val sipiUploadResponse: SipiUploadResponse = uploadToIngest( - loginToken = loginToken, - filesToUpload = Seq(FileToUpload(path = pathToXml2, mimeType = org.apache.http.entity.ContentType.TEXT_XML)), - ) - - val uploadedFile: SipiUploadResponseEntry = sipiUploadResponse.uploadedFiles.head + val uploadedFile = uploadToIngest(pathToXml2) uploadedFile.originalFilename should ===(xml2OriginalFilename) // Update the value. @@ -714,14 +633,7 @@ class KnoraSipiIntegrationV2ITSpec "not create a resource of type TextRepresentation with a Zip file" in { // Upload the file to Sipi. - val sipiUploadResponse: SipiUploadResponse = uploadToIngest( - loginToken = loginToken, - filesToUpload = Seq( - FileToUpload(path = pathToMinimalZip, mimeType = org.apache.http.entity.ContentType.create("application/zip")), - ), - ) - - val uploadedFile: SipiUploadResponseEntry = sipiUploadResponse.uploadedFiles.head + val uploadedFile = uploadToIngest(pathToMinimalZip) uploadedFile.originalFilename should ===(minimalZipOriginalFilename) // Create the resource in the API. @@ -737,14 +649,7 @@ class KnoraSipiIntegrationV2ITSpec "create a resource of type ArchiveRepresentation with a Zip file" in { // Upload the file to Sipi. - val sipiUploadResponse: SipiUploadResponse = uploadToIngest( - loginToken = loginToken, - filesToUpload = Seq( - FileToUpload(path = pathToMinimalZip, mimeType = org.apache.http.entity.ContentType.create("application/zip")), - ), - ) - - val uploadedFile: SipiUploadResponseEntry = sipiUploadResponse.uploadedFiles.head + val uploadedFile = uploadToIngest(pathToMinimalZip) uploadedFile.originalFilename should ===(minimalZipOriginalFilename) // Create the resource in the API. @@ -782,14 +687,7 @@ class KnoraSipiIntegrationV2ITSpec "change a Zip file value" in { // Upload the file to Sipi. - val sipiUploadResponse: SipiUploadResponse = uploadToIngest( - loginToken = loginToken, - filesToUpload = Seq( - FileToUpload(path = pathToTestZip, mimeType = org.apache.http.entity.ContentType.create("application/zip")), - ), - ) - - val uploadedFile: SipiUploadResponseEntry = sipiUploadResponse.uploadedFiles.head + val uploadedFile = uploadToIngest(pathToTestZip) uploadedFile.originalFilename should ===(testZipOriginalFilename) // Update the value. @@ -825,17 +723,7 @@ class KnoraSipiIntegrationV2ITSpec "create a resource of type ArchiveRepresentation with a 7z file" in { // Upload the file to Sipi. - val sipiUploadResponse: SipiUploadResponse = uploadToIngest( - loginToken = loginToken, - filesToUpload = Seq( - FileToUpload( - path = pathToTest7z, - mimeType = org.apache.http.entity.ContentType.create("application/x-7z-compressed"), - ), - ), - ) - - val uploadedFile: SipiUploadResponseEntry = sipiUploadResponse.uploadedFiles.head + val uploadedFile = uploadToIngest(pathToTest7z) uploadedFile.originalFilename should ===(test7zOriginalFilename) // Create the resource in the API. @@ -873,13 +761,7 @@ class KnoraSipiIntegrationV2ITSpec "create a resource with a WAV file" in { // Upload the file to Sipi. - val sipiUploadResponse: SipiUploadResponse = uploadToIngest( - loginToken = loginToken, - filesToUpload = - Seq(FileToUpload(path = pathToMinimalWav, mimeType = org.apache.http.entity.ContentType.create("audio/wav"))), - ) - - val uploadedFile: SipiUploadResponseEntry = sipiUploadResponse.uploadedFiles.head + val uploadedFile = uploadToIngest(pathToMinimalWav) uploadedFile.originalFilename should ===(minimalWavOriginalFilename) // Create the resource in the API. @@ -917,13 +799,7 @@ class KnoraSipiIntegrationV2ITSpec "change a WAV file value" in { // Upload the file to Sipi. - val sipiUploadResponse: SipiUploadResponse = uploadToIngest( - loginToken = loginToken, - filesToUpload = - Seq(FileToUpload(path = pathToTestWav, mimeType = org.apache.http.entity.ContentType.create("audio/wav"))), - ) - - val uploadedFile: SipiUploadResponseEntry = sipiUploadResponse.uploadedFiles.head + val uploadedFile = uploadToIngest(pathToTestWav) uploadedFile.originalFilename should ===(testWavOriginalFilename) // Update the value. @@ -959,13 +835,7 @@ class KnoraSipiIntegrationV2ITSpec "create a resource with a video file" in { // Upload the file to Sipi. - val sipiUploadResponse: SipiUploadResponse = uploadToIngest( - loginToken = loginToken, - filesToUpload = - Seq(FileToUpload(path = pathToTestVideo, mimeType = org.apache.http.entity.ContentType.create("video/mp4"))), - ) - - val uploadedFile: SipiUploadResponseEntry = sipiUploadResponse.uploadedFiles.head + val uploadedFile = uploadToIngest(pathToTestVideo) uploadedFile.originalFilename should ===(testVideoOriginalFilename) // Create the resource in the API. @@ -1003,17 +873,7 @@ class KnoraSipiIntegrationV2ITSpec "change a video file value" in { // Upload the file to Sipi. - val sipiUploadResponse: SipiUploadResponse = uploadToIngest( - loginToken, - Seq( - FileToUpload( - path = pathToTestVideo2, - mimeType = org.apache.http.entity.ContentType.create("video/mp4"), - ), - ), - ) - - val uploadedFile: SipiUploadResponseEntry = sipiUploadResponse.uploadedFiles.head + val uploadedFile = uploadToIngest(pathToTestVideo2) uploadedFile.originalFilename should ===(testVideo2OriginalFilename) // Update the value. diff --git a/integration/src/test/scala/org/knora/webapi/it/v2/StandoffRouteV2ITSpec.scala b/integration/src/test/scala/org/knora/webapi/it/v2/StandoffRouteV2ITSpec.scala index aa91d00735..1dd74f34fe 100644 --- a/integration/src/test/scala/org/knora/webapi/it/v2/StandoffRouteV2ITSpec.scala +++ b/integration/src/test/scala/org/knora/webapi/it/v2/StandoffRouteV2ITSpec.scala @@ -9,7 +9,6 @@ import org.apache.pekko import org.apache.pekko.http.javadsl.model.StatusCodes import org.apache.pekko.http.scaladsl.model.* import org.apache.pekko.http.scaladsl.model.headers.BasicHttpCredentials -import org.apache.pekko.http.scaladsl.unmarshalling.Unmarshal import org.xmlunit.builder.DiffBuilder import org.xmlunit.builder.Input import org.xmlunit.diff.Diff @@ -17,18 +16,13 @@ import spray.json.* import java.net.URLEncoder import java.nio.file.Paths -import scala.concurrent.Await -import scala.concurrent.duration.* import dsp.errors.BadRequestException import dsp.valueobjects.Iri import org.knora.webapi.* import org.knora.webapi.e2e.v2.AuthenticationV2JsonProtocol -import org.knora.webapi.e2e.v2.LoginResponse import org.knora.webapi.e2e.v2.ResponseCheckerV2.compareJSONLDForMappingCreationResponse import org.knora.webapi.messages.OntologyConstants -import org.knora.webapi.messages.store.sipimessages.* -import org.knora.webapi.messages.store.sipimessages.SipiUploadResponseJsonProtocol.* import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject import org.knora.webapi.messages.util.rdf.JsonLDDocument import org.knora.webapi.messages.util.rdf.JsonLDKeywords @@ -37,7 +31,6 @@ import org.knora.webapi.models.filemodels.UploadFileRequest import org.knora.webapi.models.standoffmodels.DefineStandoffMapping import org.knora.webapi.sharedtestdata.SharedTestDataADM import org.knora.webapi.sharedtestdata.SharedTestDataADM2.anythingProjectIri -import org.knora.webapi.testservices.FileToUpload import org.knora.webapi.util.FileUtil import org.knora.webapi.util.MutableTestIri @@ -298,25 +291,7 @@ class StandoffRouteV2ITSpec extends ITKnoraLiveSpec with AuthenticationV2JsonPro } "create a custom mapping with an XSL transformation" in { - // get authentication token - val params = Map( - "email" -> "root@example.com", - "password" -> "test", - ).toJson.compactPrint - val loginRequest = Post(baseApiUrl + s"/v2/authentication", HttpEntity(ContentTypes.`application/json`, params)) - val loginResponse: HttpResponse = singleAwaitingRequest(loginRequest) - assert(loginResponse.status == StatusCodes.OK, responseToString(loginResponse)) - val loginToken = Await.result(Unmarshal(loginResponse.entity).to[LoginResponse], 1.seconds).token - - val uploadedFile: SipiUploadResponseEntry = uploadToIngest( - loginToken = loginToken, - filesToUpload = Seq( - FileToUpload( - path = Paths.get(pathToFreetestXSLTFile), - mimeType = org.apache.http.entity.ContentType.create("text/xml"), - ), - ), - ).uploadedFiles.head + val uploadedFile = uploadToIngest(Paths.get(pathToFreetestXSLTFile)) // create FileRepresentation in API val uploadFileJson = UploadFileRequest diff --git a/integration/src/test/scala/org/knora/webapi/models/filemodels/FileModelUtil.scala b/integration/src/test/scala/org/knora/webapi/models/filemodels/FileModelUtil.scala index d081fbbb97..0f4c3b7fc3 100644 --- a/integration/src/test/scala/org/knora/webapi/models/filemodels/FileModelUtil.scala +++ b/integration/src/test/scala/org/knora/webapi/models/filemodels/FileModelUtil.scala @@ -207,7 +207,7 @@ object FileModelUtil { } val lines = ontologies.toList .map(x => s""" "${x._1}": "${x._2}\"""") - .reduce({ (a, b) => a + ",\n" + b }) + .reduce((a, b) => a + ",\n" + b) s"""|"@context" : { |$lines | } diff --git a/integration/src/test/scala/org/knora/webapi/responders/v2/LoadOntologiesSpec.scala b/integration/src/test/scala/org/knora/webapi/responders/v2/LoadOntologiesSpec.scala index f501cdc733..9c38f8e26f 100644 --- a/integration/src/test/scala/org/knora/webapi/responders/v2/LoadOntologiesSpec.scala +++ b/integration/src/test/scala/org/knora/webapi/responders/v2/LoadOntologiesSpec.scala @@ -10,7 +10,6 @@ import zio.ZIO import org.knora.webapi.CoreSpec import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject -import org.knora.webapi.messages.util.KnoraSystemInstances import org.knora.webapi.messages.v2.responder.SuccessResponseV2 import org.knora.webapi.routing.UnsafeZioRun import org.knora.webapi.slice.ontology.repo.service.OntologyCache @@ -42,7 +41,7 @@ class LoadOntologiesSpec extends CoreSpec with ImplicitSender { ) UnsafeZioRun - .run(ZIO.serviceWithZIO[OntologyCache](_.loadOntologies(KnoraSystemInstances.Users.SystemUser))) + .run(ZIO.serviceWithZIO[OntologyCache](_.loadOntologies())) .toEither .map(_ => SuccessResponseV2("OK")) .left diff --git a/integration/src/test/scala/org/knora/webapi/responders/v2/OntologyResponderV2Spec.scala b/integration/src/test/scala/org/knora/webapi/responders/v2/OntologyResponderV2Spec.scala index 3601dd70dd..34bd8cbb27 100644 --- a/integration/src/test/scala/org/knora/webapi/responders/v2/OntologyResponderV2Spec.scala +++ b/integration/src/test/scala/org/knora/webapi/responders/v2/OntologyResponderV2Spec.scala @@ -24,7 +24,6 @@ import org.knora.webapi.messages.OntologyConstants.Rdfs import org.knora.webapi.messages.SmartIri import org.knora.webapi.messages.StringFormatter import org.knora.webapi.messages.store.triplestoremessages.* -import org.knora.webapi.messages.util.KnoraSystemInstances import org.knora.webapi.messages.util.rdf.SparqlSelectResult import org.knora.webapi.messages.v2.responder.CanDoResponseV2 import org.knora.webapi.messages.v2.responder.SuccessResponseV2 @@ -452,9 +451,7 @@ class OntologyResponderV2Spec extends CoreSpec with ImplicitSender { assert(!cachedMetadataResponse.ontologies.exists(_.ontologyIri == fooIri.get.toSmartIri)) // Reload the ontologies from the triplestore and check again. - UnsafeZioRun.runOrThrow( - ZIO.serviceWithZIO[OntologyCache](_.loadOntologies(KnoraSystemInstances.Users.SystemUser)), - ) + UnsafeZioRun.runOrThrow(ZIO.serviceWithZIO[OntologyCache](_.loadOntologies())) appActor ! OntologyMetadataGetByProjectRequestV2() @@ -795,7 +792,7 @@ class OntologyResponderV2Spec extends CoreSpec with ImplicitSender { // Reload the ontology cache and see if we get the same result. UnsafeZioRun.runOrThrow( - ZIO.serviceWithZIO[OntologyCache](_.loadOntologies(KnoraSystemInstances.Users.SystemUser)), + ZIO.serviceWithZIO[OntologyCache](_.loadOntologies()), ) appActor ! PropertiesGetRequestV2( @@ -899,7 +896,7 @@ class OntologyResponderV2Spec extends CoreSpec with ImplicitSender { // Reload the ontology cache and see if we get the same result. UnsafeZioRun.runOrThrow( - ZIO.serviceWithZIO[OntologyCache](_.loadOntologies(KnoraSystemInstances.Users.SystemUser)), + ZIO.serviceWithZIO[OntologyCache](_.loadOntologies()), ) appActor ! PropertiesGetRequestV2( @@ -3738,7 +3735,7 @@ class OntologyResponderV2Spec extends CoreSpec with ImplicitSender { // Reload the ontology cache and see if we get the same result. UnsafeZioRun.runOrThrow( - ZIO.serviceWithZIO[OntologyCache](_.loadOntologies(KnoraSystemInstances.Users.SystemUser)), + ZIO.serviceWithZIO[OntologyCache](_.loadOntologies()), ) appActor ! linkPropGetRequest diff --git a/integration/src/test/scala/org/knora/webapi/testcontainers/DspIngestTestContainer.scala b/integration/src/test/scala/org/knora/webapi/testcontainers/DspIngestTestContainer.scala index 01f4b55ec7..6785d49ce2 100644 --- a/integration/src/test/scala/org/knora/webapi/testcontainers/DspIngestTestContainer.scala +++ b/integration/src/test/scala/org/knora/webapi/testcontainers/DspIngestTestContainer.scala @@ -36,6 +36,7 @@ object DspIngestTestContainer { .withEnv("DB_JDBC_URL", "jdbc:sqlite:/tmp/ingest.sqlite") .withFileSystemBind(imagesVolume.hostPath, assetDir, BindMode.READ_WRITE) .withFileSystemBind(tempVolume.hostPath, tempDir, BindMode.READ_WRITE) + .withLogConsumer(frame => print("DSP-INGEST:" + frame.getUtf8String)) } val layer: URLayer[SharedVolumes.Volumes, DspIngestTestContainer] = diff --git a/integration/src/test/scala/org/knora/webapi/testservices/TestClientService.scala b/integration/src/test/scala/org/knora/webapi/testservices/TestClientService.scala index fc9e8cd0e9..4cc7f5c35d 100644 --- a/integration/src/test/scala/org/knora/webapi/testservices/TestClientService.scala +++ b/integration/src/test/scala/org/knora/webapi/testservices/TestClientService.scala @@ -5,8 +5,6 @@ package org.knora.webapi.testservices -import org.apache.http -import org.apache.http.entity.ContentType import org.apache.pekko import org.apache.pekko.actor.ActorSystem import sttp.capabilities.zio.ZioStreams @@ -17,51 +15,22 @@ import sttp.client3.httpclient.zio.HttpClientZioBackend import zio.* import zio.json.* import zio.json.ast.Json -import zio.nio.file.Files -import java.nio.file.Path import java.util.concurrent.TimeUnit import scala.concurrent.Await import scala.concurrent.ExecutionContext import scala.concurrent.duration.FiniteDuration import dsp.errors.AssertionException -import dsp.errors.BadRequestException -import dsp.errors.NotFoundException import org.knora.webapi.config.AppConfig -import org.knora.webapi.messages.store.sipimessages.SipiUploadResponse -import org.knora.webapi.messages.store.sipimessages.SipiUploadResponseEntry -import org.knora.webapi.messages.store.sipimessages.SipiUploadResponseJsonProtocol.* import org.knora.webapi.messages.store.triplestoremessages.TriplestoreJsonProtocol import org.knora.webapi.messages.util.rdf.JsonLDDocument import org.knora.webapi.messages.util.rdf.JsonLDUtil import org.knora.webapi.settings.KnoraDispatchers -import org.knora.webapi.store.iiif.errors.SipiException import pekko.http.scaladsl.client.RequestBuilding import pekko.http.scaladsl.unmarshalling.Unmarshal -/** - * Represents a file to be uploaded to the IIF Service. - * - * @param path the path of the file. - * @param mimeType the MIME type of the file. - */ -final case class FileToUpload( - path: Path, - mimeType: ContentType, - shortcode: String = "0001", -) - -/** - * Represents an image file to be uploaded to the IIF Service. - * - * @param fileToUpload the file to be uploaded. - * @param width the image's width in pixels. - * @param height the image's height in pixels. - */ -final case class InputFile(fileToUpload: FileToUpload, width: Int, height: Int) - final case class TestClientService( config: AppConfig, sttp: SttpBackend[Task, ZioStreams], @@ -69,8 +38,6 @@ final case class TestClientService( extends TriplestoreJsonProtocol with RequestBuilding { - private val ingestUrl = uri"${config.dspIngest.baseUrl}" - implicit val executionContext: ExecutionContext = system.dispatchers.lookup(KnoraDispatchers.KnoraBlockingDispatcher) case class TestClientTimeoutException(msg: String) extends Exception @@ -83,7 +50,7 @@ final case class TestClientService( * @param printFailure If true, the response body will be printed if the request fails. * This flag is intended to be used for debugging purposes only. * Since this is unsafe, it is false by default. - * It is unsafe because the the response body can only be unmarshalled (i.e. printed) to a string once. + * It is unsafe because the response body can only be unmarshalled (i.e. printed) to a string once. * It will fail if the test code is also unmarshalling the response. * @return the response. */ @@ -136,7 +103,7 @@ final case class TestClientService( } yield body /** - * Performs a http request and dosn't return the string (only error channel). + * Performs a http request and does not return the string (only error channel). */ def checkResponseOK(request: pekko.http.scaladsl.model.HttpRequest): Task[Unit] = getResponseString(request).unit @@ -157,47 +124,6 @@ final case class TestClientService( body <- getResponseString(request) json <- ZIO.succeed(JsonLDUtil.parseJsonLD(body)) } yield json - - /** - * Uploads a file to the Ingest service's "/projects/$shortcode/assets/ingest/$filename" route. - * - * @param loginToken the login token to be included in the request to Sipi. - * @param files the files to be uploaded. - * @return a [[SipiUploadResponse]] representing Sipi's response. - */ - def uploadToIngest(loginToken: String, filesToUpload: Seq[FileToUpload]): Task[SipiUploadResponse] = - ZIO - .foreach(filesToUpload) { file => - for { - contents <- Files.readAllBytes(zio.nio.file.Path.apply(file.path.toUri())) - url = ingestUrl.addPath("projects", file.shortcode, "assets", "ingest", file.path.getFileName.toString) - response <- - doSipiRequest( - quickRequest - .post(url) - .header("Content-Type", file.mimeType.toString) - .header("Authorization", s"Bearer $loginToken") - .body(contents.toArray), - ) - json <- ZIO.fromEither(response.fromJson[SipiUploadResponseEntry]).mapError(Throwable(_)) - } yield json - } - .map(responses => SipiUploadResponse(responses.toList)) - - private def doSipiRequest[T](request: Request[String, Any]): Task[String] = - sttp.send(request).flatMap { response => - if (response.isSuccess) { - ZIO.succeed(response.body) - } else { - if (response.code.code == 404) { - ZIO.fail(NotFoundException(response.body)) - } else if (response.isClientError) { - ZIO.fail(BadRequestException(s"Sipi responded with HTTP status code ${response.code.code}: ${response.body}")) - } else { - ZIO.fail(SipiException(s"Sipi responded with HTTP status code ${response.code.code}: ${response.body}")) - } - } - } } object TestClientService { diff --git a/integration/src/test/scala/org/knora/webapi/testservices/TestDspIngestClient.scala b/integration/src/test/scala/org/knora/webapi/testservices/TestDspIngestClient.scala new file mode 100644 index 0000000000..4a495646f7 --- /dev/null +++ b/integration/src/test/scala/org/knora/webapi/testservices/TestDspIngestClient.scala @@ -0,0 +1,54 @@ +/* + * Copyright © 2021 - 2025 Swiss National Data and Service Center for the Humanities and/or DaSCH Service Platform contributors. + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.knora.webapi.testservices + +import sttp.capabilities.zio.ZioStreams +import sttp.client3 +import sttp.client3.* +import sttp.client3.SttpBackend +import zio.* +import zio.json.* +import zio.nio.file.Files +import zio.nio.file.Path + +import org.knora.webapi.config.DspIngestConfig +import org.knora.webapi.slice.admin.domain.model.KnoraProject.Shortcode +import org.knora.webapi.slice.infrastructure.JwtService +import org.knora.webapi.testservices.TestDspIngestClient.* + +final case class TestDspIngestClient( + config: DspIngestConfig, + sttp: SttpBackend[Task, ZioStreams], + jwtService: JwtService, +) { + + private val ingestUrl = uri"${config.baseUrl}" + + def uploadFile(file: java.nio.file.Path, shortcode: Shortcode = Shortcode.unsafeFrom("0001")): Task[UploadedFile] = + for { + contents <- Files.readAllBytes(Path.fromJava(file)) + filename = file.getFileName.toString + loginToken <- jwtService.createJwtForDspIngest().map(_.jwtString) + url = ingestUrl.addPath("projects", shortcode.value, "assets", "ingest", file.getFileName.toString) + request = quickRequest.post(url).header("Authorization", s"Bearer $loginToken").body(contents.toArray) + responseBody <- + sttp + .send(request) + .filterOrElseWith(_.is200)(response => + ZIO.fail(Exception(s"Upload failed: $filename, ${response.code.code}: ${response.body}")), + ) + .map(_.body) + json <- ZIO.fromEither(responseBody.fromJson[UploadedFile]).mapError(Throwable(_)) + } yield json +} + +object TestDspIngestClient { + final case class UploadedFile(originalFilename: String, internalFilename: String) + object UploadedFile { + implicit val decoder: JsonDecoder[UploadedFile] = DeriveJsonDecoder.gen[UploadedFile] + } + val layer = ZLayer.derive[TestDspIngestClient] +} diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 0f6f205bdd..cfc71fe194 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -16,43 +16,40 @@ object Dependencies { val ScalaVersion = "3.3.4" - val PekkoActorVersion = "1.1.2" + val PekkoActorVersion = "1.1.3" val PekkoHttpVersion = "1.1.0" val MonocleVersion = "3.3.0" - // rdf and graph libraries - // topbraid/shacl is not yet compatible with jena 5 so we need to use jena 4 for now - // see: https://github.com/TopQuadrant/shacl/pull/177 - val JenaVersion = "4.10.0" val Rdf4jVersion = "5.1.0" - val TopbraidShaclVersion = "1.4.3" + val TopbraidShaclVersion = "1.4.4" + val JenaVersion = "5.2.0" // should be aligned with the version topbraid-shacl uses - val ZioConfigVersion = "4.0.2" + val ZioConfigVersion = "4.0.3" val ZioLoggingVersion = "2.4.0" val ZioNioVersion = "2.0.2" val ZioMetricsConnectorsVersion = "2.3.1" - val ZioPreludeVersion = "1.0.0-RC35" + val ZioPreludeVersion = "1.0.0-RC36" val ZioSchemaVersion = "0.2.0" - val ZioVersion = "2.1.13" + val ZioVersion = "2.1.14" // ZIO val zio = "dev.zio" %% "zio" % ZioVersion val zioConfig = "dev.zio" %% "zio-config" % ZioConfigVersion val zioConfigMagnolia = "dev.zio" %% "zio-config-magnolia" % ZioConfigVersion val zioConfigTypesafe = "dev.zio" %% "zio-config-typesafe" % ZioConfigVersion - val zioJson = "dev.zio" %% "zio-json" % "0.7.3" + val zioJson = "dev.zio" %% "zio-json" % "0.7.4" val zioLogging = "dev.zio" %% "zio-logging" % ZioLoggingVersion val zioLoggingSlf4jBridge = "dev.zio" %% "zio-logging-slf4j2-bridge" % ZioLoggingVersion val zioNio = "dev.zio" %% "zio-nio" % ZioNioVersion val zioMacros = "dev.zio" %% "zio-macros" % ZioVersion val zioPrelude = "dev.zio" %% "zio-prelude" % ZioPreludeVersion - val zioSttp = "com.softwaremill.sttp.client3" %% "zio" % "3.10.1" + val zioSttp = "com.softwaremill.sttp.client3" %% "zio" % "3.10.2" // refined val refined = Seq( - "eu.timepit" %% "refined" % "0.11.2", - "dev.zio" %% "zio-json-interop-refined" % "0.7.3", + "eu.timepit" %% "refined" % "0.11.3", + "dev.zio" %% "zio-json-interop-refined" % "0.7.4", ) // monocle @@ -75,6 +72,7 @@ object Dependencies { val pekkoStream = "org.apache.pekko" %% "pekko-stream" % PekkoActorVersion // rdf and graph libraries + val jenaCore = "org.apache.jena" % "jena-core" % JenaVersion val jenaText = "org.apache.jena" % "jena-text" % JenaVersion val rdf4jClient = "org.eclipse.rdf4j" % "rdf4j-client" % Rdf4jVersion val rdf4jShacl = "org.eclipse.rdf4j" % "rdf4j-shacl" % Rdf4jVersion @@ -96,11 +94,11 @@ object Dependencies { val jwtSprayJson = "com.github.jwt-scala" %% "jwt-zio-json" % "10.0.1" // jwtSprayJson -> 9.0.2 is the latest version that's compatible with spray-json; if it wasn't for spray, this would be Scala 3 compatible val springSecurityCore = - "org.springframework.security" % "spring-security-core" % "6.3.5" exclude ( + "org.springframework.security" % "spring-security-core" % "6.3.6" exclude ( "commons-logging", "commons-logging", ) exclude ("org.springframework", "spring-aop") - val bouncyCastle = "org.bouncycastle" % "bcprov-jdk15to18" % "1.79" + val bouncyCastle = "org.bouncycastle" % "bcprov-jdk15to18" % "1.80" // caching val ehcache = "org.ehcache" % "ehcache" % "3.10.8" @@ -129,7 +127,7 @@ object Dependencies { // found/added by the plugin but deleted anyway val commonsLang3 = "org.apache.commons" % "commons-lang3" % "3.17.0" - val tapirVersion = "1.11.10" + val tapirVersion = "1.11.12" val tapir = Seq( "com.softwaremill.sttp.tapir" %% "tapir-pekko-http-server" % tapirVersion, diff --git a/project/build.properties b/project/build.properties index e88a0d817d..73df629ac1 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.10.6 +sbt.version=1.10.7 diff --git a/project/plugins.sbt b/project/plugins.sbt index 88ef40922d..09654a1e25 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -2,13 +2,13 @@ resolvers ++= Seq( Resolver.typesafeRepo("releases"), ) -addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.10.4") +addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.11.0") addSbtPlugin("io.kamon" % "sbt-aspectj-runner" % "1.1.2") addSbtPlugin("org.playframework.twirl" % "sbt-twirl" % "2.0.7") addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.3.0") addSbtPlugin("com.github.sbt" % "sbt-javaagent" % "0.1.8") -addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.2.2") +addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.3.0") addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.12.0") -addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.2") -addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.12.1") +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.3") +addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.14.0") addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.10.0") diff --git a/test_data/generated_test_data/ontologyR2RV2/knoraApiDateValue.jsonld b/test_data/generated_test_data/ontologyR2RV2/knoraApiDateValue.jsonld index 47184c4cb9..642fb4a30f 100644 --- a/test_data/generated_test_data/ontologyR2RV2/knoraApiDateValue.jsonld +++ b/test_data/generated_test_data/ontologyR2RV2/knoraApiDateValue.jsonld @@ -3,6 +3,7 @@ "@graph": [ { "knora-api:isValueClass": true, + "rdfs:label": "date value", "rdfs:subClassOf": [ { "@id": "knora-api:DateBase" diff --git a/test_data/generated_test_data/ontologyR2RV2/knoraApiOntologySimple.jsonld b/test_data/generated_test_data/ontologyR2RV2/knoraApiOntologySimple.jsonld index 0cc263a9db..640cef671d 100644 --- a/test_data/generated_test_data/ontologyR2RV2/knoraApiOntologySimple.jsonld +++ b/test_data/generated_test_data/ontologyR2RV2/knoraApiOntologySimple.jsonld @@ -900,8 +900,7 @@ "@id": "knora-api:Segment" }, { - "@id": "knora-api:StillImageAbstractFileValue", - "@type": "owl:Class", + "rdfs:label": "still image abstract file value", "rdfs:subClassOf": [ { "@type": "owl:Restriction", @@ -925,7 +924,9 @@ "owl:maxCardinality": 1 } ], - "rdfs:comment": "A file containing a two-dimensional still image" + "rdfs:comment": "A file containing a two-dimensional still image", + "@type": "owl:Class", + "@id": "knora-api:StillImageAbstractFileValue" }, { "rdfs:label": "Representation (Image)", @@ -1221,14 +1222,15 @@ "@id": "knora-api:error" }, { - "@id": "knora-api:externalUrl", + "rdfs:label": "external URL", "@type": "owl:DatatypeProperty", "knora-api:subjectType": { "@id": "knora-api:File" }, "knora-api:objectType": { "@id": "xsd:anyURI" - } + }, + "@id": "knora-api:externalUrl" }, { "rdfs:label": "has zip", @@ -1291,12 +1293,13 @@ "@id": "knora-api:hasComment" }, { - "@id": "knora-api:hasCopyrightAttribution", + "rdfs:label": "copyright attribution", + "rdfs:comment": "The copyright statement that gives credit to the original author.", "@type": "owl:DatatypeProperty", "knora-api:objectType": { "@id": "xsd:string" }, - "rdfs:comment": "The copyright statement that gives credit to the original author." + "@id": "knora-api:hasCopyrightAttribution" }, { "rdfs:label": "has 3D-file", @@ -1426,20 +1429,22 @@ "@id": "knora-api:hasKeyword" }, { - "@id": "knora-api:hasLicenseText", + "rdfs:label": "license text", + "rdfs:comment": "Specifies the terms under which a work can be used. This statement may be a reference to a well-known license, such as Creative Commons (e.g. 'CC BY-SA') or a custom license.", "@type": "owl:DatatypeProperty", "knora-api:objectType": { "@id": "xsd:string" }, - "rdfs:comment": "Specifies the terms under which a work can be used. This statement may be a reference to a well-known license, such as Creative Commons (e.g. 'CC BY-SA') or a custom license." + "@id": "knora-api:hasLicenseText" }, { - "@id": "knora-api:hasLicenseUri", + "rdfs:label": "license URI", + "rdfs:comment": "Canonical link to license.", "@type": "owl:DatatypeProperty", "knora-api:objectType": { "@id": "xsd:anyUri" }, - "rdfs:comment": "Canonical link to license." + "@id": "knora-api:hasLicenseUri" }, { "rdfs:label": "has Link to", @@ -1650,6 +1655,7 @@ "@id": "knora-api:isAudioSegmentOf" }, { + "rdfs:label": "is main resource", "rdfs:comment": "Indicates if the given resource is the main resource of a request or a resource referred to by a link property.", "@type": "owl:DatatypeProperty", "knora-api:subjectType": { @@ -1782,14 +1788,15 @@ "@id": "knora-api:relatesTo" }, { - "@id": "knora-api:resourceIcon", + "rdfs:label": "resource icon", "@type": "owl:DatatypeProperty", "knora-api:subjectType": { "@id": "owl:Class" }, "knora-api:objectType": { "@id": "xsd:string" - } + }, + "@id": "knora-api:resourceIcon" }, { "rdfs:label": "Resource property", diff --git a/test_data/generated_test_data/ontologyR2RV2/knoraApiOntologyWithValueObjects.jsonld b/test_data/generated_test_data/ontologyR2RV2/knoraApiOntologyWithValueObjects.jsonld index 6e2fe91bcb..60de721eea 100644 --- a/test_data/generated_test_data/ontologyR2RV2/knoraApiOntologyWithValueObjects.jsonld +++ b/test_data/generated_test_data/ontologyR2RV2/knoraApiOntologyWithValueObjects.jsonld @@ -172,8 +172,8 @@ "@id": "knora-api:Annotation" }, { - "@id": "knora-api:ArchiveFileValue", - "@type": "owl:Class", + "knora-api:isValueClass": true, + "rdfs:label": "archive file value", "rdfs:subClassOf": [ { "@id": "knora-api:FileValue" @@ -323,7 +323,8 @@ "knora-api:isInherited": true } ], - "knora-api:isValueClass": true + "@type": "owl:Class", + "@id": "knora-api:ArchiveFileValue" }, { "knora-api:isResourceClass": true, @@ -481,6 +482,7 @@ }, { "knora-api:isValueClass": true, + "rdfs:label": "audio file value", "rdfs:subClassOf": [ { "@id": "knora-api:FileValue" @@ -1029,6 +1031,7 @@ }, { "knora-api:isValueClass": true, + "rdfs:label": "boolean value", "rdfs:subClassOf": [ { "@id": "knora-api:BooleanBase" @@ -1167,10 +1170,12 @@ }, "owl:cardinality": 1 } - ] + ], + "rdfs:label": "color base" }, { "knora-api:isValueClass": true, + "rdfs:label": "color value", "rdfs:subClassOf": [ { "@id": "knora-api:ColorBase" @@ -1303,6 +1308,7 @@ }, { "knora-api:isValueClass": true, + "rdfs:label": "3D file value", "rdfs:subClassOf": [ { "@id": "knora-api:FileValue" @@ -1681,10 +1687,12 @@ }, "owl:cardinality": 1 } - ] + ], + "rdfs:label": "date base" }, { "knora-api:isValueClass": true, + "rdfs:label": "date value", "rdfs:subClassOf": [ { "@id": "knora-api:DateBase" @@ -1887,10 +1895,12 @@ }, "owl:cardinality": 1 } - ] + ], + "rdfs:label": "decimal base" }, { "knora-api:isValueClass": true, + "rdfs:label": "decimal value", "rdfs:subClassOf": [ { "@id": "knora-api:DecimalBase" @@ -2280,8 +2290,8 @@ "@id": "knora-api:DeletedValue" }, { - "@id": "knora-api:DocumentFileValue", - "@type": "owl:Class", + "knora-api:isValueClass": true, + "rdfs:label": "document file value", "rdfs:subClassOf": [ { "@id": "knora-api:FileValue" @@ -2438,7 +2448,8 @@ "knora-api:isInherited": true } ], - "knora-api:isValueClass": true + "@type": "owl:Class", + "@id": "knora-api:DocumentFileValue" }, { "knora-api:isResourceClass": true, @@ -2595,8 +2606,8 @@ "@id": "knora-api:DocumentRepresentation" }, { - "@id": "knora-api:FileValue", - "@type": "owl:Class", + "knora-api:isValueClass": true, + "rdfs:label": "file value", "rdfs:subClassOf": [ { "@id": "knora-api:Value" @@ -2741,7 +2752,8 @@ "knora-api:isInherited": true } ], - "knora-api:isValueClass": true + "@type": "owl:Class", + "@id": "knora-api:FileValue" }, { "@id": "knora-api:FormattedText", @@ -2751,6 +2763,7 @@ }, { "knora-api:isValueClass": true, + "rdfs:label": "geometry value", "rdfs:subClassOf": [ { "@id": "knora-api:Value" @@ -2872,8 +2885,8 @@ "@id": "knora-api:GeomValue" }, { - "@id": "knora-api:GeonameValue", - "@type": "owl:Class", + "knora-api:isValueClass": true, + "rdfs:label": "geoname value", "rdfs:subClassOf": [ { "@id": "knora-api:Value" @@ -2990,7 +3003,8 @@ "knora-api:isInherited": true } ], - "knora-api:isValueClass": true + "@type": "owl:Class", + "@id": "knora-api:GeonameValue" }, { "@id": "knora-api:IntBase", @@ -3006,10 +3020,12 @@ }, "owl:cardinality": 1 } - ] + ], + "rdfs:label": "integer base" }, { "knora-api:isValueClass": true, + "rdfs:label": "integer value", "rdfs:subClassOf": [ { "@id": "knora-api:IntBase" @@ -3155,10 +3171,12 @@ }, "owl:cardinality": 1 } - ] + ], + "rdfs:label": "interval base" }, { "knora-api:isValueClass": true, + "rdfs:label": "interval value", "rdfs:subClassOf": [ { "@id": "knora-api:IntervalBase" @@ -3464,6 +3482,7 @@ }, { "knora-api:isValueClass": true, + "rdfs:label": "link value", "rdfs:subClassOf": [ { "@id": "knora-api:Value" @@ -3609,8 +3628,7 @@ "@id": "knora-api:LinkValue" }, { - "@id": "knora-api:ListNode", - "@type": "owl:Class", + "rdfs:label": "list node", "rdfs:subClassOf": [ { "@type": "owl:Restriction", @@ -3627,11 +3645,13 @@ "owl:minCardinality": 1 } ], - "rdfs:comment": "Represents a flat or hierarchical list" + "rdfs:comment": "Represents a flat or hierarchical list", + "@type": "owl:Class", + "@id": "knora-api:ListNode" }, { - "@id": "knora-api:ListValue", - "@type": "owl:Class", + "knora-api:isValueClass": true, + "rdfs:label": "list value", "rdfs:subClassOf": [ { "@id": "knora-api:Value" @@ -3748,10 +3768,12 @@ "knora-api:isInherited": true } ], - "knora-api:isValueClass": true + "@type": "owl:Class", + "@id": "knora-api:ListValue" }, { "knora-api:isValueClass": true, + "rdfs:label": "moving image file value", "rdfs:subClassOf": [ { "@id": "knora-api:FileValue" @@ -4749,6 +4771,7 @@ "@id": "knora-api:Segment" }, { + "rdfs:label": "standoff boolean tag", "knora-api:isStandoffClass": true, "rdfs:subClassOf": [ { @@ -4851,6 +4874,7 @@ "@id": "knora-api:StandoffBooleanTag" }, { + "rdfs:label": "standoff color tag", "knora-api:isStandoffClass": true, "rdfs:subClassOf": [ { @@ -4953,6 +4977,7 @@ "@id": "knora-api:StandoffColorTag" }, { + "rdfs:label": "standoff data type tag", "knora-api:isStandoffClass": true, "rdfs:subClassOf": [ { @@ -5044,6 +5069,7 @@ "@id": "knora-api:StandoffDataTypeTag" }, { + "rdfs:label": "standoff date tag", "knora-api:isStandoffClass": true, "rdfs:subClassOf": [ { @@ -5210,6 +5236,7 @@ "@id": "knora-api:StandoffDateTag" }, { + "rdfs:label": "standoff decimal tag", "knora-api:isStandoffClass": true, "rdfs:subClassOf": [ { @@ -5312,6 +5339,7 @@ "@id": "knora-api:StandoffDecimalTag" }, { + "rdfs:label": "standoff integer tag", "knora-api:isStandoffClass": true, "rdfs:subClassOf": [ { @@ -5414,6 +5442,7 @@ "@id": "knora-api:StandoffIntegerTag" }, { + "rdfs:label": "standoff internal reference tag", "knora-api:isStandoffClass": true, "rdfs:subClassOf": [ { @@ -5515,6 +5544,7 @@ "@id": "knora-api:StandoffInternalReferenceTag" }, { + "rdfs:label": "standoff interval tag", "knora-api:isStandoffClass": true, "rdfs:subClassOf": [ { @@ -5625,6 +5655,7 @@ "@id": "knora-api:StandoffIntervalTag" }, { + "rdfs:label": "standoff link tag", "knora-api:isStandoffClass": true, "rdfs:subClassOf": [ { @@ -5723,6 +5754,7 @@ "@id": "knora-api:StandoffLinkTag" }, { + "rdfs:label": "standoff tag", "knora-api:isStandoffClass": true, "rdfs:subClassOf": [ { @@ -5801,6 +5833,7 @@ "@id": "knora-api:StandoffTag" }, { + "rdfs:label": "standoff time tag", "knora-api:isStandoffClass": true, "rdfs:subClassOf": [ { @@ -5903,6 +5936,7 @@ "@id": "knora-api:StandoffTimeTag" }, { + "rdfs:label": "standoff URI tag", "knora-api:isStandoffClass": true, "rdfs:subClassOf": [ { @@ -6006,6 +6040,7 @@ }, { "knora-api:isValueClass": true, + "rdfs:label": "still image abstract file value", "rdfs:subClassOf": [ { "@id": "knora-api:FileValue" @@ -6161,6 +6196,7 @@ }, { "knora-api:isValueClass": true, + "rdfs:label": "still image external file value", "rdfs:subClassOf": [ { "@id": "knora-api:StillImageAbstractFileValue" @@ -6337,6 +6373,7 @@ }, { "knora-api:isValueClass": true, + "rdfs:label": "still image file value", "rdfs:subClassOf": [ { "@id": "knora-api:StillImageAbstractFileValue" @@ -6671,6 +6708,7 @@ }, { "knora-api:isValueClass": true, + "rdfs:label": "Text file value", "rdfs:subClassOf": [ { "@id": "knora-api:FileValue" @@ -6980,8 +7018,8 @@ "@id": "knora-api:TextRepresentation" }, { - "@id": "knora-api:TextValue", - "@type": "owl:Class", + "knora-api:isValueClass": true, + "rdfs:label": "Text Value", "rdfs:subClassOf": [ { "@id": "knora-api:Value" @@ -7147,7 +7185,8 @@ "knora-api:isInherited": true } ], - "knora-api:isValueClass": true + "@type": "owl:Class", + "@id": "knora-api:TextValue" }, { "@id": "knora-api:TextValueType", @@ -7169,10 +7208,12 @@ }, "owl:cardinality": 1 } - ] + ], + "rdfs:label": "time base" }, { "knora-api:isValueClass": true, + "rdfs:label": "time value", "rdfs:subClassOf": [ { "@id": "knora-api:TimeBase" @@ -7323,10 +7364,12 @@ }, "owl:cardinality": 1 } - ] + ], + "rdfs:label": "URI base" }, { "knora-api:isValueClass": true, + "rdfs:label": "URI value", "rdfs:subClassOf": [ { "@id": "knora-api:UriBase" @@ -7453,6 +7496,7 @@ }, { "knora-api:isValueClass": true, + "rdfs:label": "Value", "rdfs:subClassOf": [ { "@id": "knora-api:ValueBase" @@ -8019,6 +8063,7 @@ "rdfs:comment": "Represents the literal RGB value of a ColorValue." }, { + "rdfs:label": "creation date", "@type": "owl:DatatypeProperty", "knora-api:objectType": { "@id": "xsd:dateTimeStamp" @@ -8180,28 +8225,31 @@ "rdfs:comment": "Represents the literal decimal value of a DecimalValue." }, { - "@id": "knora-api:deleteComment", + "rdfs:label": "delete comment", + "rdfs:comment": "A comment explaining why a resource or value was marked as deleted", "@type": "owl:DatatypeProperty", "knora-api:objectType": { "@id": "xsd:string" }, - "rdfs:comment": "A comment explaining why a resource or value was marked as deleted" + "@id": "knora-api:deleteComment" }, { - "@id": "knora-api:deleteDate", + "rdfs:label": "delete date", + "rdfs:comment": "Indicates when a resource or value was deleted", "@type": "owl:DatatypeProperty", "knora-api:objectType": { "@id": "xsd:dateTimeStamp" }, - "rdfs:comment": "Indicates when a resource or value was deleted" + "@id": "knora-api:deleteDate" }, { - "@id": "knora-api:deletedBy", + "rdfs:label": "deleted by", + "rdfs:comment": "Indicates who deleted a resource or value", "@type": "owl:ObjectProperty", "knora-api:objectType": { "@id": "xsd:anyURI" }, - "rdfs:comment": "Indicates who deleted a resource or value" + "@id": "knora-api:deletedBy" }, { "rdfs:label": "error", @@ -8213,6 +8261,7 @@ "@id": "knora-api:error" }, { + "rdfs:label": "external URL", "rdfs:subPropertyOf": { "@id": "knora-api:valueHas" }, @@ -8612,7 +8661,8 @@ "@type": "owl:DatatypeProperty", "knora-api:objectType": { "@id": "xsd:string" - } + }, + "rdfs:label": "has permissions" }, { "rdfs:label": "has Representation", @@ -8634,6 +8684,7 @@ }, { "knora-api:isLinkValueProperty": true, + "rdfs:label": "has Representation Value", "rdfs:subPropertyOf": { "@id": "knora-api:hasLinkToValue" }, @@ -8809,6 +8860,7 @@ "rdfs:comment": "Indicates the title of a resource" }, { + "rdfs:label": "has value", "rdfs:subPropertyOf": { "@id": "knora-api:resourceProperty" }, @@ -8886,6 +8938,7 @@ }, { "knora-api:isLinkValueProperty": true, + "rdfs:label": "is Annotation of", "rdfs:subPropertyOf": { "@id": "knora-api:hasLinkToValue" }, @@ -8920,6 +8973,7 @@ }, { "knora-api:isLinkValueProperty": true, + "rdfs:label": "Segment of", "rdfs:subPropertyOf": { "@id": "knora-api:isSegmentOfValue" }, @@ -8944,12 +8998,13 @@ "@id": "knora-api:isBuiltIn" }, { - "@id": "knora-api:isDeleted", + "rdfs:label": "is deleted", + "rdfs:comment": "Exists and is true if the resource has been deleted", "@type": "owl:DatatypeProperty", "knora-api:objectType": { "@id": "xsd:boolean" }, - "rdfs:comment": "Exists and is true if the resource has been deleted" + "@id": "knora-api:isDeleted" }, { "rdfs:label": "is editable", @@ -9000,6 +9055,7 @@ "rdfs:comment": "Indicates whether a property points to a link value (reification)" }, { + "rdfs:label": "is main resource", "@type": "owl:DatatypeProperty", "knora-api:objectType": { "@id": "xsd:boolean" @@ -9030,6 +9086,7 @@ }, { "knora-api:isLinkValueProperty": true, + "rdfs:label": "is part of", "rdfs:subPropertyOf": { "@id": "knora-api:hasLinkToValue" }, @@ -9120,6 +9177,7 @@ }, { "knora-api:isLinkValueProperty": true, + "rdfs:label": "Segment of", "rdfs:subPropertyOf": { "@id": "knora-api:hasLinkToValue" }, @@ -9154,6 +9212,7 @@ }, { "knora-api:isLinkValueProperty": true, + "rdfs:label": "is sequence of", "rdfs:subPropertyOf": { "@id": "knora-api:hasLinkToValue" }, @@ -9222,6 +9281,7 @@ }, { "knora-api:isLinkValueProperty": true, + "rdfs:label": "Segment of", "rdfs:subPropertyOf": { "@id": "knora-api:isSegmentOfValue" }, @@ -9241,7 +9301,8 @@ "@type": "owl:DatatypeProperty", "knora-api:objectType": { "@id": "xsd:dateTimeStamp" - } + }, + "rdfs:label": "last modification date" }, { "rdfs:label": "Link value has source", @@ -9370,6 +9431,7 @@ "@id": "knora-api:ontologyName" }, { + "rdfs:label": "page count", "rdfs:subPropertyOf": { "@id": "knora-api:valueHas" }, @@ -9427,16 +9489,18 @@ "rdfs:comment": "Indicates that this resource relates to another resource" }, { - "@id": "knora-api:resourceIcon", - "@type": "owl:DatatypeProperty", + "rdfs:label": "resource icon", "knora-api:subjectType": { "@id": "owl:Class" }, + "@type": "owl:DatatypeProperty", "knora-api:objectType": { "@id": "xsd:string" - } + }, + "@id": "knora-api:resourceIcon" }, { + "rdfs:label": "resource property", "knora-api:isResourceProperty": true, "@type": "owl:ObjectProperty", "@id": "knora-api:resourceProperty", @@ -9469,34 +9533,37 @@ "@id": "knora-api:seqnum" }, { - "@id": "knora-api:standoffTagHasEnd", - "@type": "owl:DatatypeProperty", + "rdfs:label": "standoff tag has end", "knora-api:subjectType": { "@id": "knora-api:StandoffTag" }, + "@type": "owl:DatatypeProperty", "knora-api:objectType": { "@id": "xsd:integer" - } + }, + "@id": "knora-api:standoffTagHasEnd" }, { - "@id": "knora-api:standoffTagHasEndIndex", - "@type": "owl:DatatypeProperty", + "rdfs:label": "standoff tag has end index", "knora-api:subjectType": { "@id": "knora-api:StandoffTag" }, + "@type": "owl:DatatypeProperty", "knora-api:objectType": { "@id": "xsd:integer" - } + }, + "@id": "knora-api:standoffTagHasEndIndex" }, { - "@id": "knora-api:standoffTagHasEndParent", - "@type": "owl:ObjectProperty", + "rdfs:label": "standoff tag has end parent", "knora-api:subjectType": { "@id": "knora-api:StandoffTag" }, + "@type": "owl:ObjectProperty", "knora-api:objectType": { "@id": "knora-api:StandoffTag" - } + }, + "@id": "knora-api:standoffTagHasEndParent" }, { "rdfs:label": "standoff tag has end parent index", @@ -9511,69 +9578,76 @@ "rdfs:comment": "The next knora-api:standoffTagHasStartIndex of the end parent tag of a standoff tag." }, { - "@id": "knora-api:standoffTagHasInternalReference", - "@type": "owl:ObjectProperty", + "rdfs:label": "standoff tag has internal reference", "knora-api:subjectType": { "@id": "knora-api:StandoffInternalReferenceTag" }, + "@type": "owl:ObjectProperty", "knora-api:objectType": { "@id": "knora-api:StandoffTag" - } + }, + "@id": "knora-api:standoffTagHasInternalReference" }, { - "@id": "knora-api:standoffTagHasLink", - "@type": "owl:ObjectProperty", + "rdfs:label": "standoff tag has link", "knora-api:subjectType": { "@id": "knora-api:StandoffLinkTag" }, + "@type": "owl:ObjectProperty", "knora-api:objectType": { "@id": "knora-api:Resource" - } + }, + "@id": "knora-api:standoffTagHasLink" }, { - "@id": "knora-api:standoffTagHasOriginalXMLID", - "@type": "owl:DatatypeProperty", + "rdfs:label": "standoff tag has original XML ID", "knora-api:subjectType": { "@id": "knora-api:StandoffTag" }, + "@type": "owl:DatatypeProperty", "knora-api:objectType": { "@id": "xsd:string" - } + }, + "@id": "knora-api:standoffTagHasOriginalXMLID" }, { - "@id": "knora-api:standoffTagHasStart", - "@type": "owl:DatatypeProperty", + "rdfs:label": "standoff tag has start", "knora-api:subjectType": { "@id": "knora-api:StandoffTag" }, + "@type": "owl:DatatypeProperty", "knora-api:objectType": { "@id": "xsd:integer" - } + }, + "@id": "knora-api:standoffTagHasStart" }, { - "@id": "knora-api:standoffTagHasStartAncestor", + "rdfs:label": "standoff tag has start ancestor", + "knora-api:subjectType": { + "@id": "knora-api:StandoffTag" + }, "@type": [ "owl:ObjectProperty", "owl:TransitiveProperty" ], - "knora-api:subjectType": { - "@id": "knora-api:StandoffTag" - }, "knora-api:objectType": { "@id": "knora-api:StandoffTag" - } + }, + "@id": "knora-api:standoffTagHasStartAncestor" }, { - "@id": "knora-api:standoffTagHasStartIndex", - "@type": "owl:DatatypeProperty", + "rdfs:label": "standoff tag has start index", "knora-api:subjectType": { "@id": "knora-api:StandoffTag" }, + "@type": "owl:DatatypeProperty", "knora-api:objectType": { "@id": "xsd:integer" - } + }, + "@id": "knora-api:standoffTagHasStartIndex" }, { + "rdfs:label": "standoff tag has start parent", "rdfs:subPropertyOf": { "@id": "knora-api:standoffTagHasStartAncestor" }, @@ -9599,14 +9673,15 @@ "rdfs:comment": "The next knora-api:standoffTagHasStartIndex of the start parent tag of a standoff tag." }, { - "@id": "knora-api:standoffTagHasUUID", - "@type": "owl:DatatypeProperty", + "rdfs:label": "standoff tag has UUID", "knora-api:subjectType": { "@id": "knora-api:StandoffTag" }, + "@type": "owl:DatatypeProperty", "knora-api:objectType": { "@id": "xsd:string" - } + }, + "@id": "knora-api:standoffTagHasUUID" }, { "rdfs:label": "Still image file value has X dimension", @@ -9780,6 +9855,7 @@ "rdfs:comment": "Standoff markup attached to a text value." }, { + "rdfs:label": "value has timestamp", "rdfs:subPropertyOf": { "@id": "knora-api:valueHas" }, @@ -9828,6 +9904,7 @@ "rdfs:comment": "A plain string representation of a value" }, { + "rdfs:label": "value creation date", "rdfs:subPropertyOf": { "@id": "knora-api:valueHas" }, @@ -9845,9 +9922,11 @@ "@type": "rdf:Property", "knora-api:subjectType": { "@id": "knora-api:ValueBase" - } + }, + "rdfs:label": "value has" }, { + "rdfs:label": "value has comment", "rdfs:subPropertyOf": { "@id": "knora-api:valueHas" }, @@ -9862,6 +9941,7 @@ "rdfs:comment": "A comment on a value" }, { + "rdfs:label": "value has UUID", "rdfs:subPropertyOf": { "@id": "knora-api:valueHas" }, diff --git a/test_data/generated_test_data/ontologyR2RV2/standoffOntologyWithValueObjects.jsonld b/test_data/generated_test_data/ontologyR2RV2/standoffOntologyWithValueObjects.jsonld index 0ee0e8d002..759efa731f 100644 --- a/test_data/generated_test_data/ontologyR2RV2/standoffOntologyWithValueObjects.jsonld +++ b/test_data/generated_test_data/ontologyR2RV2/standoffOntologyWithValueObjects.jsonld @@ -456,6 +456,104 @@ "@type": "owl:Class", "@id": "standoff:StandoffCodeTag" }, + { + "knora-api:isStandoffClass": true, + "rdfs:subClassOf": [ + { + "@id": "standoff:StandoffStructuralTag" + }, + { + "@type": "owl:Restriction", + "owl:onProperty": { + "@id": "knora-api:standoffTagHasEnd" + }, + "owl:cardinality": 1, + "knora-api:isInherited": true + }, + { + "@type": "owl:Restriction", + "owl:onProperty": { + "@id": "knora-api:standoffTagHasEndIndex" + }, + "owl:maxCardinality": 1, + "knora-api:isInherited": true + }, + { + "@type": "owl:Restriction", + "owl:onProperty": { + "@id": "knora-api:standoffTagHasEndParent" + }, + "owl:maxCardinality": 1, + "knora-api:isInherited": true + }, + { + "@type": "owl:Restriction", + "owl:onProperty": { + "@id": "knora-api:standoffTagHasEndParentIndex" + }, + "owl:maxCardinality": 1, + "knora-api:isInherited": true + }, + { + "@type": "owl:Restriction", + "owl:onProperty": { + "@id": "knora-api:standoffTagHasOriginalXMLID" + }, + "owl:maxCardinality": 1, + "knora-api:isInherited": true + }, + { + "@type": "owl:Restriction", + "owl:onProperty": { + "@id": "knora-api:standoffTagHasStart" + }, + "owl:cardinality": 1, + "knora-api:isInherited": true + }, + { + "@type": "owl:Restriction", + "owl:onProperty": { + "@id": "knora-api:standoffTagHasStartIndex" + }, + "owl:cardinality": 1, + "knora-api:isInherited": true + }, + { + "@type": "owl:Restriction", + "owl:onProperty": { + "@id": "knora-api:standoffTagHasStartParent" + }, + "owl:maxCardinality": 1, + "knora-api:isInherited": true + }, + { + "@type": "owl:Restriction", + "owl:onProperty": { + "@id": "knora-api:standoffTagHasStartParentIndex" + }, + "owl:maxCardinality": 1, + "knora-api:isInherited": true + }, + { + "@type": "owl:Restriction", + "owl:onProperty": { + "@id": "knora-api:standoffTagHasUUID" + }, + "owl:cardinality": 1, + "knora-api:isInherited": true + }, + { + "@type": "owl:Restriction", + "owl:onProperty": { + "@id": "standoff:standoffFootnoteTagHasContent" + }, + "owl:cardinality": 1 + } + ], + "rdfs:comment": "Represents a footnote in a TextValue", + "@type": "owl:Class", + "@id": "standoff:StandoffFootnoteTag" + }, { "knora-api:isStandoffClass": true, "rdfs:subClassOf": [ @@ -2935,6 +3033,17 @@ "@type": "owl:Class", "@id": "standoff:StandoffVisualTag" }, + { + "@type": "owl:DatatypeProperty", + "knora-api:objectType": { + "@id": "xsd:string" + }, + "@id": "standoff:standoffFootnoteTagHasContent", + "knora-api:subjectType": { + "@id": "standoff:StandoffFootnoteTag" + }, + "rdfs:comment": "describes the content of a footnote" + }, { "@type": "owl:DatatypeProperty", "knora-api:objectType": { diff --git a/version.txt b/version.txt index cc85ff7699..c97cfb7420 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -31.1.0 +31.2.1 diff --git a/webapi/src/main/resources/knora-ontologies/knora-base.ttl b/webapi/src/main/resources/knora-ontologies/knora-base.ttl index c2caed9f30..50ffe08506 100644 --- a/webapi/src/main/resources/knora-ontologies/knora-base.ttl +++ b/webapi/src/main/resources/knora-ontologies/knora-base.ttl @@ -20,7 +20,7 @@ rdf:type owl:Ontology ; rdfs:label "The Knora base ontology"@en ; :attachedToProject knora-admin:SystemProject ; - :ontologyVersion "knora-base v44" . + :ontologyVersion "knora-base v46" . ################################################################# @@ -34,6 +34,7 @@ :ontologyVersion rdf:type owl:DatatypeProperty ; + rdfs:label "ontology version"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; rdfs:comment "Indicates the version of the Knora built-in ontologies in a repository."@en ; :subjectClassConstraint owl:Ontology ; @@ -46,6 +47,7 @@ :isMainResource rdf:type owl:DatatypeProperty ; + rdfs:label "is main resource"@en ; rdfs:comment "Indicates if the given resource is the main resource of a request or a resource referred to by a link property."@en ; :subjectClassConstraint :Resource ; :objectDatatypeConstraint xsd:boolean . @@ -55,6 +57,7 @@ :objectCannotBeMarkedAsDeleted rdf:type rdf:Property ; + rdfs:label "object cannot be marked as deleted"@en ; rdfs:comment "The base property of properties whose objects can't be marked as deleted"@en . @@ -62,6 +65,7 @@ :objectDatatypeConstraint rdf:type owl:DatatypeProperty ; + rdfs:label "object datatype constraint"@en ; rdfs:comment "Specifies the type required as the object of a datatype property"@en . @@ -69,6 +73,7 @@ :resourceIcon rdf:type owl:DatatypeProperty ; + rdfs:label "resource icon"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; :subjectClassConstraint owl:Class ; :objectDatatypeConstraint xsd:string . @@ -78,6 +83,7 @@ :resourceProperty rdf:type owl:ObjectProperty ; + rdfs:label "resource property"@en ; rdfs:comment "The base property of properties that point from Knora resources to Knora resources or values. These properties are required to have cardinalities in the resource classes in which they are used."@en ; :subjectClassConstraint :Resource . @@ -86,6 +92,7 @@ :subjectClassConstraint rdf:type owl:ObjectProperty ; + rdfs:label "subject class constraint"@en ; rdfs:comment "Specifies the OWL class that the subject of a property must belong to"@en . @@ -93,6 +100,7 @@ :objectClassConstraint rdf:type owl:ObjectProperty ; + rdfs:label "object class constraint"@en ; rdfs:comment "Specifies the OWL class that the object of a property must belong to"@en . @@ -374,6 +382,7 @@ :hasRepresentationValue rdf:type owl:ObjectProperty ; + rdfs:label "has Representation Value"@en; :objectClassConstraint :LinkValue ; :subjectClassConstraint :Resource ; :isEditable true ; @@ -414,6 +423,7 @@ :standoffTagHasLink rdf:type owl:ObjectProperty ; + rdfs:label "standoff tag has link"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; :objectClassConstraint :Resource ; :subjectClassConstraint :StandoffLinkTag . @@ -423,6 +433,7 @@ :standoffTagHasInternalReference rdf:type owl:ObjectProperty ; + rdfs:label "standoff tag has internal reference"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; :objectClassConstraint :StandoffTag ; :subjectClassConstraint :StandoffInternalReferenceTag . @@ -432,6 +443,7 @@ :standoffTagHasStart rdf:type owl:DatatypeProperty ; + rdfs:label "standoff tag has start"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; :subjectClassConstraint :StandoffTag ; :objectDatatypeConstraint xsd:integer . @@ -441,6 +453,7 @@ :standoffTagHasEnd rdf:type owl:DatatypeProperty ; + rdfs:label "standoff tag has end"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; :subjectClassConstraint :StandoffTag ; :objectDatatypeConstraint xsd:integer . @@ -450,6 +463,7 @@ :standoffTagHasStartIndex rdf:type owl:DatatypeProperty ; + rdfs:label "standoff tag has start index"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; :subjectClassConstraint :StandoffTag ; :objectDatatypeConstraint xsd:integer . @@ -459,6 +473,7 @@ :standoffTagHasEndIndex rdf:type owl:DatatypeProperty ; + rdfs:label "standoff tag has end index"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; :subjectClassConstraint :StandoffTag ; :objectDatatypeConstraint xsd:integer . @@ -469,6 +484,7 @@ :standoffTagHasStartAncestor rdf:type owl:ObjectProperty, owl:TransitiveProperty ; + rdfs:label "standoff tag has start ancestor"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; :subjectClassConstraint :StandoffTag ; :objectClassConstraint :StandoffTag . @@ -478,6 +494,7 @@ :standoffTagHasStartParent rdf:type owl:ObjectProperty ; + rdfs:label "standoff tag has start parent"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted, :standoffTagHasStartAncestor ; :subjectClassConstraint :StandoffTag ; @@ -488,6 +505,7 @@ :standoffTagHasEndParent rdf:type owl:ObjectProperty ; + rdfs:label "standoff tag has end parent"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; :subjectClassConstraint :StandoffTag ; :objectClassConstraint :StandoffTag . @@ -497,13 +515,16 @@ :standoffTagHasUUID rdf:type owl:DatatypeProperty ; + rdfs:label "standoff tag has UUID"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; :subjectClassConstraint :StandoffTag ; :objectDatatypeConstraint xsd:string . +### http://www.knora.org/ontology/knora-base#standoffTagHasMaxStandoffStartIndex :valueHasMaxStandoffStartIndex rdf:type owl:DatatypeProperty ; + rdfs:label "value has max standoff start index"@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :Value ; :objectDatatypeConstraint xsd:integer . @@ -513,6 +534,7 @@ :hasSubListNode rdf:type owl:ObjectProperty ; + rdfs:label "has sub-list-node"@en ; rdfs:comment "A hierarchical list is formed using the \"hasSubListNode\"-property"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; :objectClassConstraint :ListNode ; @@ -523,6 +545,7 @@ :hasValue rdf:type owl:ObjectProperty ; + rdfs:label "has value"@en ; rdfs:subPropertyOf :resourceProperty ; :subjectClassConstraint :Resource ; :objectClassConstraint :Value . @@ -531,6 +554,7 @@ :hasCopyrightAttribution rdf:type owl:DatatypeProperty ; + rdfs:label "copyright attribution"@en; rdfs:comment "The copyright statement that gives credit to the original author."@en ; :objectDatatypeConstraint xsd:string . @@ -538,12 +562,15 @@ :hasLicenseText rdf:type owl:DatatypeProperty ; + rdfs:label "license text"@en; rdfs:comment "Specifies the terms under which a work can be used. This statement may be a reference to a well-known license, such as Creative Commons (e.g. 'CC BY-SA') or a custom license."@en ; :objectDatatypeConstraint xsd:string . +### http://www.knora.org/ontology/knora-base#hasLicenseUri :hasLicenseUri rdf:type owl:DatatypeProperty ; + rdfs:label "license URI"@en; rdfs:comment "Canonical link to license."@en ; :objectDatatypeConstraint xsd:anyUri . @@ -565,6 +592,10 @@ :isAnnotationOfValue rdf:type owl:ObjectProperty ; + rdfs:label "ist Annotation von"@de, + "is Annotation of"@en, + "est Annotation de"@fr, + "è Annotation di"@it ; :objectClassConstraint :LinkValue ; :subjectClassConstraint :Annotation ; :isEditable true ; @@ -590,6 +621,10 @@ :isPartOfValue rdf:type owl:ObjectProperty ; + rdfs:label "ist Teil von"@de, + "is part of"@en, + "fait partie de"@fr, + "fa parte di"@it ; :objectClassConstraint :LinkValue ; :subjectClassConstraint :Resource ; :isEditable true ; @@ -630,6 +665,7 @@ :previousValue rdf:type owl:ObjectProperty ; + rdfs:label "previous value"@en ; rdfs:subPropertyOf :valueHas ; rdfs:comment "Points to the previous verson of a value"@en ; :subjectClassConstraint :Value ; @@ -654,6 +690,7 @@ :standoffTagHasOriginalXMLID rdf:type owl:DatatypeProperty ; + rdfs:label "standoff tag has original XML ID"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; :objectDatatypeConstraint xsd:string ; :subjectClassConstraint :StandoffTag . @@ -665,6 +702,7 @@ :targetHasOriginalXMLID rdf:type owl:DatatypeProperty ; + rdfs:label "target has original XML ID"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; :objectDatatypeConstraint xsd:string ; :subjectClassConstraint :StandoffTag . @@ -674,6 +712,7 @@ :valueHasStandoff rdf:type owl:ObjectProperty ; + rdfs:label "value has standoff"@en ; rdfs:subPropertyOf :valueHas ; :objectClassConstraint :StandoffTag ; :subjectClassConstraint :TextValue . @@ -683,6 +722,7 @@ :valueHasLanguage rdf:type owl:DatatypeProperty ; + rdfs:label "value has language"@en ; :objectDatatypeConstraint xsd:string ; :subjectClassConstraint :TextValue . @@ -691,6 +731,7 @@ :valueHasMapping rdf:type owl:ObjectProperty ; + rdfs:label "value has mapping"@en ; rdfs:subPropertyOf :valueHas ; :objectClassConstraint :XMLToStandoffMapping ; :subjectClassConstraint :TextValue . @@ -820,11 +861,10 @@ :deletedBy rdf:type owl:ObjectProperty ; + rdfs:label "deleted by"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; rdfs:comment "Indicates who deleted a resource or value"@en ; - # No :subjectClassConstraint, because this can be used with :Resource or :Value. - :objectClassConstraint knora-admin:User . @@ -840,6 +880,7 @@ :creationDate rdf:type owl:DatatypeProperty ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; + rdfs:label "creation date"@en ; rdfs:comment "Indicates when a resource was created"@en ; :subjectClassConstraint :Resource ; :objectDatatypeConstraint xsd:dateTime . @@ -849,11 +890,10 @@ :deleteDate rdf:type owl:DatatypeProperty ; + rdfs:label "delete date"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; rdfs:comment "Indicates when a resource or value was deleted"@en ; - # No :subjectClassConstraint, because this can be used with :Resource or :Value. - :objectDatatypeConstraint xsd:dateTime . @@ -861,6 +901,7 @@ :dimX rdf:type owl:DatatypeProperty ; + rdfs:label "dimX / width"@en ; :subjectClassConstraint :FileValue ; rdfs:subPropertyOf :valueHas ; :objectDatatypeConstraint xsd:integer . @@ -870,6 +911,7 @@ :dimY rdf:type owl:DatatypeProperty ; + rdfs:label "dimY / height"@en ; :subjectClassConstraint :FileValue ; rdfs:subPropertyOf :valueHas ; :objectDatatypeConstraint xsd:integer . @@ -879,6 +921,7 @@ :pageCount rdf:type owl:DatatypeProperty ; + rdfs:label "page count"@en ; :subjectClassConstraint :FileValue ; rdfs:subPropertyOf :valueHas ; :objectDatatypeConstraint xsd:integer . @@ -888,6 +931,7 @@ :duration rdf:type owl:DatatypeProperty ; + rdfs:label "duration"@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :FileValue ; :objectDatatypeConstraint xsd:decimal . @@ -897,6 +941,7 @@ :extResAccessInfo rdf:type owl:DatatypeProperty ; + rdfs:label "external resource access info"@en ; rdfs:comment "Information (URL etc.) for accessing an external resource"@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :ExternalResValue ; @@ -907,6 +952,7 @@ :extResId rdf:type owl:DatatypeProperty ; + rdfs:label "external resource ID"@en ; rdfs:comment "The ID of the external resource. The form of the ID is dependent on the provider."@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :ExternalResValue ; @@ -917,6 +963,7 @@ :extResProvider rdf:type owl:DatatypeProperty ; + rdfs:label "external resource provider"@en ; rdfs:comment "The name of the external provider of the resource"@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :ExternalResValue ; @@ -927,6 +974,7 @@ :fps rdf:type owl:DatatypeProperty ; + rdfs:label "frames per second"@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :FileValue ; :objectDatatypeConstraint xsd:decimal . @@ -936,6 +984,7 @@ :internalFilename rdf:type owl:DatatypeProperty ; + rdfs:label "internal filename"@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :FileValue ; :objectDatatypeConstraint xsd:string . @@ -945,6 +994,7 @@ :internalMimeType rdf:type owl:DatatypeProperty ; + rdfs:label "internal MIME type"@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :FileValue ; :objectDatatypeConstraint xsd:string . @@ -954,11 +1004,10 @@ :isDeleted rdf:type owl:DatatypeProperty ; + rdfs:label "is deleted"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; rdfs:comment "Exists and is true if the resource has been deleted"@en ; - # No :subjectClassConstraint, because this can be used with :Resource or :Value. - :objectDatatypeConstraint xsd:boolean . @@ -966,6 +1015,7 @@ :isRootNode rdf:type owl:DatatypeProperty ; + rdfs:label "is root node"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; :subjectClassConstraint :ListNode ; :objectDatatypeConstraint xsd:boolean . @@ -975,6 +1025,7 @@ :hasRootNode rdf:type owl:ObjectProperty ; + rdfs:label "has root node"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; :subjectClassConstraint :ListNode ; :objectDatatypeConstraint :ListNode . @@ -984,6 +1035,7 @@ :lastModificationDate rdf:type owl:DatatypeProperty ; + rdfs:label "last modification date"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; :objectDatatypeConstraint xsd:dateTime . @@ -992,6 +1044,7 @@ :listNodePosition rdf:type owl:DatatypeProperty ; + rdfs:label "list node position"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; :subjectClassConstraint :ListNode ; :objectDatatypeConstraint xsd:integer . @@ -1001,6 +1054,7 @@ :listNodeName rdf:type owl:DatatypeProperty ; + rdfs:label "list node name"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; :subjectClassConstraint :ListNode ; :objectDatatypeConstraint xsd:string . @@ -1010,6 +1064,7 @@ :originalFilename rdf:type owl:DatatypeProperty ; + rdfs:label "original filename"@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :FileValue ; :objectDatatypeConstraint xsd:string . @@ -1019,6 +1074,7 @@ :externalUrl rdf:type owl:DatatypeProperty ; + rdfs:label "external URL"@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :StillImageExternalFileValue ; :objectDatatypeConstraint xsd:anyURI. @@ -1028,6 +1084,7 @@ :originalMimeType rdf:type owl:DatatypeProperty ; + rdfs:label "original MIME type"@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :FileValue ; :objectDatatypeConstraint xsd:string . @@ -1037,6 +1094,7 @@ :valueHasComment rdf:type owl:DatatypeProperty ; + rdfs:label "value has comment"@en ; rdfs:comment "A comment on a value"@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :Value ; @@ -1047,11 +1105,10 @@ :deleteComment rdf:type owl:DatatypeProperty ; + rdfs:label "delete comment"@en ; rdfs:comment "A comment explaining why a resource or value was marked as deleted"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; - # No :subjectClassConstraint, because this can be used with :Resource or :Value. - :objectDatatypeConstraint xsd:string . @@ -1059,6 +1116,7 @@ :valueCreationDate rdf:type owl:DatatypeProperty ; + rdfs:label "value creation date"@en ; :subjectClassConstraint :Value ; rdfs:subPropertyOf :valueHas ; :objectDatatypeConstraint xsd:dateTime . @@ -1068,6 +1126,7 @@ :valueHas rdf:type rdf:Property ; + rdfs:label "value has"@en ; :subjectClassConstraint :ValueBase ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted . @@ -1077,6 +1136,7 @@ :valueHasUUID rdf:type owl:DatatypeProperty ; rdfs:subPropertyOf :valueHas ; + rdfs:label "value has UUID"@en ; rdfs:comment "The UUID of a value"@en ; :subjectClassConstraint :Value ; :objectDatatypeConstraint xsd:string . @@ -1086,6 +1146,7 @@ :valueHasCalendar rdf:type owl:DatatypeProperty ; + rdfs:label "value has calendar"@en ; rdfs:comment "Name of the calendar to be used, such as \"GREGORIAN\" or \"JULIAN\"."@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :DateBase ; @@ -1096,6 +1157,7 @@ :valueHasColor rdf:type owl:DatatypeProperty ; + rdfs:label "value has color"@en ; rdfs:comment "Color in the form of #rrggbb (as defining web colors)"@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :ColorBase ; @@ -1106,6 +1168,7 @@ :valueHasEndJDN rdf:type owl:DatatypeProperty ; + rdfs:label "value has end JDN"@en ; rdfs:comment "Contains the end of a date as a Julian Day Number (JDN)"@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :DateBase ; @@ -1116,6 +1179,7 @@ :valueHasEndPrecision rdf:type owl:DatatypeProperty ; + rdfs:label "value has end precision"@en ; rdfs:comment "Precision of knowledge about the end of the date. Allowed are \"DAY\", \"MONTH\" or \"YEAR\"."@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :DateBase ; @@ -1126,6 +1190,7 @@ :valueHasDecimal rdf:type owl:DatatypeProperty ; + rdfs:label "value has decimal"@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :DecimalBase ; :objectDatatypeConstraint xsd:decimal . @@ -1135,6 +1200,7 @@ :valueHasGeometry rdf:type owl:DatatypeProperty ; + rdfs:label "value has geometry"@en ; rdfs:comment "JSON string describing a geometry (e.g. a region). Currently geometries are limited to 2D unions of primitive objects like circles, squares and polygons."@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :GeomValue ; @@ -1145,6 +1211,7 @@ :valueHasGeonameCode rdf:type owl:DatatypeProperty ; + rdfs:label "value has geoname code"@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :GeonameValue ; :objectDatatypeConstraint xsd:string . @@ -1154,6 +1221,7 @@ :valueHasInteger rdf:type owl:DatatypeProperty ; + rdfs:label "value has integer"@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :IntBase ; :objectDatatypeConstraint xsd:integer . @@ -1163,6 +1231,7 @@ :valueHasBoolean rdf:type owl:DatatypeProperty ; + rdfs:label "value has boolean"@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :BooleanBase ; :objectDatatypeConstraint xsd:boolean . @@ -1172,6 +1241,7 @@ :valueHasUri rdf:type owl:DatatypeProperty ; + rdfs:label "value has URI"@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :UriBase ; :objectDatatypeConstraint xsd:anyURI . @@ -1181,6 +1251,7 @@ :valueHasIntervalEnd rdf:type owl:DatatypeProperty ; + rdfs:label "value has interval end"@en ; rdfs:subPropertyOf :valueHas , schema:endOffset ; :subjectClassConstraint :IntervalBase ; @@ -1191,6 +1262,7 @@ :valueHasIntervalStart rdf:type owl:DatatypeProperty ; + rdfs:label "value has interval start"@en ; rdfs:subPropertyOf :valueHas , schema:startOffset ; :subjectClassConstraint :IntervalBase ; @@ -1201,6 +1273,7 @@ :valueHasTimeStamp rdf:type owl:DatatypeProperty ; + rdfs:label "value has timestamp"@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :TimeBase ; :objectDatatypeConstraint xsd:dateTime . @@ -1210,6 +1283,7 @@ :valueHasListNode rdf:type owl:ObjectProperty ; + rdfs:label "value has list node"@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :ListValue ; :objectClassConstraint :ListNode . @@ -1219,6 +1293,7 @@ :valueHasOrder rdf:type owl:DatatypeProperty ; + rdfs:label "value has order"@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :Value ; :objectDatatypeConstraint xsd:integer . @@ -1228,6 +1303,7 @@ :valueHasRefCount rdf:type owl:DatatypeProperty ; + rdfs:label "value has reference count"@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :LinkValue ; :objectDatatypeConstraint xsd:integer . @@ -1237,6 +1313,7 @@ :valueHasStartJDN rdf:type owl:DatatypeProperty ; + rdfs:label "value has start JDN"@en ; rdfs:comment "Contains the start of a date as a Julian Day Number (JDN)"@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :DateBase ; @@ -1247,6 +1324,7 @@ :valueHasStartPrecision rdf:type owl:DatatypeProperty ; + rdfs:label "value has start precision"@en ; rdfs:comment "The precision the start of a date. Allowed values are \"DAY\", \"MONTH\", or \"YEAR\"."@en ; rdfs:subPropertyOf :valueHas ; :subjectClassConstraint :DateBase ; @@ -1258,6 +1336,7 @@ :valueHasString rdf:type owl:DatatypeProperty ; rdfs:subPropertyOf :valueHas ; + rdfs:label "value has string"@en ; rdfs:comment "A string representation of a value, required for full-text searches and search results."@en ; :subjectClassConstraint :Value ; :objectDatatypeConstraint xsd:string . @@ -1267,6 +1346,7 @@ :hasPermissions rdf:type owl:DatatypeProperty ; + rdfs:label "has permissions"@en ; rdfs:subPropertyOf :objectCannotBeMarkedAsDeleted ; :objectDatatypeConstraint xsd:string . @@ -1308,6 +1388,7 @@ [ rdf:type owl:Restriction ; owl:onProperty :duration ; owl:maxCardinality "1"^^xsd:nonNegativeInteger ] ; + rdfs:label "audio file value"@en; rdfs:comment "Represents an audio file"@en . @@ -1331,6 +1412,7 @@ :ColorBase rdf:type owl:Class ; + rdfs:label "color base"@en ; rdfs:subClassOf :ValueBase, [ rdf:type owl:Restriction ; owl:onProperty :valueHasColor ; @@ -1343,6 +1425,7 @@ rdf:type owl:Class ; rdfs:subClassOf :Value, :ColorBase ; + rdfs:label "color value"@en ; rdfs:comment "Represents a color in HTML format, e.g. \"#33eeff\""@en . @@ -1351,6 +1434,7 @@ :DDDFileValue rdf:type owl:Class ; rdfs:subClassOf :FileValue ; + rdfs:label "3D file value"@en ; rdfs:comment "This represents some 3D-object with mesh data, point cloud, etc."@en . @@ -1373,6 +1457,7 @@ :DateBase rdf:type owl:Class ; + rdfs:label "date base"@en ; rdfs:subClassOf :ValueBase, [ rdf:type owl:Restriction ; owl:onProperty :valueHasCalendar ; @@ -1397,6 +1482,7 @@ rdf:type owl:Class ; rdfs:subClassOf :Value, :DateBase ; + rdfs:label "date value"@en ; rdfs:comment "Represents a Knora date value"@en . @@ -1404,6 +1490,7 @@ :DocumentFileValue rdf:type owl:Class ; + rdfs:label "document file value"@en ; rdfs:subClassOf :FileValue, [ rdf:type owl:Restriction ; owl:onProperty :pageCount ; @@ -1434,6 +1521,7 @@ :ArchiveFileValue rdf:type owl:Class ; + rdfs:label "archive file value"@en ; rdfs:subClassOf :FileValue . @@ -1455,6 +1543,7 @@ :ExternalResValue rdf:type owl:Class ; + rdfs:label "external resource value"@en ; rdfs:subClassOf :Value, [ rdf:type owl:Restriction ; owl:onProperty :extResId ; @@ -1486,6 +1575,7 @@ :FileValue rdf:type owl:Class ; + rdfs:label "file value"@en ; rdfs:subClassOf :Value, [ rdf:type owl:Restriction ; owl:onProperty :internalFilename ; @@ -1514,6 +1604,7 @@ :DecimalBase rdf:type owl:Class ; + rdfs:label "decimal base"@en ; rdfs:subClassOf :ValueBase, [ rdf:type owl:Restriction ; owl:onProperty :valueHasDecimal ; @@ -1526,6 +1617,7 @@ rdf:type owl:Class ; rdfs:subClassOf :Value, :DecimalBase ; + rdfs:label "decimal value"@en ; rdfs:comment "Represents an arbitrary-precision decimal value"@en . @@ -1537,6 +1629,7 @@ [ rdf:type owl:Restriction ; owl:onProperty :valueHasGeometry ; owl:cardinality "1"^^xsd:nonNegativeInteger ] ; + rdfs:label "geometry value"@en ; rdfs:comment "Represents a geometrical objects as JSON string"@en . @@ -1544,6 +1637,7 @@ :GeonameValue rdf:type owl:Class ; + rdfs:label "geoname value"@en ; rdfs:subClassOf :Value, [ rdf:type owl:Restriction ; owl:onProperty :valueHasGeonameCode ; @@ -1554,6 +1648,7 @@ :IntBase rdf:type owl:Class ; + rdfs:label "integer base"@en ; rdfs:subClassOf :ValueBase, [ rdf:type owl:Restriction ; owl:onProperty :valueHasInteger ; @@ -1566,6 +1661,7 @@ rdf:type owl:Class ; rdfs:subClassOf :Value, :IntBase ; + rdfs:label "integer value"@en ; rdfs:comment "Represents an integer value"@en . ### http://www.knora.org/ontology/knora-base#BooleanBase @@ -1584,6 +1680,7 @@ rdf:type owl:Class ; rdfs:subClassOf :Value, :BooleanBase ; + rdfs:label "boolean value"@en ; rdfs:comment "Represents a boolean value"@en . @@ -1591,6 +1688,7 @@ :UriBase rdf:type owl:Class ; + rdfs:label "URI base"@en ; rdfs:subClassOf :ValueBase, [ rdf:type owl:Restriction ; owl:onProperty :valueHasUri ; @@ -1602,12 +1700,14 @@ rdf:type owl:Class ; rdfs:subClassOf :Value, :UriBase ; + rdfs:label "URI value"@en ; rdfs:comment "Represents a URI"@en . ### http://www.knora.org/ontology/knora-base#IntervalBase :IntervalBase rdf:type owl:Class ; + rdfs:label "interval base"@en ; rdfs:subClassOf :ValueBase, [ rdf:type owl:Restriction ; owl:onProperty :valueHasIntervalEnd ; @@ -1623,6 +1723,7 @@ rdf:type owl:Class ; rdfs:subClassOf :Value, :IntervalBase ; + rdfs:label "interval value"@en ; rdfs:comment "Represents a time interval, e.g. in an audio recording"@en . @@ -1630,6 +1731,7 @@ :TimeBase rdf:type owl:Class ; + rdfs:label "time base"@en ; rdfs:subClassOf :ValueBase, [ rdf:type owl:Restriction ; owl:onProperty :valueHasTimeStamp ; @@ -1642,6 +1744,7 @@ rdf:type owl:Class ; rdfs:subClassOf :Value, :TimeBase ; + rdfs:label "time value"@en ; rdfs:comment "Represents a timestamp"@en . @@ -1673,6 +1776,7 @@ :LinkValue rdf:type owl:Class ; + rdfs:label "link value"@en ; rdfs:subClassOf :Value, rdf:Statement, [ rdf:type owl:Restriction ; @@ -1694,6 +1798,7 @@ :ListNode rdf:type owl:Class ; + rdfs:label "list node"@en ; rdfs:subClassOf [ rdf:type owl:Restriction ; owl:onProperty :hasSubListNode ; owl:minCardinality "0"^^xsd:nonNegativeInteger ], @@ -1722,6 +1827,7 @@ :ListValue rdf:type owl:Class ; + rdfs:label "list value"@en ; rdfs:subClassOf :Value, [ rdf:type owl:Restriction ; owl:onProperty :valueHasListNode ; @@ -1733,6 +1839,7 @@ :MovingImageFileValue rdf:type owl:Class ; rdfs:subClassOf :FileValue ; + rdfs:label "moving image file value"@en ; rdfs:comment "Represents a moving image file"@en . @@ -1851,13 +1958,15 @@ :standoffParentClassConstraint - rdf:type owl:ObjectProperty . + rdf:type owl:ObjectProperty ; + rdfs:label "standoff parent class constraint"@en . ### http://www.knora.org/ontology/knora-base#StandoffTag :StandoffTag rdf:type owl:Class ; + rdfs:label "standoff tag"@en ; rdfs:subClassOf [ rdf:type owl:Restriction ; owl:onProperty :standoffTagHasStart ; owl:cardinality "1"^^xsd:nonNegativeInteger ], @@ -1899,6 +2008,7 @@ :StandoffDataTypeTag rdf:type owl:Class ; rdfs:subClassOf :StandoffTag ; + rdfs:label "standoff data type tag"@en ; rdfs:comment "Represents a knora-base value type in a TextValue"@en . @@ -1917,6 +2027,7 @@ [ rdf:type owl:Restriction ; owl:onProperty :standoffTagHasLink ; owl:cardinality "1"^^xsd:nonNegativeInteger ] ; + rdfs:label "standoff link tag"@en ; rdfs:comment "Represents a reference to a Knora resource in a TextValue"@en . @@ -1926,6 +2037,7 @@ rdf:type owl:Class ; rdfs:subClassOf :StandoffDataTypeTag, :UriBase ; + rdfs:label "standoff URI tag"@en ; rdfs:comment "Represents an arbitrary URI in a TextValue"@en . @@ -1935,6 +2047,7 @@ rdf:type owl:Class ; rdfs:subClassOf :StandoffDataTypeTag, :DateBase ; + rdfs:label "standoff date tag"@en ; rdfs:comment "Represents a date in a TextValue"@en . @@ -1944,6 +2057,7 @@ rdf:type owl:Class ; rdfs:subClassOf :StandoffDataTypeTag, :ColorBase ; + rdfs:label "standoff color tag"@en ; rdfs:comment "Represents a color in a TextValue"@en . @@ -1953,6 +2067,7 @@ rdf:type owl:Class ; rdfs:subClassOf :StandoffDataTypeTag, :IntBase ; + rdfs:label "standoff integer tag"@en ; rdfs:comment "Represents an integer value in a TextValue"@en . @@ -1962,6 +2077,7 @@ rdf:type owl:Class ; rdfs:subClassOf :StandoffDataTypeTag, :DecimalBase ; + rdfs:label "standoff decimal tag"@en ; rdfs:comment "Represents a decimal (floating point) value in a TextValue"@en . @@ -1971,6 +2087,7 @@ rdf:type owl:Class ; rdfs:subClassOf :StandoffDataTypeTag, :IntervalBase ; + rdfs:label "standoff interval tag"@en ; rdfs:comment "Represents an interval in a TextValue"@en . @@ -1980,6 +2097,7 @@ rdf:type owl:Class ; rdfs:subClassOf :StandoffDataTypeTag, :TimeBase ; + rdfs:label "standoff time tag"@en ; rdfs:comment "Represents a timestamp in a TextValue"@en . @@ -1989,6 +2107,7 @@ rdf:type owl:Class ; rdfs:subClassOf :StandoffDataTypeTag, :BooleanBase ; + rdfs:label "standoff boolean tag"@en ; rdfs:comment "Represents a boolean in a TextValue"@en . @@ -2001,6 +2120,7 @@ [ rdf:type owl:Restriction ; owl:onProperty :standoffTagHasInternalReference ; owl:cardinality "1"^^xsd:nonNegativeInteger ] ; + rdfs:label "standoff internal reference tag"@en ; rdfs:comment "Represents an internal reference in a TextValue"@en . @@ -2015,6 +2135,7 @@ [ rdf:type owl:Restriction ; owl:onProperty :dimX ; owl:cardinality "1"^^xsd:nonNegativeInteger ] ; + rdfs:label "still image file value"@en ; rdfs:comment "A file containing a two-dimensional still image"@en . @@ -2026,6 +2147,7 @@ [ rdf:type owl:Restriction ; owl:onProperty :externalUrl ; owl:cardinality "1"^^xsd:nonNegativeInteger ] ; + rdfs:label "still image external file value"@en ; rdfs:comment "A file containing a two-dimensional still image"@en . @@ -2034,6 +2156,7 @@ :StillImageAbstractFileValue rdf:type owl:Class ; rdfs:subClassOf :FileValue ; + rdfs:label "still image abstract file value"@en ; rdfs:comment "A file containing a two-dimensional still image"@en . @@ -2057,6 +2180,7 @@ :TextFileValue rdf:type owl:Class ; + rdfs:label "Text file value"@en ; rdfs:subClassOf :FileValue ; rdfs:comment "A text file such as plain Unicode text, LaTeX, TEI/XML, etc."@en . @@ -2175,6 +2299,7 @@ :TextValue rdf:type owl:Class ; + rdfs:label "Text Value"@en ; rdfs:subClassOf :Value, [ rdf:type owl:Restriction ; owl:onProperty :valueHasStandoff ; @@ -2240,6 +2365,7 @@ [ rdf:type owl:Restriction ; owl:onProperty :valueHasUUID ; owl:maxCardinality "1"^^xsd:nonNegativeInteger ] ; + rdfs:label "Value"@en ; rdfs:comment "The base class of classes representing Knora values"@en . @@ -2373,6 +2499,10 @@ :isSegmentOfValue rdf:type owl:ObjectProperty ; + rdfs:label "Segment of"@en , + "Segment von"@de , + "Segment de"@fr , + "Segmento di"@it ; :objectClassConstraint :LinkValue ; :subjectClassConstraint :Segment ; :isEditable true ; @@ -2398,6 +2528,10 @@ :isAudioSegmentOfValue rdf:type owl:ObjectProperty ; + rdfs:label "Segment of"@en , + "Segment von"@de , + "Segment de"@fr , + "Segmento di"@it ; :objectClassConstraint :LinkValue ; :subjectClassConstraint :AudioSegment ; :isEditable true ; @@ -2422,6 +2556,10 @@ :isVideoSegmentOfValue rdf:type owl:ObjectProperty ; + rdfs:label "Segment of"@en , + "Segment von"@de , + "Segment de"@fr , + "Segmento di"@it ; :objectClassConstraint :LinkValue ; :subjectClassConstraint :VideoSegment ; :isEditable true ; @@ -2542,6 +2680,10 @@ :isSequenceOfValue rdf:type owl:ObjectProperty ; + rdfs:label "ist Sequenz von"@de, + "is sequence of"@en, + "fait partie de"@fr, + "fa parte di"@it ; :objectClassConstraint :LinkValue ; :subjectClassConstraint :Resource ; :isEditable true ; diff --git a/webapi/src/main/resources/knora-ontologies/standoff-data.ttl b/webapi/src/main/resources/knora-ontologies/standoff-data.ttl index 87f2fd9e58..0b6384c8c6 100644 --- a/webapi/src/main/resources/knora-ontologies/standoff-data.ttl +++ b/webapi/src/main/resources/knora-ontologies/standoff-data.ttl @@ -50,7 +50,8 @@ , , , - . + , + . a knora-base:MappingElement ; @@ -75,6 +76,21 @@ knora-base:mappingElementRequiresSeparator true ; knora-base:mappingHasXMLTagname "p"^^xsd:string . + + a knora-base:MappingElement ; + knora-base:mappingHasStandoffClass standoff:StandoffFootnoteTag ; + knora-base:mappingHasXMLClass "noClass"^^xsd:string ; + knora-base:mappingHasXMLNamespace "noNamespace"^^xsd:string ; + knora-base:mappingElementRequiresSeparator true ; + knora-base:mappingHasXMLTagname "footnote"^^xsd:string ; + knora-base:mappingHasXMLAttribute . + + + a knora-base:MappingXMLAttribute ; + knora-base:mappingHasStandoffProperty standoff:standoffFootnoteTagHasContent ; + knora-base:mappingHasXMLAttributename "content"^^xsd:string ; + knora-base:mappingHasXMLNamespace "noNamespace"^^xsd:string . + a knora-base:MappingElement ; knora-base:mappingHasStandoffClass standoff:StandoffItalicTag ; diff --git a/webapi/src/main/resources/knora-ontologies/standoff-onto.ttl b/webapi/src/main/resources/knora-ontologies/standoff-onto.ttl index cfb976f911..5bf0a294c5 100644 --- a/webapi/src/main/resources/knora-ontologies/standoff-onto.ttl +++ b/webapi/src/main/resources/knora-ontologies/standoff-onto.ttl @@ -47,6 +47,15 @@ knora-base:subjectClassConstraint :StandoffHyperlinkTag ; knora-base:objectDatatypeConstraint xsd:string . +### http://www.knora.org/ontology/standoff#standoffFootnoteTagHasContent + +:standoffFootnoteTagHasContent + rdf:type owl:DatatypeProperty ; + rdfs:subPropertyOf knora-base:objectCannotBeMarkedAsDeleted ; + rdfs:comment "describes the content of a footnote"@en ; + knora-base:subjectClassConstraint :StandoffFootnoteTag ; + knora-base:objectDatatypeConstraint xsd:string . + ################################################################# # @@ -120,6 +129,15 @@ rdfs:subClassOf :StandoffStructuralTag ; rdfs:comment "Represents a paragraph in a TextValue"@en . +### http://www.knora.org/ontology/standoff#StandoffFootnoteTag + +:StandoffFootnoteTag + rdf:type owl:Class ; + rdfs:subClassOf :StandoffStructuralTag , + [ rdf:type owl:Restriction ; + owl:onProperty :standoffFootnoteTagHasContent ; + owl:cardinality "1"^^xsd:nonNegativeInteger ] ; + rdfs:comment "Represents a footnote in a TextValue"@en . ### http://www.knora.org/ontology/standoff#StandoffHeader1Tag diff --git a/webapi/src/main/scala/org/knora/webapi/core/AppServer.scala b/webapi/src/main/scala/org/knora/webapi/core/AppServer.scala index e749efce6a..c79133ccd7 100644 --- a/webapi/src/main/scala/org/knora/webapi/core/AppServer.scala +++ b/webapi/src/main/scala/org/knora/webapi/core/AppServer.scala @@ -10,7 +10,6 @@ import zio.* import org.knora.webapi.config.AppConfig import org.knora.webapi.core.domain.AppState -import org.knora.webapi.messages.util.KnoraSystemInstances import org.knora.webapi.slice.ontology.repo.service.OntologyCache import org.knora.webapi.store.iiif.api.SipiService import org.knora.webapi.store.triplestore.api.TriplestoreService @@ -66,9 +65,7 @@ final case class AppServer( private def populateOntologyCaches(requiresRepository: Boolean): Task[Unit] = for { _ <- state.set(AppState.LoadingOntologies) - _ <- ontologyCache - .loadOntologies(KnoraSystemInstances.Users.SystemUser) - .when(requiresRepository) + _ <- ontologyCache.loadOntologies().when(requiresRepository) _ <- state.set(AppState.OntologiesReady) } yield () diff --git a/webapi/src/main/scala/org/knora/webapi/messages/StringFormatter.scala b/webapi/src/main/scala/org/knora/webapi/messages/StringFormatter.scala index 5252be2210..a9051c3402 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/StringFormatter.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/StringFormatter.scala @@ -260,7 +260,7 @@ object StringFormatter { private def getOrCacheSmartIri(iriStr: IRI, creationFun: () => SmartIri): SmartIri = smartIriCache.computeIfAbsent( iriStr, - JavaUtil.function({ (_: Object) => creationFun() }), + JavaUtil.function((_: Object) => creationFun()), ) val live: ZLayer[AppConfig, Nothing, StringFormatter] = ZLayer.fromFunction { (appConfig: AppConfig) => diff --git a/webapi/src/main/scala/org/knora/webapi/messages/store/sipimessages/SipiMessages.scala b/webapi/src/main/scala/org/knora/webapi/messages/store/sipimessages/SipiMessages.scala index 74bb468c20..78b54c6229 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/store/sipimessages/SipiMessages.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/store/sipimessages/SipiMessages.scala @@ -5,8 +5,6 @@ package org.knora.webapi.messages.store.sipimessages -import zio.json.* - import org.knora.webapi.core.RelayedMessage import org.knora.webapi.messages.store.StoreRequest import org.knora.webapi.messages.traits.RequestWithSender @@ -36,26 +34,3 @@ case class SipiGetTextFileRequest(fileUrl: String, requestingUser: User, senderN * @param content the file content. */ case class SipiGetTextFileResponse(content: String) - -/** - * Represents the information that Sipi returns about each file that has been uploaded. - * - * @param originalFilename the original filename that was submitted to Sipi. - * @param internalFilename Sipi's internal filename for the stored temporary file. - */ -case class SipiUploadResponseEntry( - originalFilename: String, - internalFilename: String, -) - -/** - * Represents Sipi's response to a file upload request. - * - * @param uploadedFiles the information about each file that was uploaded. - */ -case class SipiUploadResponse(uploadedFiles: List[SipiUploadResponseEntry]) - -object SipiUploadResponseJsonProtocol { - implicit val entry: JsonCodec[SipiUploadResponseEntry] = DeriveJsonCodec.gen[SipiUploadResponseEntry] - implicit val response: JsonCodec[SipiUploadResponse] = DeriveJsonCodec.gen[SipiUploadResponse] -} diff --git a/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/JenaModel.scala b/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/JenaModel.scala index d9ba3e65ce..7b0ad48b23 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/JenaModel.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/JenaModel.scala @@ -21,7 +21,7 @@ sealed trait JenaNode extends RdfNode { } case class JenaBlankNode(node: jena.graph.Node) extends JenaNode with BlankNode { - override def id: String = node.getBlankNodeId.getLabelString + override def id: String = node.getBlankNodeLabel override def stringValue: String = id } @@ -126,7 +126,7 @@ object JenaContextFactory { /** * Converts a named graph IRI to a [[jena.graph.Node]]. */ - def contextIriToNode(context: IRI): jena.graph.Node = + private def contextIriToNode(context: IRI): jena.graph.Node = jena.graph.NodeFactory.createURI(context) /** @@ -359,7 +359,7 @@ object JenaNodeFactory { * @return a [[DatatypeLiteral]]. */ def makeDatatypeLiteral(value: String, datatype: IRI): DatatypeLiteral = - JenaDatatypeLiteral(jena.graph.NodeFactory.createLiteral(value, typeMapper.getTypeByName(datatype))) + JenaDatatypeLiteral(jena.graph.NodeFactory.createLiteralDT(value, typeMapper.getTypeByName(datatype))) /** * Constructs a string with a language tag. @@ -368,7 +368,7 @@ object JenaNodeFactory { * @param language the language tag. */ def makeStringWithLanguage(value: String, language: String): StringWithLanguage = - JenaStringWithLanguage(jena.graph.NodeFactory.createLiteral(value, language)) + JenaStringWithLanguage(jena.graph.NodeFactory.createLiteralLang(value, language)) /** * Constructs a statement. 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 50ad017d44..c046443de0 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 @@ -96,41 +96,40 @@ object CreateOntologyRequestV2 { apiRequestID: UUID, requestingUser: User, ): ZIO[StringFormatter, Throwable, CreateOntologyRequestV2] = ZIO.serviceWithZIO[StringFormatter] { - implicit sf: StringFormatter => - for { - isShared <- ZIO - .fromEither(jsonLDDocument.body.getBoolean(KnoraApiV2Complex.IsShared)) - .mapBoth(BadRequestException(_), _.exists(identity)) - ontologyName <- - ZIO.attempt { - jsonLDDocument.body.requireStringWithValidation( - KnoraApiV2Complex.OntologyName, - ValuesValidator.validateProjectSpecificOntologyName(_).getOrElse(_), - ) - } - label <- - ZIO.attempt( - jsonLDDocument.body.requireStringWithValidation(Rdfs.Label, Iri.toSparqlEncodedString(_).getOrElse(_)), - ) - comment <- - ZIO.attempt( - jsonLDDocument.body.maybeStringWithValidation(Rdfs.Comment, Iri.toSparqlEncodedString(_).getOrElse(_)), + implicit sf: StringFormatter => for { + isShared <- ZIO + .fromEither(jsonLDDocument.body.getBoolean(KnoraApiV2Complex.IsShared)) + .mapBoth(BadRequestException(_), _.exists(identity)) + ontologyName <- + ZIO.attempt { + jsonLDDocument.body.requireStringWithValidation( + KnoraApiV2Complex.OntologyName, + ValuesValidator.validateProjectSpecificOntologyName(_).getOrElse(_), ) - projectIri <- ZIO.attempt { - jsonLDDocument.body.requireIriInObject( - KnoraApiV2Complex.AttachedToProject, - sf.toSmartIriWithErr, - ) - } - } yield CreateOntologyRequestV2( - ontologyName = ontologyName, - projectIri = projectIri, - isShared = isShared, - label = label, - comment = comment, - apiRequestID = apiRequestID, - requestingUser = requestingUser, - ) + } + label <- + ZIO.attempt( + jsonLDDocument.body.requireStringWithValidation(Rdfs.Label, Iri.toSparqlEncodedString(_).getOrElse(_)), + ) + comment <- + ZIO.attempt( + jsonLDDocument.body.maybeStringWithValidation(Rdfs.Comment, Iri.toSparqlEncodedString(_).getOrElse(_)), + ) + projectIri <- ZIO.attempt { + jsonLDDocument.body.requireIriInObject( + KnoraApiV2Complex.AttachedToProject, + sf.toSmartIriWithErr, + ) + } + } yield CreateOntologyRequestV2( + ontologyName = ontologyName, + projectIri = projectIri, + isShared = isShared, + label = label, + comment = comment, + apiRequestID = apiRequestID, + requestingUser = requestingUser, + ) } } diff --git a/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/valuemessages/ValueMessagesV2.scala b/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/valuemessages/ValueMessagesV2.scala index 38c3409e28..f779c2b359 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/valuemessages/ValueMessagesV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/valuemessages/ValueMessagesV2.scala @@ -2186,14 +2186,11 @@ case class StillImageExternalFileValueContentV2( case ApiV2Complex => JsonLDObject( toJsonLDObjectMapInComplexSchema(makeFileUrl) ++ Map( - StillImageFileValueHasIIIFBaseUrl -> JsonLDUtil - .makeUriObject( - { - val uri = externalUrl.value.toURI - if (uri.getPort == -1) URI.create(s"${uri.getScheme}://${uri.getHost}").toURL - else URI.create(s"${uri.getScheme}://${uri.getHost}:${uri.getPort}").toURL - }, - ), + StillImageFileValueHasIIIFBaseUrl -> JsonLDUtil.makeUriObject { + val uri = externalUrl.value.toURI + if (uri.getPort == -1) URI.create(s"${uri.getScheme}://${uri.getHost}").toURL + else URI.create(s"${uri.getScheme}://${uri.getHost}:${uri.getPort}").toURL + }, StillImageFileValueHasExternalUrl -> JsonLDUtil.makeUriObject(externalUrl.value), ), ) diff --git a/webapi/src/main/scala/org/knora/webapi/package.scala b/webapi/src/main/scala/org/knora/webapi/package.scala index cdde921bad..e7697e62ef 100644 --- a/webapi/src/main/scala/org/knora/webapi/package.scala +++ b/webapi/src/main/scala/org/knora/webapi/package.scala @@ -14,7 +14,7 @@ package object webapi { * The version of `knora-base` and of the other built-in ontologies that this version of Knora requires. * Must be the same as the object of `knora-base:ontologyVersion` in the `knora-base` ontology being used. */ - val KnoraBaseVersion: Int = 44 + val KnoraBaseVersion: Int = 46 val KnoraBaseVersionString: String = s"$versionPrefix$KnoraBaseVersion" /** diff --git a/webapi/src/main/scala/org/knora/webapi/responders/IriLocker.scala b/webapi/src/main/scala/org/knora/webapi/responders/IriLocker.scala index bc4468e24a..c9f0c3be86 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/IriLocker.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/IriLocker.scala @@ -134,7 +134,7 @@ object IriLocker { val newLock = lockMap.merge( iri, IriLock(apiRequestID, 1), - JavaUtil.biFunction({ (currentLock, _) => + JavaUtil.biFunction((currentLock, _) => // The lock is already in use. Who has it? if (currentLock.apiRequestID == apiRequestID) { // We already have it, so increment the entry count. @@ -142,8 +142,8 @@ object IriLocker { } else { // Another API request has it, so leave it as is. currentLock - } - }), + }, + ), ) // Do we have the lock? if (newLock.apiRequestID == apiRequestID) { @@ -174,7 +174,7 @@ object IriLocker { private def decrementOrReleaseLock(iri: IRI, apiRequestID: UUID): Unit = { val _ = lockMap.compute( iri, - JavaUtil.biFunction({ (_, maybeCurrentLock) => + JavaUtil.biFunction((_, maybeCurrentLock) => Option(maybeCurrentLock) match { case Some(currentLock) => if (currentLock.apiRequestID == apiRequestID) { @@ -198,8 +198,8 @@ object IriLocker { throw ApplicationLockException( s"API request $apiRequestID was supposed to have an update lock on $iri, but the lock is unused", ) - } - }), + }, + ), ) } } diff --git a/webapi/src/main/scala/org/knora/webapi/responders/v2/ResourcesResponderV2.scala b/webapi/src/main/scala/org/knora/webapi/responders/v2/ResourcesResponderV2.scala index 38e96d2003..cfa585bb24 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/v2/ResourcesResponderV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/v2/ResourcesResponderV2.scala @@ -1628,14 +1628,13 @@ final case class ResourcesResponderV2( ) // If there is a version history for deletion of the event, create a delete resource event for it. - (deletionRep, resourceAtValueChanges) = fullReps.tail.partition { case (resHist, resource) => - resource - .asInstanceOf[ReadResourceV2] - .deletionInfo - .exists(deletionInfo => - deletionInfo.deleteDate == resHist.versionDate, - ) - } + (deletionRep, resourceAtValueChanges) = + fullReps.tail.partition { case (resHist, resource) => + resource + .asInstanceOf[ReadResourceV2] + .deletionInfo + .exists(deletionInfo => deletionInfo.deleteDate == resHist.versionDate) + } resourceDeleteEvent = getResourceDeletionEvents(deletionRep) // For each value version, form an event diff --git a/webapi/src/main/scala/org/knora/webapi/responders/v2/SearchResponderV2.scala b/webapi/src/main/scala/org/knora/webapi/responders/v2/SearchResponderV2.scala index fa9edf8aaa..cb27b911c5 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/v2/SearchResponderV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/v2/SearchResponderV2.scala @@ -997,10 +997,9 @@ final case class SearchResponderV2Live( mainResourceVar: QueryVariable, ): SparqlSelectResult = { // Make a Map of merged results per main resource IRI. - val prequeryRowsMergedMap: Map[IRI, VariableResultsRow] = prequeryResponseNotMerged.results.bindings.groupBy { - row => - // Get the rows for each main resource IRI. - row.rowMap(mainResourceVar.variableName) + val prequeryRowsMergedMap: Map[IRI, VariableResultsRow] = prequeryResponseNotMerged.results.bindings.groupBy { row => + // Get the rows for each main resource IRI. + row.rowMap(mainResourceVar.variableName) }.map { case (resourceIri: IRI, rows: Seq[VariableResultsRow]) => // Make a Set of all the column names in the rows to be merged. val columnNamesToMerge: Set[String] = rows.flatMap(_.rowMap.keySet).toSet diff --git a/webapi/src/main/scala/org/knora/webapi/responders/v2/ontology/OntologyHelpers.scala b/webapi/src/main/scala/org/knora/webapi/responders/v2/ontology/OntologyHelpers.scala index 0875bca89d..be2b99dafa 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/v2/ontology/OntologyHelpers.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/v2/ontology/OntologyHelpers.scala @@ -778,8 +778,7 @@ object OntologyHelpers { OntologyConstants.KnoraBase.IsAudioSegmentOfValue.toSmartIri case subProps if subProps.contains(OntologyConstants.KnoraBase.IsVideoSegmentOf.toSmartIri) => OntologyConstants.KnoraBase.IsVideoSegmentOfValue.toSmartIri - case subProps - if subProps.size == 1 => // if subPropertyOf is neither isPartOf nor HasLinkTo it inherits from a custom link property + case subProps if subProps.size == 1 => // if subPropertyOf is neither isPartOf nor HasLinkTo it inherits from a custom link property internalPropertyDef.subPropertyOf.head.fromLinkPropToLinkValueProp case _ => throw BadRequestException( diff --git a/webapi/src/main/scala/org/knora/webapi/routing/v2/OntologiesRouteV2.scala b/webapi/src/main/scala/org/knora/webapi/routing/v2/OntologiesRouteV2.scala index cc77bbd40f..04fe3f7fd3 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/v2/OntologiesRouteV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/v2/OntologiesRouteV2.scala @@ -152,16 +152,14 @@ final case class OntologiesRouteV2()( path(ontologiesBasePath / "metadata") { put { entity(as[String]) { jsonRequest => requestContext => - { - val requestTask = for { - requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) - apiRequestId <- RouteUtilZ.randomUuid() - requestMessage <- - requestParser(_.changeOntologyMetadataRequestV2(jsonRequest, apiRequestId, requestingUser)) - .mapError(BadRequestException.apply) - } yield requestMessage - RouteUtilV2.runRdfRouteZ(requestTask, requestContext) - } + val requestTask = for { + requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) + apiRequestId <- RouteUtilZ.randomUuid() + requestMessage <- + requestParser(_.changeOntologyMetadataRequestV2(jsonRequest, apiRequestId, requestingUser)) + .mapError(BadRequestException.apply) + } yield requestMessage + RouteUtilV2.runRdfRouteZ(requestTask, requestContext) } } } @@ -199,15 +197,13 @@ final case class OntologiesRouteV2()( post { // Create a new class. entity(as[String]) { jsonRequest => requestContext => - { - val requestMessageTask = for { - requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) - apiRequestId <- RouteUtilZ.randomUuid() - requestMessage <- requestParser(_.createClassRequestV2(jsonRequest, apiRequestId, requestingUser)) - .mapError(BadRequestException.apply) - } yield requestMessage - RouteUtilV2.runRdfRouteZ(requestMessageTask, requestContext) - } + val requestMessageTask = for { + requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) + apiRequestId <- RouteUtilZ.randomUuid() + requestMessage <- requestParser(_.createClassRequestV2(jsonRequest, apiRequestId, requestingUser)) + .mapError(BadRequestException.apply) + } yield requestMessage + RouteUtilV2.runRdfRouteZ(requestMessageTask, requestContext) } } } @@ -217,18 +213,16 @@ final case class OntologiesRouteV2()( put { // Change the labels or comments of a class. entity(as[String]) { jsonRequest => requestContext => - { - val requestMessageTask = for { - requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) - requestDoc <- RouteUtilV2.parseJsonLd(jsonRequest) - apiRequestId <- RouteUtilZ.randomUuid() - requestMessage <- - ZIO.attempt( - ChangeClassLabelsOrCommentsRequestV2.fromJsonLd(requestDoc, apiRequestId, requestingUser), - ) - } yield requestMessage - RouteUtilV2.runRdfRouteZ(requestMessageTask, requestContext) - } + val requestMessageTask = for { + requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) + requestDoc <- RouteUtilV2.parseJsonLd(jsonRequest) + apiRequestId <- RouteUtilZ.randomUuid() + requestMessage <- + ZIO.attempt( + ChangeClassLabelsOrCommentsRequestV2.fromJsonLd(requestDoc, apiRequestId, requestingUser), + ) + } yield requestMessage + RouteUtilV2.runRdfRouteZ(requestMessageTask, requestContext) } } } @@ -256,16 +250,14 @@ final case class OntologiesRouteV2()( post { // Add cardinalities to a class. entity(as[String]) { jsonRequest => requestContext => - { - val requestMessageTask = for { - requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) - requestDoc <- RouteUtilV2.parseJsonLd(jsonRequest) - apiRequestId <- RouteUtilZ.randomUuid() - requestMessage <- - ZIO.attempt(AddCardinalitiesToClassRequestV2.fromJsonLd(requestDoc, apiRequestId, requestingUser)) - } yield requestMessage - RouteUtilV2.runRdfRouteZ(requestMessageTask, requestContext) - } + val requestMessageTask = for { + requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) + requestDoc <- RouteUtilV2.parseJsonLd(jsonRequest) + apiRequestId <- RouteUtilZ.randomUuid() + requestMessage <- + ZIO.attempt(AddCardinalitiesToClassRequestV2.fromJsonLd(requestDoc, apiRequestId, requestingUser)) + } yield requestMessage + RouteUtilV2.runRdfRouteZ(requestMessageTask, requestContext) } } } @@ -290,15 +282,13 @@ final case class OntologiesRouteV2()( path(ontologiesBasePath / "cardinalities") { put { entity(as[String]) { reqBody => requestContext => - { - val messageTask = for { - user <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) - document <- RouteUtilV2.parseJsonLd(reqBody) - apiRequestId <- RouteUtilZ.randomUuid() - msg <- ZIO.attempt(ReplaceClassCardinalitiesRequestV2.fromJsonLd(document, apiRequestId, user)) - } yield msg - RouteUtilV2.runRdfRouteZ(messageTask, requestContext) - } + val messageTask = for { + user <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) + document <- RouteUtilV2.parseJsonLd(reqBody) + apiRequestId <- RouteUtilZ.randomUuid() + msg <- ZIO.attempt(ReplaceClassCardinalitiesRequestV2.fromJsonLd(document, apiRequestId, user)) + } yield msg + RouteUtilV2.runRdfRouteZ(messageTask, requestContext) } } } @@ -307,17 +297,15 @@ final case class OntologiesRouteV2()( path(ontologiesBasePath / "candeletecardinalities") { post { entity(as[String]) { jsonRequest => requestContext => - { - val messageTask = for { - requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) - requestDoc <- RouteUtilV2.parseJsonLd(jsonRequest) - apiRequestId <- RouteUtilZ.randomUuid() - msg <- ZIO.attempt( - CanDeleteCardinalitiesFromClassRequestV2.fromJsonLd(requestDoc, apiRequestId, requestingUser), - ) - } yield msg - RouteUtilV2.runRdfRouteZ(messageTask, requestContext) - } + val messageTask = for { + requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) + requestDoc <- RouteUtilV2.parseJsonLd(jsonRequest) + apiRequestId <- RouteUtilZ.randomUuid() + msg <- ZIO.attempt( + CanDeleteCardinalitiesFromClassRequestV2.fromJsonLd(requestDoc, apiRequestId, requestingUser), + ) + } yield msg + RouteUtilV2.runRdfRouteZ(messageTask, requestContext) } } } @@ -328,16 +316,14 @@ final case class OntologiesRouteV2()( path(ontologiesBasePath / "cardinalities") { patch { entity(as[String]) { jsonRequest => requestContext => - { - val requestMessageTask = for { - requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) - requestDoc <- RouteUtilV2.parseJsonLd(jsonRequest) - apiRequestId <- RouteUtilZ.randomUuid() - msg <- - ZIO.attempt(DeleteCardinalitiesFromClassRequestV2.fromJsonLd(requestDoc, apiRequestId, requestingUser)) - } yield msg - RouteUtilV2.runRdfRouteZ(requestMessageTask, requestContext) - } + val requestMessageTask = for { + requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) + requestDoc <- RouteUtilV2.parseJsonLd(jsonRequest) + apiRequestId <- RouteUtilZ.randomUuid() + msg <- + ZIO.attempt(DeleteCardinalitiesFromClassRequestV2.fromJsonLd(requestDoc, apiRequestId, requestingUser)) + } yield msg + RouteUtilV2.runRdfRouteZ(requestMessageTask, requestContext) } } } @@ -347,15 +333,13 @@ final case class OntologiesRouteV2()( put { // Change a class's cardinalities. entity(as[String]) { jsonRequest => requestContext => - { - val requestMessageTask = for { - requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) - requestDoc <- RouteUtilV2.parseJsonLd(jsonRequest) - apiRequestId <- RouteUtilZ.randomUuid() - msg <- ZIO.attempt(ChangeGuiOrderRequestV2.fromJsonLd(requestDoc, apiRequestId, requestingUser)) - } yield msg - RouteUtilV2.runRdfRouteZ(requestMessageTask, requestContext) - } + val requestMessageTask = for { + requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) + requestDoc <- RouteUtilV2.parseJsonLd(jsonRequest) + apiRequestId <- RouteUtilZ.randomUuid() + msg <- ZIO.attempt(ChangeGuiOrderRequestV2.fromJsonLd(requestDoc, apiRequestId, requestingUser)) + } yield msg + RouteUtilV2.runRdfRouteZ(requestMessageTask, requestContext) } } } @@ -461,142 +445,140 @@ final case class OntologiesRouteV2()( post { // Create a new property. entity(as[String]) { jsonRequest => requestContext => - { - val requestMessageTask = for { - requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) - requestDoc <- RouteUtilV2.parseJsonLd(jsonRequest) - inputOntology <- getInputOntology(requestDoc) - propertyUpdateInfo <- getPropertyDef(inputOntology) - propertyInfoContent: PropertyInfoContentV2 = propertyUpdateInfo.propertyInfoContent - _ <- PropertyIri.make(propertyInfoContent.propertyIri.toString).toZIO - - // get gui related values from request and validate them by making value objects from it - // get the (optional) gui element from the request - maybeGuiElement <- getGuiElement(propertyInfoContent) - // get the gui attribute(s) from the request - maybeGuiAttributes <- getGuiAttributes(propertyInfoContent) - _ <- GuiObject - .makeFromStrings(maybeGuiAttributes, maybeGuiElement) - .toZIO - .mapError(error => BadRequestException(error.msg)) - - apiRequestId <- RouteUtilZ.randomUuid() - requestMessage <- - ZIO.attempt(CreatePropertyRequestV2.fromJsonLd(requestDoc, apiRequestId, requestingUser)) - - // get gui related values from request and validate them by making value objects from it - - // get ontology info from request - inputOntology <- getInputOntology(requestDoc) - propertyInfoContent <- getPropertyDef(inputOntology).map(_.propertyInfoContent) - - // get the (optional) gui element - // get the (optional) gui element from the request - maybeGuiElement <- getGuiElement(propertyInfoContent) - - // validate the gui element by creating value object - validatedGuiElement = maybeGuiElement match { - case Some(guiElement) => GuiElement.make(guiElement).map(Some(_)) - case None => Validation.succeed(None) - } - maybeGuiAttributes <- getGuiAttributes(propertyInfoContent) - - // validate the gui attributes by creating value objects - guiAttributes = maybeGuiAttributes.map(guiAttribute => GuiAttribute.make(guiAttribute)) - - validatedGuiAttributes = Validation.validateAll(guiAttributes).map(_.toSet) - - // validate the combination of gui element and gui attribute by creating a GuiObject value object - guiObject = Validation - .validate(validatedGuiAttributes, validatedGuiElement) - .flatMap(values => GuiObject.make(values._1, values._2)) - - ontologyIri <- - ZIO.serviceWithZIO[IriConverter](_.asSmartIri(inputOntology.ontologyMetadata.ontologyIri.toString)) - lastModificationDate = Validation.succeed(propertyUpdateInfo.lastModificationDate) - propertyIri <- ZIO - .serviceWithZIO[IriConverter](_.asSmartIri(propertyInfoContent.propertyIri.toString)) - subClassConstraintSmartIri <- - RouteUtilZ.toSmartIri(OntologyConstants.KnoraBase.SubjectClassConstraint, "Should not happen") - subjectType <- - propertyInfoContent.predicates.get(subClassConstraintSmartIri) match { - case None => ZIO.succeed(None) - case Some(value) => - value.objects.head match { - case objectType: SmartIriLiteralV2 => - ZIO - .serviceWithZIO[IriConverter]( - _.asSmartIri(objectType.value.toOntologySchema(InternalSchema).toString), - ) - .map(Some(_)) - case other => - ZIO.fail(ValidationException(s"Unexpected subject type for $other")) - } - } - objectTypeSmartIri <- RouteUtilZ - .toSmartIri(OntologyConstants.KnoraApiV2Complex.ObjectType, "Should not happen") - objectType <- - propertyInfoContent.predicates.get(objectTypeSmartIri) match { - case None => - ZIO.fail(ValidationException(s"Object type cannot be empty.")) - case Some(value) => - value.objects.head match { - case objectType: SmartIriLiteralV2 => - ZIO - .serviceWithZIO[IriConverter]( - _.asSmartIri(objectType.value.toOntologySchema(InternalSchema).toString), - ) - case other => - ZIO.fail(ValidationException(s"Unexpected object type for $other")) + val requestMessageTask = for { + requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) + requestDoc <- RouteUtilV2.parseJsonLd(jsonRequest) + inputOntology <- getInputOntology(requestDoc) + propertyUpdateInfo <- getPropertyDef(inputOntology) + propertyInfoContent: PropertyInfoContentV2 = propertyUpdateInfo.propertyInfoContent + _ <- PropertyIri.make(propertyInfoContent.propertyIri.toString).toZIO + + // get gui related values from request and validate them by making value objects from it + // get the (optional) gui element from the request + maybeGuiElement <- getGuiElement(propertyInfoContent) + // get the gui attribute(s) from the request + maybeGuiAttributes <- getGuiAttributes(propertyInfoContent) + _ <- GuiObject + .makeFromStrings(maybeGuiAttributes, maybeGuiElement) + .toZIO + .mapError(error => BadRequestException(error.msg)) + + apiRequestId <- RouteUtilZ.randomUuid() + requestMessage <- + ZIO.attempt(CreatePropertyRequestV2.fromJsonLd(requestDoc, apiRequestId, requestingUser)) + + // get gui related values from request and validate them by making value objects from it + + // get ontology info from request + inputOntology <- getInputOntology(requestDoc) + propertyInfoContent <- getPropertyDef(inputOntology).map(_.propertyInfoContent) + + // get the (optional) gui element + // get the (optional) gui element from the request + maybeGuiElement <- getGuiElement(propertyInfoContent) + + // validate the gui element by creating value object + validatedGuiElement = maybeGuiElement match { + case Some(guiElement) => GuiElement.make(guiElement).map(Some(_)) + case None => Validation.succeed(None) + } + maybeGuiAttributes <- getGuiAttributes(propertyInfoContent) + + // validate the gui attributes by creating value objects + guiAttributes = maybeGuiAttributes.map(guiAttribute => GuiAttribute.make(guiAttribute)) + + validatedGuiAttributes = Validation.validateAll(guiAttributes).map(_.toSet) + + // validate the combination of gui element and gui attribute by creating a GuiObject value object + guiObject = Validation + .validate(validatedGuiAttributes, validatedGuiElement) + .flatMap(values => GuiObject.make(values._1, values._2)) + + ontologyIri <- + ZIO.serviceWithZIO[IriConverter](_.asSmartIri(inputOntology.ontologyMetadata.ontologyIri.toString)) + lastModificationDate = Validation.succeed(propertyUpdateInfo.lastModificationDate) + propertyIri <- ZIO + .serviceWithZIO[IriConverter](_.asSmartIri(propertyInfoContent.propertyIri.toString)) + subClassConstraintSmartIri <- + RouteUtilZ.toSmartIri(OntologyConstants.KnoraBase.SubjectClassConstraint, "Should not happen") + subjectType <- + propertyInfoContent.predicates.get(subClassConstraintSmartIri) match { + case None => ZIO.succeed(None) + case Some(value) => + value.objects.head match { + case objectType: SmartIriLiteralV2 => + ZIO + .serviceWithZIO[IriConverter]( + _.asSmartIri(objectType.value.toOntologySchema(InternalSchema).toString), + ) + .map(Some(_)) + case other => + ZIO.fail(ValidationException(s"Unexpected subject type for $other")) + } + } + objectTypeSmartIri <- RouteUtilZ + .toSmartIri(OntologyConstants.KnoraApiV2Complex.ObjectType, "Should not happen") + objectType <- + propertyInfoContent.predicates.get(objectTypeSmartIri) match { + case None => + ZIO.fail(ValidationException(s"Object type cannot be empty.")) + case Some(value) => + value.objects.head match { + case objectType: SmartIriLiteralV2 => + ZIO + .serviceWithZIO[IriConverter]( + _.asSmartIri(objectType.value.toOntologySchema(InternalSchema).toString), + ) + case other => + ZIO.fail(ValidationException(s"Unexpected object type for $other")) + } + } + labelSmartIri <- RouteUtilZ.toSmartIri(OntologyConstants.Rdfs.Label, "Should not happen") + label = propertyInfoContent.predicates.get(labelSmartIri) match { + case None => Validation.fail(ValidationException("Label missing")) + case Some(value) => + value.objects.head match { + case StringLiteralV2(value, Some(language)) => LangString.makeFromStrings(language, value) + case StringLiteralV2(_, None) => + Validation.fail(ValidationException("Label missing the language tag")) + case _ => Validation.fail(ValidationException("Unexpected Type for Label")) + } } - } - labelSmartIri <- RouteUtilZ.toSmartIri(OntologyConstants.Rdfs.Label, "Should not happen") - label = propertyInfoContent.predicates.get(labelSmartIri) match { - case None => Validation.fail(ValidationException("Label missing")) + commentSmartIri <- RouteUtilZ.toSmartIri(OntologyConstants.Rdfs.Comment, "Should not happen") + comment = propertyInfoContent.predicates.get(commentSmartIri) match { + case None => Validation.succeed(None) case Some(value) => value.objects.head match { - case StringLiteralV2(value, Some(language)) => LangString.makeFromStrings(language, value) + case StringLiteralV2(value, Some(language)) => + LangString.makeFromStrings(language, value).map(Some(_)) case StringLiteralV2(_, None) => - Validation.fail(ValidationException("Label missing the language tag")) - case _ => Validation.fail(ValidationException("Unexpected Type for Label")) + Validation.fail(ValidationException("Comment missing the language tag")) + case _ => Validation.fail(ValidationException("Unexpected Type for Comment")) } } - commentSmartIri <- RouteUtilZ.toSmartIri(OntologyConstants.Rdfs.Comment, "Should not happen") - comment = propertyInfoContent.predicates.get(commentSmartIri) match { - case None => Validation.succeed(None) - case Some(value) => - value.objects.head match { - case StringLiteralV2(value, Some(language)) => - LangString.makeFromStrings(language, value).map(Some(_)) - case StringLiteralV2(_, None) => - Validation.fail(ValidationException("Comment missing the language tag")) - case _ => Validation.fail(ValidationException("Unexpected Type for Comment")) - } - } - superProperties = - propertyInfoContent.subPropertyOf.toList match { - case Nil => Validation.fail(ValidationException("SuperProperties cannot be empty.")) - case superProps => Validation.succeed(superProps) - } - - _ <- - Validation - .validate( - lastModificationDate, - label, - comment, - superProperties, - guiObject, - ) - .flatMap(v => - CreatePropertyCommand - .make(ontologyIri, v._1, propertyIri, subjectType, objectType, v._2, v._3, v._4, v._5), - ) - .toZIO - } yield requestMessage - - RouteUtilV2.runRdfRouteZ(requestMessageTask, requestContext) - } + superProperties = + propertyInfoContent.subPropertyOf.toList match { + case Nil => Validation.fail(ValidationException("SuperProperties cannot be empty.")) + case superProps => Validation.succeed(superProps) + } + + _ <- + Validation + .validate( + lastModificationDate, + label, + comment, + superProperties, + guiObject, + ) + .flatMap(v => + CreatePropertyCommand + .make(ontologyIri, v._1, propertyIri, subjectType, objectType, v._2, v._3, v._4, v._5), + ) + .toZIO + } yield requestMessage + + RouteUtilV2.runRdfRouteZ(requestMessageTask, requestContext) } } } @@ -643,18 +625,16 @@ final case class OntologiesRouteV2()( put { // Change the labels or comments of a property. entity(as[String]) { jsonRequest => requestContext => - { - val requestMessageTask = for { - requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) - requestDoc <- RouteUtilV2.parseJsonLd(jsonRequest) - apiRequestId <- RouteUtilZ.randomUuid() - requestMessage <- - ZIO.attempt( - ChangePropertyLabelsOrCommentsRequestV2.fromJsonLd(requestDoc, apiRequestId, requestingUser), - ) - } yield requestMessage - RouteUtilV2.runRdfRouteZ(requestMessageTask, requestContext) - } + val requestMessageTask = for { + requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) + requestDoc <- RouteUtilV2.parseJsonLd(jsonRequest) + apiRequestId <- RouteUtilZ.randomUuid() + requestMessage <- + ZIO.attempt( + ChangePropertyLabelsOrCommentsRequestV2.fromJsonLd(requestDoc, apiRequestId, requestingUser), + ) + } yield requestMessage + RouteUtilV2.runRdfRouteZ(requestMessageTask, requestContext) } } } @@ -680,32 +660,30 @@ final case class OntologiesRouteV2()( put { // Change the salsah-gui:guiElement and/or salsah-gui:guiAttribute of a property. entity(as[String]) { jsonRequest => requestContext => - { - val requestTask = for { - requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) - requestDoc <- RouteUtilV2.parseJsonLd(jsonRequest) - inputOntology <- getInputOntology(requestDoc) - propertyUpdateInfo <- getPropertyDef(inputOntology) - propertyInfoContent = propertyUpdateInfo.propertyInfoContent - lastModificationDate = propertyUpdateInfo.lastModificationDate - propertyIri <- PropertyIri.make(propertyInfoContent.propertyIri.toString).toZIO - newGuiElement <- getGuiElement(propertyInfoContent) - newGuiAttributes <- getGuiAttributes(propertyInfoContent) - guiObject <- - GuiObject - .makeFromStrings(newGuiAttributes, newGuiElement) - .toZIO - .mapError(e => BadRequestException(e.msg)) - apiRequestId <- RouteUtilZ.randomUuid() - } yield ChangePropertyGuiElementRequest( - propertyIri, - guiObject, - lastModificationDate, - apiRequestId, - requestingUser, - ) - RouteUtilV2.runRdfRouteZ(requestTask, requestContext) - } + val requestTask = for { + requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) + requestDoc <- RouteUtilV2.parseJsonLd(jsonRequest) + inputOntology <- getInputOntology(requestDoc) + propertyUpdateInfo <- getPropertyDef(inputOntology) + propertyInfoContent = propertyUpdateInfo.propertyInfoContent + lastModificationDate = propertyUpdateInfo.lastModificationDate + propertyIri <- PropertyIri.make(propertyInfoContent.propertyIri.toString).toZIO + newGuiElement <- getGuiElement(propertyInfoContent) + newGuiAttributes <- getGuiAttributes(propertyInfoContent) + guiObject <- + GuiObject + .makeFromStrings(newGuiAttributes, newGuiElement) + .toZIO + .mapError(e => BadRequestException(e.msg)) + apiRequestId <- RouteUtilZ.randomUuid() + } yield ChangePropertyGuiElementRequest( + propertyIri, + guiObject, + lastModificationDate, + apiRequestId, + requestingUser, + ) + RouteUtilV2.runRdfRouteZ(requestTask, requestContext) } } } @@ -783,15 +761,13 @@ final case class OntologiesRouteV2()( // Create a new, empty ontology. post { entity(as[String]) { jsonRequest => requestContext => - { - val t = for { - requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) - requestDoc <- RouteUtilV2.parseJsonLd(jsonRequest) - apiRequestId <- RouteUtilZ.randomUuid() - requestMessage <- CreateOntologyRequestV2.fromJsonLd(requestDoc, apiRequestId, requestingUser) - } yield requestMessage - RouteUtilV2.runRdfRouteZ(t, requestContext) - } + val t = for { + requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) + requestDoc <- RouteUtilV2.parseJsonLd(jsonRequest) + apiRequestId <- RouteUtilZ.randomUuid() + requestMessage <- CreateOntologyRequestV2.fromJsonLd(requestDoc, apiRequestId, requestingUser) + } yield requestMessage + RouteUtilV2.runRdfRouteZ(t, requestContext) } } } diff --git a/webapi/src/main/scala/org/knora/webapi/routing/v2/ResourcesRouteV2.scala b/webapi/src/main/scala/org/knora/webapi/routing/v2/ResourcesRouteV2.scala index 374c625405..891eb014c9 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/v2/ResourcesRouteV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/v2/ResourcesRouteV2.scala @@ -100,18 +100,16 @@ final case class ResourcesRouteV2(appConfig: AppConfig)( private def createResource(): Route = path(resourcesBasePath) { post { entity(as[String]) { jsonRequest => requestContext => - { - val requestTask = for { - requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) - apiRequestId <- RouteUtilZ.randomUuid() - requestMessage <- jsonLdRequestParser( - _.createResourceRequestV2(jsonRequest, requestingUser, apiRequestId), - ).mapError(BadRequestException.apply) - // check for each value which represents a file value if the file's MIME type is allowed - _ <- checkMimeTypesForFileValueContents(requestMessage.createResource.flatValues) - } yield requestMessage - RouteUtilV2.runRdfRouteZ(requestTask, requestContext) - } + val requestTask = for { + requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) + apiRequestId <- RouteUtilZ.randomUuid() + requestMessage <- jsonLdRequestParser( + _.createResourceRequestV2(jsonRequest, requestingUser, apiRequestId), + ).mapError(BadRequestException.apply) + // check for each value which represents a file value if the file's MIME type is allowed + _ <- checkMimeTypesForFileValueContents(requestMessage.createResource.flatValues) + } yield requestMessage + RouteUtilV2.runRdfRouteZ(requestTask, requestContext) } } } @@ -119,16 +117,14 @@ final case class ResourcesRouteV2(appConfig: AppConfig)( private def updateResourceMetadata(): Route = path(resourcesBasePath) { put { entity(as[String]) { jsonRequest => requestContext => - { - val requestMessageFuture = for { - requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) - apiRequestId <- RouteUtilZ.randomUuid() - requestMessage <- - jsonLdRequestParser(_.updateResourceMetadataRequestV2(jsonRequest, requestingUser, apiRequestId)) - .mapError(BadRequestException.apply) - } yield requestMessage - RouteUtilV2.runRdfRouteZ(requestMessageFuture, requestContext) - } + val requestMessageFuture = for { + requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) + apiRequestId <- RouteUtilZ.randomUuid() + requestMessage <- + jsonLdRequestParser(_.updateResourceMetadataRequestV2(jsonRequest, requestingUser, apiRequestId)) + .mapError(BadRequestException.apply) + } yield requestMessage + RouteUtilV2.runRdfRouteZ(requestMessageFuture, requestContext) } } } @@ -380,15 +376,13 @@ final case class ResourcesRouteV2(appConfig: AppConfig)( private def deleteResource(): Route = path(resourcesBasePath / "delete") { post { entity(as[String]) { jsonRequest => requestContext => - { - val requestTask = for { - apiRequestId <- RouteUtilZ.randomUuid() - requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) - msg <- jsonLdRequestParser(_.deleteOrEraseResourceRequestV2(jsonRequest, requestingUser, apiRequestId)) - .mapError(BadRequestException.apply) - } yield msg - RouteUtilV2.runRdfRouteZ(requestTask, requestContext) - } + val requestTask = for { + apiRequestId <- RouteUtilZ.randomUuid() + requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) + msg <- jsonLdRequestParser(_.deleteOrEraseResourceRequestV2(jsonRequest, requestingUser, apiRequestId)) + .mapError(BadRequestException.apply) + } yield msg + RouteUtilV2.runRdfRouteZ(requestTask, requestContext) } } } @@ -396,16 +390,14 @@ final case class ResourcesRouteV2(appConfig: AppConfig)( private def eraseResource(): Route = path(resourcesBasePath / "erase") { post { entity(as[String]) { jsonRequest => requestContext => - { - val requestTask = for { - apiRequestId <- RouteUtilZ.randomUuid() - requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) - requestMessage <- - jsonLdRequestParser(_.deleteOrEraseResourceRequestV2(jsonRequest, requestingUser, apiRequestId)) - .mapError(BadRequestException.apply) - } yield requestMessage.copy(erase = true) - RouteUtilV2.runRdfRouteZ(requestTask, requestContext) - } + val requestTask = for { + apiRequestId <- RouteUtilZ.randomUuid() + requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) + requestMessage <- + jsonLdRequestParser(_.deleteOrEraseResourceRequestV2(jsonRequest, requestingUser, apiRequestId)) + .mapError(BadRequestException.apply) + } yield requestMessage.copy(erase = true) + RouteUtilV2.runRdfRouteZ(requestTask, requestContext) } } } diff --git a/webapi/src/main/scala/org/knora/webapi/routing/v2/ValuesRouteV2.scala b/webapi/src/main/scala/org/knora/webapi/routing/v2/ValuesRouteV2.scala index 89a1b3bd0f..64bbe0394f 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/v2/ValuesRouteV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/v2/ValuesRouteV2.scala @@ -81,19 +81,17 @@ final case class ValuesRouteV2()( private def createValue(): Route = path(valuesBasePath) { post { entity(as[String]) { jsonLdString => ctx => - { - RouteUtilV2.completeResponse( - for { - requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(ctx)) - apiRequestId <- Random.nextUUID - valueToCreate <- jsonLdRequestParser( - _.createValueV2FromJsonLd(jsonLdString).mapError(BadRequestException(_)), - ) - response <- responder(_.createValueV2(valueToCreate, requestingUser, apiRequestId)) - } yield response, - ctx, - ) - } + RouteUtilV2.completeResponse( + for { + requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(ctx)) + apiRequestId <- Random.nextUUID + valueToCreate <- jsonLdRequestParser( + _.createValueV2FromJsonLd(jsonLdString).mapError(BadRequestException(_)), + ) + response <- responder(_.createValueV2(valueToCreate, requestingUser, apiRequestId)) + } yield response, + ctx, + ) } } } @@ -101,19 +99,17 @@ final case class ValuesRouteV2()( private def updateValue(): Route = path(valuesBasePath) { put { entity(as[String]) { jsonLdString => ctx => - { - RouteUtilV2.completeResponse( - for { - requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(ctx)) - apiRequestId <- Random.nextUUID - updateValue <- jsonLdRequestParser( - _.updateValueV2fromJsonLd(jsonLdString).mapError(BadRequestException(_)), - ) - response <- responder(_.updateValueV2(updateValue, requestingUser, apiRequestId)) - } yield response, - ctx, - ) - } + RouteUtilV2.completeResponse( + for { + requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(ctx)) + apiRequestId <- Random.nextUUID + updateValue <- jsonLdRequestParser( + _.updateValueV2fromJsonLd(jsonLdString).mapError(BadRequestException(_)), + ) + response <- responder(_.updateValueV2(updateValue, requestingUser, apiRequestId)) + } yield response, + ctx, + ) } } } @@ -121,18 +117,16 @@ final case class ValuesRouteV2()( private def deleteValue(): Route = path(valuesBasePath / "delete") { post { entity(as[String]) { jsonLdString => requestContext => - { - RouteUtilV2.completeResponse( - for { - requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) - apiRequestId <- RouteUtilZ.randomUuid() - deleteValue <- - jsonLdRequestParser(_.deleteValueV2FromJsonLd(jsonLdString).mapError(BadRequestException(_))) - response <- responder(_.deleteValueV2(deleteValue, requestingUser, apiRequestId)) - } yield response, - requestContext, - ) - } + RouteUtilV2.completeResponse( + for { + requestingUser <- ZIO.serviceWithZIO[Authenticator](_.getUserADM(requestContext)) + apiRequestId <- RouteUtilZ.randomUuid() + deleteValue <- + jsonLdRequestParser(_.deleteValueV2FromJsonLd(jsonLdString).mapError(BadRequestException(_))) + response <- responder(_.deleteValueV2(deleteValue, requestingUser, apiRequestId)) + } yield response, + requestContext, + ) } } } diff --git a/webapi/src/main/scala/org/knora/webapi/slice/admin/api/service/StoreRestService.scala b/webapi/src/main/scala/org/knora/webapi/slice/admin/api/service/StoreRestService.scala index fb6e7fb349..5018c85fb0 100644 --- a/webapi/src/main/scala/org/knora/webapi/slice/admin/api/service/StoreRestService.scala +++ b/webapi/src/main/scala/org/knora/webapi/slice/admin/api/service/StoreRestService.scala @@ -10,7 +10,6 @@ import zio.* import dsp.errors.ForbiddenException import org.knora.webapi.config.AppConfig import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject -import org.knora.webapi.messages.util.KnoraSystemInstances.Users.SystemUser import org.knora.webapi.slice.admin.api.MessageResponse import org.knora.webapi.slice.infrastructure.CacheManager import org.knora.webapi.slice.ontology.repo.service.OntologyCache @@ -42,7 +41,7 @@ final case class StoreRestService( } _ <- ZIO.logWarning(s"Resetting triplestore content with ${rdfDataObjects.map(_.name).mkString(", ")}") _ <- triplestoreService.resetTripleStoreContent(rdfDataObjects, prependDefaults).logError - _ <- ontologyCache.loadOntologies(SystemUser).logError + _ <- ontologyCache.loadOntologies().logError _ = cacheManager.clearAll() } yield MessageResponse("success") } diff --git a/webapi/src/main/scala/org/knora/webapi/slice/admin/domain/model/User.scala b/webapi/src/main/scala/org/knora/webapi/slice/admin/domain/model/User.scala index 419a889fdc..59dcb12727 100644 --- a/webapi/src/main/scala/org/knora/webapi/slice/admin/domain/model/User.scala +++ b/webapi/src/main/scala/org/knora/webapi/slice/admin/domain/model/User.scala @@ -203,7 +203,7 @@ object Username extends StringValueCompanion[Username] { "[a-zA-Z0-9._-]+" + // Only contains alphanumeric characters, underscore, hyphen and dot. "(? TriplePattern): Task[Option[E]] = - findOneByQuery(findByTriplePatternQuery(pattern)) + protected def findOneByPattern(pattern: RdfSubject => GraphPattern): Task[Option[E]] = + findOneByQuery(findByPatternQuery(pattern)) - protected def findAllByTriplePattern(pattern: RdfSubject => TriplePattern): Task[Chunk[E]] = - findAllByQuery(findByTriplePatternQuery(pattern)) + protected def findAllByPattern(pattern: RdfSubject => GraphPattern): Task[Chunk[E]] = + findAllByQuery(findByPatternQuery(pattern)) - private def findByTriplePatternQuery(pattern: RdfSubject => TriplePattern) = { + private def findByPatternQuery(pattern: RdfSubject => GraphPattern) = { val s = variable("s") val query: String = entityQuery(tripleP(s), graphP(s).and(pattern(s))).getQueryString Construct(query) } - protected def findOneByQuery(construct: Construct): Task[Option[E]] = + private def findOneByQuery(construct: Construct): Task[Option[E]] = runQuery(construct) .map(_.nextOption()) .flatMap(ZIO.foreach(_)(mapper.toEntity(_).mapError(TriplestoreResponseException.apply))) - protected def findAllByQuery(construct: Construct): Task[Chunk[E]] = + private def findAllByQuery(construct: Construct): Task[Chunk[E]] = runQuery(construct).flatMap( ZStream.fromIterator(_).mapZIO(mapper.toEntity(_).mapError(TriplestoreResponseException.apply)).runCollect, ) diff --git a/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/AdministrativePermissionRepoLive.scala b/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/AdministrativePermissionRepoLive.scala index 5913672901..65d8f0fd5b 100644 --- a/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/AdministrativePermissionRepoLive.scala +++ b/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/AdministrativePermissionRepoLive.scala @@ -60,13 +60,13 @@ final case class AdministrativePermissionRepoLive( groupIri: GroupIri, projectIri: ProjectIri, ): Task[Option[AdministrativePermission]] = - findOneByTriplePattern( + findOneByPattern( _.has(Vocabulary.KnoraAdmin.forGroup, Rdf.iri(groupIri.value)) .andHas(Vocabulary.KnoraAdmin.forProject, Rdf.iri(projectIri.value)), ) override def findByProject(projectIri: ProjectIri): Task[Chunk[AdministrativePermission]] = - findAllByTriplePattern(_.has(Vocabulary.KnoraAdmin.forProject, Rdf.iri(projectIri.value))) + findAllByPattern(_.has(Vocabulary.KnoraAdmin.forProject, Rdf.iri(projectIri.value))) } object AdministrativePermissionRepoLive { diff --git a/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/DefaultObjectAccessPermissionRepoLive.scala b/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/DefaultObjectAccessPermissionRepoLive.scala index 37c7d76606..b2431ff294 100644 --- a/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/DefaultObjectAccessPermissionRepoLive.scala +++ b/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/DefaultObjectAccessPermissionRepoLive.scala @@ -6,6 +6,7 @@ package org.knora.webapi.slice.admin.repo.service import org.eclipse.rdf4j.common.net.ParsedIRI +import org.eclipse.rdf4j.sparqlbuilder.core.SparqlBuilder.`var` as variable import org.eclipse.rdf4j.sparqlbuilder.graphpattern.TriplePattern import org.eclipse.rdf4j.sparqlbuilder.rdf.Iri import org.eclipse.rdf4j.sparqlbuilder.rdf.Rdf @@ -54,15 +55,23 @@ final case class DefaultObjectAccessPermissionRepoLive( ) override def findByProject(projectIri: ProjectIri): Task[Chunk[DefaultObjectAccessPermission]] = - findAllByTriplePattern(_.has(Vocabulary.KnoraAdmin.forProject, Rdf.iri(projectIri.value))) + findAllByPattern(_.has(Vocabulary.KnoraAdmin.forProject, Rdf.iri(projectIri.value))) def findByProjectAndForWhat(projectIri: ProjectIri, forWhat: ForWhat): Task[Option[DefaultObjectAccessPermission]] = - findOneByTriplePattern(p => + findOneByPattern(p => val pattern = p.has(Vocabulary.KnoraAdmin.forProject, Rdf.iri(projectIri.value)) forWhat match { - case Group(g) => pattern.andHas(Vocabulary.KnoraAdmin.forGroup, Rdf.iri(g.value)) - case ResourceClass(rc) => pattern.andHas(Vocabulary.KnoraAdmin.forResourceClass, Rdf.iri(rc.value)) - case Property(prop) => pattern.andHas(Vocabulary.KnoraAdmin.forProperty, Rdf.iri(prop.value)) + case Group(g) => pattern.andHas(Vocabulary.KnoraAdmin.forGroup, Rdf.iri(g.value)) + case ResourceClass(rc) => + pattern + .andHas(Vocabulary.KnoraAdmin.forResourceClass, Rdf.iri(rc.value)) + .filterNotExists(p.has(Vocabulary.KnoraAdmin.forProperty, variable("prop"))) + + case Property(prop) => + pattern + .andHas(Vocabulary.KnoraAdmin.forProperty, Rdf.iri(prop.value)) + .filterNotExists(p.has(Vocabulary.KnoraAdmin.forResourceClass, variable("rc"))) + case ResourceClassAndProperty(rc, prop) => pattern .andHas(Vocabulary.KnoraAdmin.forResourceClass, Rdf.iri(rc.value)) diff --git a/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/EntityCache.scala b/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/EntityCache.scala index 098c31965a..8ae1d0aa0f 100644 --- a/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/EntityCache.scala +++ b/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/EntityCache.scala @@ -10,7 +10,6 @@ import zio.URLayer import zio.ZIO import zio.ZLayer -import scala.annotation.nowarn import scala.reflect.ClassTag import org.knora.webapi.slice.common.Value.StringValue @@ -24,8 +23,6 @@ final case class EntityCache[I <: StringValue, E <: EntityWithId[I]](cache: EhCa } object EntityCache { - - @nowarn // suppresses warnings about unused type parameters Tag def layer[I <: StringValue: ClassTag: Tag, E <: EntityWithId[I]: ClassTag: Tag]( cacheName: String, ): URLayer[CacheManager, EntityCache[I, E]] = diff --git a/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/KnoraGroupRepoLive.scala b/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/KnoraGroupRepoLive.scala index 32af7df8cb..5e257dad12 100644 --- a/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/KnoraGroupRepoLive.scala +++ b/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/KnoraGroupRepoLive.scala @@ -58,11 +58,11 @@ final case class KnoraGroupRepoLive( super.save(group) override def findByName(name: GroupName): Task[Option[KnoraGroup]] = - findOneByTriplePattern(_.has(groupName, Rdf.literalOf(name.value))) + findOneByPattern(_.has(groupName, Rdf.literalOf(name.value))) .map(_.orElse(KnoraGroupRepo.builtIn.findOneBy(_.groupName == name))) override def findByProjectIri(projectIri: ProjectIri): Task[Chunk[KnoraGroup]] = - findAllByTriplePattern(_.has(belongsToProject, Rdf.iri(projectIri.value))) + findAllByPattern(_.has(belongsToProject, Rdf.iri(projectIri.value))) } object KnoraGroupRepoLive { diff --git a/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/KnoraProjectRepoLive.scala b/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/KnoraProjectRepoLive.scala index ed3097a541..a56d446dfb 100644 --- a/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/KnoraProjectRepoLive.scala +++ b/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/KnoraProjectRepoLive.scala @@ -55,11 +55,11 @@ final case class KnoraProjectRepoLive( super.findById(id).map(_.orElse(KnoraProjectRepo.builtIn.findOneBy(_.id == id))) override def findByShortcode(shortcode: Shortcode): Task[Option[KnoraProject]] = - findOneByTriplePattern(_.has(Vocabulary.KnoraAdmin.projectShortcode, shortcode.value)) + findOneByPattern(_.has(Vocabulary.KnoraAdmin.projectShortcode, shortcode.value)) .map(_.orElse(KnoraProjectRepo.builtIn.findOneBy(_.shortcode == shortcode))) override def findByShortname(shortname: Shortname): Task[Option[KnoraProject]] = - findOneByTriplePattern(_.has(Vocabulary.KnoraAdmin.projectShortname, shortname.value)) + findOneByPattern(_.has(Vocabulary.KnoraAdmin.projectShortname, shortname.value)) .map(_.orElse(KnoraProjectRepo.builtIn.findOneBy(_.shortname == shortname))) override def findAll(): Task[Chunk[KnoraProject]] = super.findAll().map(_ ++ KnoraProjectRepo.builtIn.all) diff --git a/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/KnoraUserRepoLive.scala b/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/KnoraUserRepoLive.scala index 9d328a589a..3af1704d8f 100644 --- a/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/KnoraUserRepoLive.scala +++ b/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/KnoraUserRepoLive.scala @@ -59,23 +59,23 @@ final case class KnoraUserRepoLive( super.findById(id).map(_.orElse(KnoraUserRepo.builtIn.findOneBy(_.id == id))) override def findByProjectAdminMembership(projectIri: ProjectIri): Task[Chunk[KnoraUser]] = - findAllByTriplePattern(_.has(isInProjectAdminGroup, Rdf.iri(projectIri.value))) + findAllByPattern(_.has(isInProjectAdminGroup, Rdf.iri(projectIri.value))) .map(_ ++ KnoraUserRepo.builtIn.findAllBy(_.isInProjectAdminGroup.contains(projectIri))) override def findByProjectMembership(projectIri: ProjectIri): Task[Chunk[KnoraUser]] = - findAllByTriplePattern(_.has(isInProject, Rdf.iri(projectIri.value))) + findAllByPattern(_.has(isInProject, Rdf.iri(projectIri.value))) .map(_ ++ KnoraUserRepo.builtIn.findAllBy(_.isInProject.contains(projectIri))) override def findByGroupMembership(groupIri: GroupIri): Task[Chunk[KnoraUser]] = - findAllByTriplePattern(_.has(isInGroup, Rdf.iri(groupIri.value))) + findAllByPattern(_.has(isInGroup, Rdf.iri(groupIri.value))) .map(_ ++ KnoraUserRepo.builtIn.findAllBy(_.isInGroup.contains(groupIri))) override def findByEmail(mail: Email): Task[Option[KnoraUser]] = - findOneByTriplePattern(_.has(email, Rdf.literalOf(mail.value))) + findOneByPattern(_.has(email, Rdf.literalOf(mail.value))) .map(_.orElse(KnoraUserRepo.builtIn.findOneBy(_.email == mail))) override def findByUsername(name: Username): Task[Option[KnoraUser]] = - findOneByTriplePattern(_.has(username, Rdf.literalOf(name.value))) + findOneByPattern(_.has(username, Rdf.literalOf(name.value))) .map(_.orElse(KnoraUserRepo.builtIn.findOneBy(_.username == name))) override def save(user: KnoraUser): Task[KnoraUser] = diff --git a/webapi/src/main/scala/org/knora/webapi/slice/common/api/HandlerMapper.scala b/webapi/src/main/scala/org/knora/webapi/slice/common/api/HandlerMapper.scala index d87fe92c9b..34ad1bb4e1 100644 --- a/webapi/src/main/scala/org/knora/webapi/slice/common/api/HandlerMapper.scala +++ b/webapi/src/main/scala/org/knora/webapi/slice/common/api/HandlerMapper.scala @@ -48,7 +48,7 @@ final case class HandlerMapper()(implicit val r: zio.Runtime[Any]) { def mapSecuredEndpointHandler[INPUT, OUTPUT]( handlerAndEndpoint: SecuredEndpointHandler[INPUT, OUTPUT], ): Full[SecurityIn, User, INPUT, RequestRejectedException, OUTPUT, Any, Future] = - handlerAndEndpoint.endpoint.serverLogic(user => in => { runToFuture(handlerAndEndpoint.handler(user)(in)) }) + handlerAndEndpoint.endpoint.serverLogic(user => in => runToFuture(handlerAndEndpoint.handler(user)(in))) def mapPublicEndpointHandler[INPUT, OUTPUT]( handlerAndEndpoint: PublicEndpointHandler[INPUT, OUTPUT], diff --git a/webapi/src/main/scala/org/knora/webapi/slice/ontology/api/OntologyV2RequestParser.scala b/webapi/src/main/scala/org/knora/webapi/slice/ontology/api/OntologyV2RequestParser.scala index 13199af5a3..2ad5780c47 100644 --- a/webapi/src/main/scala/org/knora/webapi/slice/ontology/api/OntologyV2RequestParser.scala +++ b/webapi/src/main/scala/org/knora/webapi/slice/ontology/api/OntologyV2RequestParser.scala @@ -6,7 +6,7 @@ package org.knora.webapi.slice.ontology.api import org.apache.jena.rdf.model.* -import org.apache.jena.vocabulary.OWL +import org.apache.jena.vocabulary.OWL2 as OWL import org.apache.jena.vocabulary.RDFS import zio.* diff --git a/webapi/src/main/scala/org/knora/webapi/slice/ontology/repo/service/OntologyCache.scala b/webapi/src/main/scala/org/knora/webapi/slice/ontology/repo/service/OntologyCache.scala index 3cffc6881b..8b4de85646 100644 --- a/webapi/src/main/scala/org/knora/webapi/slice/ontology/repo/service/OntologyCache.scala +++ b/webapi/src/main/scala/org/knora/webapi/slice/ontology/repo/service/OntologyCache.scala @@ -21,13 +21,11 @@ import org.knora.webapi.messages.SmartIri import org.knora.webapi.messages.StringFormatter import org.knora.webapi.messages.twirl.queries.sparql import org.knora.webapi.messages.util.ErrorHandlingMap -import org.knora.webapi.messages.util.KnoraSystemInstances import org.knora.webapi.messages.util.OntologyUtil import org.knora.webapi.messages.v2.responder.ontologymessages.* import org.knora.webapi.messages.v2.responder.ontologymessages.OwlCardinality.* import org.knora.webapi.responders.v2.ontology.OntologyHelpers import org.knora.webapi.responders.v2.ontology.OntologyHelpers.OntologyGraph -import org.knora.webapi.slice.admin.domain.model.User import org.knora.webapi.slice.admin.domain.service.KnoraProjectRepo import org.knora.webapi.slice.ontology.repo.model.OntologyCacheData import org.knora.webapi.store.triplestore.api.TriplestoreService @@ -419,11 +417,8 @@ trait OntologyCache { /** * Loads and caches all ontology information. - * - * @param requestingUser the user making the request. - * @return [[Unit]] */ - def loadOntologies(requestingUser: User): Task[Unit] + def loadOntologies(): Task[Unit] /** * Gets the ontology data from the cache. @@ -475,12 +470,6 @@ trait OntologyCache { updatedClassIri: SmartIri, ): Task[OntologyCacheData] - /** - * Loads and caches all ontology information. - * - * @return [[Unit]] - */ - final def loadOntologies(): Task[Unit] = loadOntologies(KnoraSystemInstances.Users.SystemUser) } final case class OntologyCacheLive(triplestore: TriplestoreService, cacheDataRef: Ref[OntologyCacheData])(implicit @@ -490,19 +479,9 @@ final case class OntologyCacheLive(triplestore: TriplestoreService, cacheDataRef /** * Loads and caches all ontology information. - * - * @param requestingUser the user making the request. - * @return [[Unit]] */ - override def loadOntologies(requestingUser: User): Task[Unit] = + override def loadOntologies(): Task[Unit] = for { - _ <- - ZIO - .fail(ForbiddenException(s"Only a system administrator can reload ontologies")) - .when( - !(requestingUser.id == KnoraSystemInstances.Users.SystemUser.id || requestingUser.permissions.isSystemAdmin), - ) - // Get all ontology metadata. _ <- ZIO.logInfo(s"Loading ontologies into cache") allOntologyMetadataResponse <- triplestore.query(Select(sparql.v2.txt.getAllOntologyMetadata())) diff --git a/webapi/src/main/twirl/org/knora/webapi/messages/twirl/queries/sparql/admin/findAllAssets.scala.txt b/webapi/src/main/twirl/org/knora/webapi/messages/twirl/queries/sparql/admin/findAllAssets.scala.txt deleted file mode 100644 index f94e96b14f..0000000000 --- a/webapi/src/main/twirl/org/knora/webapi/messages/twirl/queries/sparql/admin/findAllAssets.scala.txt +++ /dev/null @@ -1,35 +0,0 @@ -@* - * Copyright © 2021 - 2024 Swiss National Data and Service Center for the Humanities and/or DaSCH Service Platform contributors. - * SPDX-License-Identifier: Apache-2.0 - *@ - -@import org.knora.webapi.slice.resourceinfo.domain.InternalIri - -@** - * Finds all assets belonging to a project. - * - * @param ontologyGraphs the ontology graphs belonging to the project. - * @param projectGraph the data graph for the project. - *@ - -@( - ontologyGraphs: List[InternalIri], - projectGraph: InternalIri, -) - -PREFIX rdf: -PREFIX : -PREFIX rdfs: - -SELECT ?internalFilename -# ontology graphs -@for(graph <- ontologyGraphs) { -FROM <@{graph.value}> -} -# project graphs -FROM <@{projectGraph.value}> -WHERE { - ?fileValueType rdfs:subClassOf* :FileValue . - ?s a ?fileValueType . - ?s ?internalFilename -} diff --git a/webapi/src/main/twirl/org/knora/webapi/messages/twirl/queries/sparql/admin/getProjectAdminData.scala.txt b/webapi/src/main/twirl/org/knora/webapi/messages/twirl/queries/sparql/admin/getProjectAdminData.scala.txt deleted file mode 100644 index 707fb80505..0000000000 --- a/webapi/src/main/twirl/org/knora/webapi/messages/twirl/queries/sparql/admin/getProjectAdminData.scala.txt +++ /dev/null @@ -1,35 +0,0 @@ -@* - * Copyright © 2021 - 2024 Swiss National Data and Service Center for the Humanities and/or DaSCH Service Platform contributors. - * SPDX-License-Identifier: Apache-2.0 - *@ - -@import org.knora.webapi.IRI - -@** - * Given a project IRI, returns all the admin data for that project. - * - * @param projectIri the project IRI. - *@ -@(projectIri: IRI) - -prefix knora-admin: - -CONSTRUCT { - ?project ?projectPred ?projectObj . - ?user ?userPred ?userObj . - ?group ?groupPred ?groupObj . -} - -WHERE { - BIND(IRI("@projectIri") as ?project) - - { - ?project ?projectPred ?projectObj . - } UNION { - ?user ?userPred ?userObj ; - knora-admin:isInProject ?project . - } UNION { - ?group ?groupPred ?groupObj ; - knora-admin:belongsToProject ?project . - } -} diff --git a/webapi/src/main/twirl/org/knora/webapi/messages/twirl/queries/sparql/admin/getProjects.scala.txt b/webapi/src/main/twirl/org/knora/webapi/messages/twirl/queries/sparql/admin/getProjects.scala.txt deleted file mode 100644 index b00a79be9a..0000000000 --- a/webapi/src/main/twirl/org/knora/webapi/messages/twirl/queries/sparql/admin/getProjects.scala.txt +++ /dev/null @@ -1,46 +0,0 @@ -@* - * Copyright © 2021 - 2024 Swiss National Data and Service Center for the Humanities and/or DaSCH Service Platform contributors. - * SPDX-License-Identifier: Apache-2.0 - *@ - -@import org.knora.webapi.IRI - -@** - * Gets all information about a single project or all projects. Selection either through the project's IRI, shortname, or shortcode. - * - * @param maybeIri the project's IRI. - * @param maybeShortname the project's shortname. - * @param maybeShortcode the project's shortcode. - *@ -@( - maybeIri: Option[IRI] = None, - maybeShortname: Option[String] = None, - maybeShortcode: Option[String] = None -) - -PREFIX xsd: -PREFIX rdf: -PREFIX knora-admin: -PREFIX knora-base: -PREFIX owl: - -CONSTRUCT { - ?project ?p ?o . -} -WHERE { - - @if(maybeIri.nonEmpty) { - BIND(IRI("@maybeIri") as ?project) - } - - @if(maybeShortname.nonEmpty) { - ?project knora-admin:projectShortname "@maybeShortname.get"^^xsd:string . - } - - @if(maybeShortcode.nonEmpty) { - ?project knora-admin:projectShortcode "@maybeShortcode.get"^^xsd:string . - } - - ?project a knora-admin:knoraProject . - ?project ?p ?o . -} diff --git a/webapi/src/main/twirl/org/knora/webapi/messages/twirl/queries/sparql/admin/updateProject.scala.txt b/webapi/src/main/twirl/org/knora/webapi/messages/twirl/queries/sparql/admin/updateProject.scala.txt deleted file mode 100644 index fbca6613ab..0000000000 --- a/webapi/src/main/twirl/org/knora/webapi/messages/twirl/queries/sparql/admin/updateProject.scala.txt +++ /dev/null @@ -1,131 +0,0 @@ -@* - * Copyright © 2021 - 2024 Swiss National Data and Service Center for the Humanities and/or DaSCH Service Platform contributors. - * SPDX-License-Identifier: Apache-2.0 - *@ - -@import org.knora.webapi.IRI -@import org.knora.webapi.messages.store.triplestoremessages.StringLiteralV2 - -@** - * Updates an existing project with the provided values. - * - * @param dataNamedGraph the named graph to update. - * @param projectIri the IRI of the project we want to update. - * @param maybeShortname the new optional value for shortname. - * @param maybeLongname the new optional value for longname. - * @param maybeDescription the new optional value for description. - * @param maybeKeywords the new optional value for keywords. - * @param maybeLogo the new optional value for logo. - * @param maybeStatus the new optional value for status. - * @param maybeSelfjoin the new optional value for selfjoin. - *@ -@(adminNamedGraphIri: IRI, - projectIri: IRI, - maybeShortname: Option[String], - maybeLongname: Option[String], - maybeDescriptions: Option[Seq[StringLiteralV2]], - maybeKeywords: Option[Seq[String]], - maybeLogo: Option[String], - maybeStatus: Option[Boolean], - maybeSelfjoin: Option[Boolean]) - -PREFIX rdf: -PREFIX rdfs: -PREFIX xsd: -PREFIX knora-admin: - -WITH <@adminNamedGraphIri> -DELETE { - - @* Delete current values, for which we have a new one. *@ - - @if(maybeShortname.nonEmpty) { - ?project knora-admin:projectShortname ?currentShortname . - } - - @if(maybeLongname.nonEmpty) { - ?project knora-admin:projectLongname ?currentLongname . - } - - @if(maybeDescriptions.nonEmpty) { - ?project knora-admin:projectDescription ?currentDescription . - } - - @if(maybeKeywords.nonEmpty) { - ?project knora-admin:projectKeyword ?currentKeywords . - } - - @if(maybeLogo.nonEmpty) { - ?project knora-admin:projectLogo ?currentLogo . - } - - @if(maybeStatus.nonEmpty) { - ?project knora-admin:status ?currentStatus . - } - - @if(maybeSelfjoin.nonEmpty) { - ?project knora-admin:hasSelfJoinEnabled ?currentSelfjoin . - } - - - -} INSERT { - - @* Add the new values. *@ - - @if(maybeShortname.nonEmpty) { - ?project knora-admin:projectShortname "@maybeShortname.get"^^xsd:string . - } - - @if(maybeLongname.nonEmpty) { - ?project knora-admin:projectLongname """@maybeLongname.get"""^^xsd:string . - } - - @if(maybeDescriptions.nonEmpty) { - @for(description <- maybeDescriptions.get) { - @if(description.language.nonEmpty) { - ?project knora-admin:projectDescription """@description.value"""@@@{description.language.get} . - } else { - ?project knora-admin:projectDescription """@description.value"""^^xsd:string . - } - } - } - - @if(maybeKeywords.nonEmpty) { - @for(keyword <- maybeKeywords.get) { - ?project knora-admin:projectKeyword "@keyword"^^xsd:string . - } - } - - @if(maybeLogo.nonEmpty) { - ?project knora-admin:projectLogo "@maybeLogo.get"^^xsd:string . - } - - @if(maybeStatus.nonEmpty) { - ?project knora-admin:status "@maybeStatus.get"^^xsd:boolean . - } - - @if(maybeSelfjoin.nonEmpty) { - ?project knora-admin:hasSelfJoinEnabled "@maybeSelfjoin.get"^^xsd:boolean . - } -} - -WHERE { - BIND(IRI("@projectIri") AS ?project) - - @* Get all current defined values. *@ - - ?project knora-admin:projectShortname ?currentShortname . - - optional {?project knora-admin:projectLongname ?currentLongname .} - - optional {?project knora-admin:projectDescription ?currentDescription .} - - optional {?project knora-admin:projectKeyword ?currentKeywords .} - - optional {?project knora-admin:projectLogo ?currentLogo .} - - ?project knora-admin:status ?currentStatus . - - ?project knora-admin:hasSelfJoinEnabled ?currentSelfjoin . -} diff --git a/webapi/src/test/scala/org/knora/webapi/slice/admin/repo/service/DefaultObjectAccessPermissionRepoLiveSpec.scala b/webapi/src/test/scala/org/knora/webapi/slice/admin/repo/service/DefaultObjectAccessPermissionRepoLiveSpec.scala index c985334b5b..d71ecfd364 100644 --- a/webapi/src/test/scala/org/knora/webapi/slice/admin/repo/service/DefaultObjectAccessPermissionRepoLiveSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/slice/admin/repo/service/DefaultObjectAccessPermissionRepoLiveSpec.scala @@ -40,21 +40,47 @@ object DefaultObjectAccessPermissionRepoLiveSpec extends ZIOSpecDefault { private def permission(forWhat: ForWhat, permissions: Chunk[DefaultObjectAccessPermissionPart]) = DefaultObjectAccessPermission(PermissionIri.makeNew(shortcode), projectIri, forWhat, permissions) + private val resourceClassIri: InternalIri = InternalIri("https://example.com/rc") + private val propertyIri: InternalIri = InternalIri("https://example.com/p") private val expected = permission( - ForWhat.ResourceClassAndProperty(InternalIri("https://example.com/rc"), InternalIri("https://example.com/p")), + ForWhat.ResourceClassAndProperty(resourceClassIri, propertyIri), Chunk( DefaultObjectAccessPermissionPart(RestrictedView, NonEmptyChunk(groupIri)), DefaultObjectAccessPermissionPart(View, NonEmptyChunk(GroupIri.makeNew(shortcode), GroupIri.makeNew(shortcode))), ), ) - val spec = suite("AdministrativePermissionRepoLive")( + val spec = suite("DefaultObjectAccessPermissionRepoLive")( test("should save and find") { for { saved <- repo(_.save(expected)) found <- repo(_.findById(saved.id)) } yield assertTrue(found.contains(saved), saved == expected) }, + test("given ForWhat Property and ForWhat ResourceClassAndProperty exist should findByProjectAndForWhat") { + val rc = permission( + ForWhat.ResourceClass(resourceClassIri), + Chunk(DefaultObjectAccessPermissionPart(View, NonEmptyChunk(GroupIri.makeNew(shortcode)))), + ) + val p = permission( + ForWhat.Property(propertyIri), + Chunk(DefaultObjectAccessPermissionPart(View, NonEmptyChunk(GroupIri.makeNew(shortcode)))), + ) + val rcp = permission( + ForWhat.ResourceClassAndProperty(resourceClassIri, propertyIri), + Chunk(DefaultObjectAccessPermissionPart(View, NonEmptyChunk(GroupIri.makeNew(shortcode)))), + ) + for { + _ <- repo(_.saveAll(List(p, rc, rcp))) + foundPp <- repo(_.findByProjectAndForWhat(projectIri, p.forWhat)) + foundRc <- repo(_.findByProjectAndForWhat(projectIri, rc.forWhat)) + foundRcp <- repo(_.findByProjectAndForWhat(projectIri, rcp.forWhat)) + } yield assertTrue( + foundPp.contains(p), + foundRc.contains(rc), + foundRcp.contains(rcp), + ) + }, test("should delete") { for { saved <- repo(_.save(expected)) diff --git a/webapi/src/test/scala/org/knora/webapi/slice/ontology/repo/service/OntologyCacheFake.scala b/webapi/src/test/scala/org/knora/webapi/slice/ontology/repo/service/OntologyCacheFake.scala index b2c64e9e19..ebc15b50c1 100644 --- a/webapi/src/test/scala/org/knora/webapi/slice/ontology/repo/service/OntologyCacheFake.scala +++ b/webapi/src/test/scala/org/knora/webapi/slice/ontology/repo/service/OntologyCacheFake.scala @@ -12,7 +12,6 @@ import zio.ZLayer import org.knora.webapi.messages.SmartIri import org.knora.webapi.messages.v2.responder.ontologymessages.ReadOntologyV2 -import org.knora.webapi.slice.admin.domain.model.User import org.knora.webapi.slice.ontology.repo.model.OntologyCacheData case class OntologyCacheFake(ref: Ref[OntologyCacheData]) extends OntologyCache { @@ -23,11 +22,8 @@ case class OntologyCacheFake(ref: Ref[OntologyCacheData]) extends OntologyCache /** * Loads and caches all ontology information. - * - * @param requestingUser the user making the request. - * @return a [[Unit]]. */ - override def loadOntologies(requestingUser: User): Task[Unit] = + override def loadOntologies(): Task[Unit] = throw new UnsupportedOperationException("Not possible in tests. Provide the respective test data as Ref.") /** diff --git a/webapi/src/test/scala/org/knora/webapi/store/triplestore/api/TriplestoreServiceInMemory.scala b/webapi/src/test/scala/org/knora/webapi/store/triplestore/api/TriplestoreServiceInMemory.scala index 7ec92b16ee..3e8e3145d4 100644 --- a/webapi/src/test/scala/org/knora/webapi/store/triplestore/api/TriplestoreServiceInMemory.scala +++ b/webapi/src/test/scala/org/knora/webapi/store/triplestore/api/TriplestoreServiceInMemory.scala @@ -99,8 +99,9 @@ final case class TriplestoreServiceInMemory(datasetRef: Ref[Dataset])(implicit v private def getDataSetWithTransaction(readWrite: ReadWrite): URIO[Scope, Dataset] = { val acquire = getDataset.tap(ds => ZIO.succeed(ds.begin(readWrite))) - def release(ds: Dataset) = ZIO.succeed(try { ds.commit() } - finally { ds.end() }) + def release(ds: Dataset) = ZIO.succeed(try { + ds.commit() + } finally { ds.end() }) ZIO.acquireRelease(acquire)(release) } diff --git a/webapi/src/test/scala/org/knora/webapi/store/triplestore/api/TriplestoreServiceInMemorySpec.scala b/webapi/src/test/scala/org/knora/webapi/store/triplestore/api/TriplestoreServiceInMemorySpec.scala index 69cfb51be6..2272a74943 100644 --- a/webapi/src/test/scala/org/knora/webapi/store/triplestore/api/TriplestoreServiceInMemorySpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/store/triplestore/api/TriplestoreServiceInMemorySpec.scala @@ -303,7 +303,7 @@ object TriplestoreServiceInMemorySpec extends ZIOSpecDefault { TriG, ), ) - } yield assertTrue({ val fileExists = Files.exists(testFile.toFile.toPath); fileExists }) + } yield assertTrue { val fileExists = Files.exists(testFile.toFile.toPath); fileExists } } }), ).provide(TriplestoreServiceInMemory.layer, datasetLayerFromTurtle(testDataSet), StringFormatter.test)