From 9170419f052746346c4ee5ff2138ab69125a5e1e Mon Sep 17 00:00:00 2001 From: Benjamin Geer Date: Tue, 17 Nov 2020 13:30:52 +0100 Subject: [PATCH] =?UTF-8?q?feat(api-v2):=20Add=20an=20RDF=20processing=20f?= =?UTF-8?q?a=C3=A7ade=20(DSP-1020)=20(#1754)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/05-internals/design/principles/index.md | 1 + .../05-internals/design/principles/rdf-api.md | 111 ++++ webapi/BUILD.bazel | 6 +- .../org/knora/webapi/ITKnoraLiveSpec.scala | 4 +- .../e2e/v2/KnoraSipiIntegrationV2ITSpec.scala | 9 +- webapi/src/main/resources/application.conf | 13 + .../org/knora/webapi/RdfMediaTypes.scala | 8 + .../knora/webapi/app/ApplicationActor.scala | 11 +- .../scala/org/knora/webapi/app/BUILD.bazel | 3 + .../knora/webapi/exceptions/Exceptions.scala | 10 +- .../org/knora/webapi/feature/BUILD.bazel | 3 - .../knora/webapi/feature/FeatureFactory.scala | 7 +- .../http/handler/KnoraExceptionHandler.scala | 2 +- .../org/knora/webapi/messages/BUILD.bazel | 5 +- .../webapi/messages/OntologyConstants.scala | 11 +- .../groupsmessages/GroupsMessagesADM.scala | 77 ++- .../listsmessages/ListsMessagesADM.scala | 49 +- .../PermissionsMessagesADM.scala | 71 ++- .../ProjectsMessagesADM.scala | 81 ++- .../sipimessages/SipiMessagesADM.scala | 13 +- .../storesmessages/StoresMessagesADM.scala | 12 +- .../usersmessages/UsersMessagesADM.scala | 147 +++-- .../TriplestoreMessages.scala | 161 ++--- .../util/ConstructResponseUtilV2.scala | 54 +- .../messages/util/PermissionUtilADM.scala | 9 +- .../webapi/messages/util/RdfFormatUtil.scala | 135 ----- .../webapi/messages/util/UserUtilADM.scala | 4 + .../webapi/messages/util/ValueUtilV1.scala | 53 +- .../messages/util/{ => rdf}/JsonLDUtil.scala | 522 +++++++++-------- .../messages/util/rdf/RdfFeatureFactory.scala | 86 +++ .../messages/util/rdf/RdfFormatUtil.scala | 211 +++++++ .../webapi/messages/util/rdf/RdfModel.scala | 335 +++++++++++ .../util/rdf/jenaimpl/JenaFormatUtil.scala | 89 +++ .../util/rdf/jenaimpl/JenaModel.scala | 387 ++++++++++++ .../util/rdf/rdf4jimpl/RDF4JFormatUtil.scala | 74 +++ .../util/rdf/rdf4jimpl/RDF4JModel.scala | 339 +++++++++++ .../ckanmessages/CkanMessagesV1.scala | 8 +- .../ontologymessages/OntologyMessagesV1.scala | 36 +- .../projectmessages/ProjectMessagesV1.scala | 40 +- .../resourcemessages/ResourceMessagesV1.scala | 119 ++-- .../standoffmessages/StandoffMessagesV1.scala | 28 +- .../usermessages/UserMessagesV1.scala | 26 +- .../valuemessages/ValueMessagesV1.scala | 98 ++-- .../v2/responder/KnoraRequestV2.scala | 37 +- .../v2/responder/KnoraResponseV2.scala | 61 +- .../listsmessages/ListsMessagesV2.scala | 20 +- .../metadatamessages/MetadataMessagesV2.scala | 29 +- .../ontologymessages/OntologyMessagesV2.scala | 335 ++++++----- .../resourcemessages/ResourceMessagesV2.scala | 170 ++++-- .../searchmessages/SearchMessagesV2.scala | 43 +- .../standoffmessages/StandoffMessagesV2.scala | 74 ++- .../valuemessages/ValueMessagesV2.scala | 238 ++++---- .../org/knora/webapi/responders/BUILD.bazel | 1 + .../responders/admin/GroupsResponderADM.scala | 278 ++++++--- .../responders/admin/ListsResponderADM.scala | 260 +++++--- .../admin/PermissionsResponderADM.scala | 243 ++++---- .../admin/ProjectsResponderADM.scala | 254 +++++--- .../responders/admin/SipiResponderADM.scala | 8 +- .../responders/admin/StoresResponderADM.scala | 15 +- .../responders/admin/UsersResponderADM.scala | 553 +++++++++++++----- .../responders/v1/CkanResponderV1.scala | 120 +++- .../responders/v1/OntologyResponderV1.scala | 71 ++- .../responders/v1/ProjectsResponderV1.scala | 93 ++- .../responders/v1/ResourcesResponderV1.scala | 250 +++++--- .../responders/v1/StandoffResponderV1.scala | 53 +- .../responders/v1/UsersResponderV1.scala | 87 ++- .../responders/v1/ValuesResponderV1.scala | 410 +++++++++---- .../responders/v2/ListsResponderV2.scala | 30 +- .../responders/v2/MetadataResponderV2.scala | 19 +- .../responders/v2/OntologyResponderV2.scala | 228 ++++++-- .../responders/v2/ResourcesResponderV2.scala | 177 ++++-- .../v2/ResponderWithStandoffV2.scala | 18 +- .../responders/v2/SearchResponderV2.scala | 88 ++- .../responders/v2/StandoffResponderV2.scala | 108 +++- .../responders/v2/ValuesResponderV2.scala | 103 +++- .../knora/webapi/routing/Authenticator.scala | 124 ++-- .../org/knora/webapi/routing/BUILD.bazel | 3 +- .../org/knora/webapi/routing/KnoraRoute.scala | 16 +- .../knora/webapi/routing/RouteUtilV1.scala | 9 +- .../knora/webapi/routing/RouteUtilV2.scala | 22 +- .../webapi/routing/admin/GroupsRouteADM.scala | 56 +- .../routing/admin/PermissionsRouteADM.scala | 33 +- .../routing/admin/ProjectsRouteADM.scala | 206 +++++-- .../webapi/routing/admin/SipiRouteADM.scala | 12 +- .../webapi/routing/admin/StoreRouteADM.scala | 7 +- .../webapi/routing/admin/UsersRouteADM.scala | 160 +++-- .../admin/lists/NewListsRouteADMFeature.scala | 51 +- .../admin/lists/OldListsRouteADMFeature.scala | 62 +- .../routing/v1/AuthenticationRouteV1.scala | 20 +- .../knora/webapi/routing/v1/CkanRouteV1.scala | 13 +- .../webapi/routing/v1/ListsRouteV1.scala | 10 +- .../webapi/routing/v1/ProjectsRouteV1.scala | 36 +- .../routing/v1/ResourceTypesRouteV1.scala | 66 ++- .../webapi/routing/v1/ResourcesRouteV1.scala | 138 ++++- .../webapi/routing/v1/SearchRouteV1.scala | 10 +- .../webapi/routing/v1/StandoffRouteV1.scala | 17 +- .../webapi/routing/v1/UsersRouteV1.scala | 44 +- .../webapi/routing/v1/ValuesRouteV1.scala | 61 +- .../routing/v2/AuthenticationRouteV2.scala | 15 +- .../webapi/routing/v2/ListsRouteV2.scala | 22 +- .../webapi/routing/v2/MetadataRouteV2.scala | 38 +- .../webapi/routing/v2/OntologiesRouteV2.scala | 98 +++- .../webapi/routing/v2/ResourcesRouteV2.scala | 67 ++- .../webapi/routing/v2/SearchRouteV2.scala | 58 +- .../webapi/routing/v2/StandoffRouteV2.scala | 19 +- .../webapi/routing/v2/ValuesRouteV2.scala | 26 +- .../scala/org/knora/webapi/store/BUILD.bazel | 1 + .../http/HttpTriplestoreConnector.scala | 113 ++-- .../scala/org/knora/webapi/util/BUILD.bazel | 1 + .../org/knora/webapi/util/JavaUtil.scala | 10 +- .../scala/org/knora/webapi/CoreSpec.scala | 21 +- .../test/scala/org/knora/webapi/E2ESpec.scala | 29 +- .../test/scala/org/knora/webapi/R2RSpec.scala | 49 +- .../webapi/e2e/FeatureToggleR2RSpec.scala | 64 +- .../knora/webapi/e2e/InstanceChecker.scala | 13 +- .../webapi/e2e/admin/ProjectsADME2ESpec.scala | 7 +- .../e2e/v2/JSONLDHandlingV2R2RSpec.scala | 2 +- .../webapi/e2e/v2/ListsRouteV2R2RSpec.scala | 18 +- .../e2e/v2/MetadataRouteV2E2ESpec.scala | 18 +- .../webapi/e2e/v2/OntologyV2R2RSpec.scala | 7 +- .../e2e/v2/ResourcesRouteV2E2ESpec.scala | 35 +- .../webapi/e2e/v2/ResponseCheckerV2.scala | 21 +- .../webapi/e2e/v2/SearchRouteV2R2RSpec.scala | 16 +- .../webapi/e2e/v2/ValuesRouteV2E2ESpec.scala | 243 ++++---- .../knora/webapi/e2e/v2/ValuesV2R2RSpec.scala | 12 +- .../PermissionsMessagesADMSpec.scala | 26 +- .../knora/webapi/messages/util/BUILD.bazel | 57 -- .../util/ConstructResponseUtilV2Spec.scala | 30 +- .../messages/util/RdfFormatUtilSpec.scala | 81 --- .../webapi/messages/util/rdf/BUILD.bazel | 14 + .../util/{ => rdf}/JsonLDUtilSpec.scala | 113 +++- .../util/{ => rdf}/KnoraResponseV2Spec.scala | 34 +- .../messages/util/rdf/RdfFormatUtilSpec.scala | 149 +++++ .../messages/util/rdf/RdfModelSpec.scala | 217 +++++++ .../messages/util/rdf/jenaimpl/BUILD.bazel | 84 +++ .../rdf/jenaimpl/JenaFormatUtilSpec.scala | 28 + .../rdf/jenaimpl/JenaJsonLDUtilSpec.scala | 28 + .../jenaimpl/JenaKnoraResponseV2Spec.scala | 28 + .../util/rdf/jenaimpl/JenaModelSpec.scala | 28 + .../messages/util/rdf/rdf4jimpl/BUILD.bazel | 83 +++ .../rdf/rdf4jimpl/RDF4JFormatUtilSpec.scala | 28 + .../rdf/rdf4jimpl/RDF4JJsonLDUtilSpec.scala | 28 + .../rdf4jimpl/RDF4JKnoraResponseV2Spec.scala | 28 + .../util/rdf/rdf4jimpl/RDF4JModelSpec.scala | 28 + .../MetadataMessagesV2Spec.scala | 21 +- .../InputOntologyV2Spec.scala | 2 +- .../webapi/other/v1/DrawingsGodsV1Spec.scala | 56 +- .../admin/GroupsResponderADMSpec.scala | 75 ++- .../admin/ListsResponderADMSpec.scala | 280 ++++----- .../admin/PermissionsResponderADMSpec.scala | 21 +- .../admin/ProjectsResponderADMSpec.scala | 109 ++-- .../admin/SipiResponderADMSpec.scala | 16 +- .../admin/UsersResponderADMSpec.scala | 190 +++--- .../v1/OntologyResponderV1Spec.scala | 12 +- .../v1/ProjectsResponderV1Spec.scala | 41 +- .../v1/ResourcesResponderV1Spec.scala | 77 ++- .../responders/v1/UsersResponderV1Spec.scala | 64 +- .../responders/v1/ValuesResponderV1Spec.scala | 86 ++- .../responders/v2/ListsResponderV2Spec.scala | 12 +- .../v2/MetadataResponderV2Spec.scala | 26 +- .../v2/OntologyResponderV2Spec.scala | 148 ++++- .../v2/ResourcesResponderV2Spec.scala | 133 ++++- .../responders/v2/SearchResponderV2Spec.scala | 19 +- .../responders/v2/ValuesResponderV2Spec.scala | 137 ++++- .../webapi/routing/AuthenticatorSpec.scala | 74 +-- 165 files changed, 9390 insertions(+), 3462 deletions(-) create mode 100644 docs/05-internals/design/principles/rdf-api.md delete mode 100644 webapi/src/main/scala/org/knora/webapi/messages/util/RdfFormatUtil.scala rename webapi/src/main/scala/org/knora/webapi/messages/util/{ => rdf}/JsonLDUtil.scala (74%) create mode 100644 webapi/src/main/scala/org/knora/webapi/messages/util/rdf/RdfFeatureFactory.scala create mode 100644 webapi/src/main/scala/org/knora/webapi/messages/util/rdf/RdfFormatUtil.scala create mode 100644 webapi/src/main/scala/org/knora/webapi/messages/util/rdf/RdfModel.scala create mode 100644 webapi/src/main/scala/org/knora/webapi/messages/util/rdf/jenaimpl/JenaFormatUtil.scala create mode 100644 webapi/src/main/scala/org/knora/webapi/messages/util/rdf/jenaimpl/JenaModel.scala create mode 100644 webapi/src/main/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/RDF4JFormatUtil.scala create mode 100644 webapi/src/main/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/RDF4JModel.scala delete mode 100644 webapi/src/test/scala/org/knora/webapi/messages/util/RdfFormatUtilSpec.scala create mode 100644 webapi/src/test/scala/org/knora/webapi/messages/util/rdf/BUILD.bazel rename webapi/src/test/scala/org/knora/webapi/messages/util/{ => rdf}/JsonLDUtilSpec.scala (64%) rename webapi/src/test/scala/org/knora/webapi/messages/util/{ => rdf}/KnoraResponseV2Spec.scala (73%) create mode 100644 webapi/src/test/scala/org/knora/webapi/messages/util/rdf/RdfFormatUtilSpec.scala create mode 100644 webapi/src/test/scala/org/knora/webapi/messages/util/rdf/RdfModelSpec.scala create mode 100644 webapi/src/test/scala/org/knora/webapi/messages/util/rdf/jenaimpl/BUILD.bazel create mode 100644 webapi/src/test/scala/org/knora/webapi/messages/util/rdf/jenaimpl/JenaFormatUtilSpec.scala create mode 100644 webapi/src/test/scala/org/knora/webapi/messages/util/rdf/jenaimpl/JenaJsonLDUtilSpec.scala create mode 100644 webapi/src/test/scala/org/knora/webapi/messages/util/rdf/jenaimpl/JenaKnoraResponseV2Spec.scala create mode 100644 webapi/src/test/scala/org/knora/webapi/messages/util/rdf/jenaimpl/JenaModelSpec.scala create mode 100644 webapi/src/test/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/BUILD.bazel create mode 100644 webapi/src/test/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/RDF4JFormatUtilSpec.scala create mode 100644 webapi/src/test/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/RDF4JJsonLDUtilSpec.scala create mode 100644 webapi/src/test/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/RDF4JKnoraResponseV2Spec.scala create mode 100644 webapi/src/test/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/RDF4JModelSpec.scala diff --git a/docs/05-internals/design/principles/index.md b/docs/05-internals/design/principles/index.md index 43092ca339..f39e2ae77a 100644 --- a/docs/05-internals/design/principles/index.md +++ b/docs/05-internals/design/principles/index.md @@ -23,6 +23,7 @@ License along with Knora. If not, see . - [Futures with Akka](futures-with-akka.md) - [HTTP Module](http-module.md) - [Store Module](store-module.md) +- [RDF Processing API](rdf-api.md) - [Triplestore Updates](triplestore-updates.md) - [Consistency Checking](consistency-checking.md) - [Authentication](authentication.md) diff --git a/docs/05-internals/design/principles/rdf-api.md b/docs/05-internals/design/principles/rdf-api.md new file mode 100644 index 0000000000..d551fb5f3d --- /dev/null +++ b/docs/05-internals/design/principles/rdf-api.md @@ -0,0 +1,111 @@ + + +# RDF Processing API + +Knora provides an API for parsing and formatting RDF data and +for working with RDF graphs. This allows Knora developers to use a single, +idiomatic Scala API as a façade for a Java RDF library. +By using a feature toggle, you can choose either +[Jena](https://jena.apache.org/tutorials/rdf_api.html) +or +[RDF4J](https://rdf4j.org/documentation/programming/) +as the underlying implementation. + + +## Overview + +The API is in the package `org.knora.webapi.messages.util.rdf`. It includes: + +- `RdfModel`, which represents a set of RDF graphs (a default graph and/or one or more named graphs). + A model can be constructed from scratch, modified, and searched. + +- `RdfNode` and its subclasses, which represent RDF nodes (IRIs, blank nodes, and literals). + +- `Statement`, which represents a triple or quad. + +- `RdfNodeFactory`, which creates nodes and statements. + +- `RdfModelFactory`, which creates empty RDF models. + +- `RdfFormatUtil`, which parses and formats RDF models. + +- `JsonLDUtil`, which provides specialised functionality for working + with RDF in JSON-LD format, and for converting between RDF models + and JSON-LD documents. `RdfFormatUtil` uses `JsonLDUtil` when appropriate. + +To work with RDF models, start with `RdfFeatureFactory`, which returns instances +of `RdfNodeFactory`, `RdfModelFactory`, and `RdfFormatUtil`, using feature toggle +configuration. + +`JsonLDUtil` does not need a feature factory. + + +## Implementations + +- The Jena-based implementation, in package `org.knora.webapi.messages.util.rdf.jenaimpl`. + +- The RDF4J-based implementation, in package `org.knora.webapi.messages.util.rdf.rdf4jimpl`. + + +## Feature toggle + +For an overview of feature toggles, see [Feature Toggles](feature-toggles.md). + +The RDF API uses the feature toggle `jena-rdf-library`: + +- `on`: use the Jena implementation. + +- `off` (the default): use the RDF4J implementation. + + +The default setting is used on startup, e.g. to read ontologies from the +repository. After startup, the per-request setting is used. + + +## What still uses RDF4J directly + +Before this API was added, Knora mainly used the RDF4J API directly, and still does +in some places: + +- Code that uses RDF4J's streaming API to process large amounts of data, especially to + avoid constructing a large string in TriG format: + + - `ProjectsResponderADM.projectDataGetRequestADM` + + - `HttpTriplestoreConnector.turtleToTrig` + + - `RepositoryUpdater` + +- The repository update plugin tests, which use SPARQL. + +- `TEIHeader`: uses XSLT that depends on the exact format of the RDF/XML generated by RDF4J. + The XSLT would need to be improved to handle `rdf:Description`. + +- `GravsearchParser`: uses RDF4J's SPARQL parser. This is probably + not worth changing. + + +## TODO + +- SHACL validation. + +- SPARQL querying. + +- A streaming parsing/formatting API for processing large graphs. diff --git a/webapi/BUILD.bazel b/webapi/BUILD.bazel index 3f7d626760..fc5070deef 100644 --- a/webapi/BUILD.bazel +++ b/webapi/BUILD.bazel @@ -2,7 +2,6 @@ package(default_visibility = ["//visibility:public"]) load("@io_bazel_rules_scala//scala:scala.bzl", "scala_binary", "scala_library", "scala_repl", "scala_test") - # alias added for convenience. To call, use: bazel run //webapi:GenerateContributorsFile alias( name = "GenerateContributorsFile", @@ -156,6 +155,7 @@ scala_library( "//webapi/src/main/scala/org/knora/webapi/http/handler", "//webapi/src/main/scala/org/knora/webapi/instrumentation", "//webapi/src/main/scala/org/knora/webapi/messages", + "//webapi/src/main/scala/org/knora/webapi/feature", "//webapi/src/main/scala/org/knora/webapi/responders", "//webapi/src/main/scala/org/knora/webapi/routing", "//webapi/src/main/scala/org/knora/webapi/settings", @@ -167,7 +167,6 @@ scala_library( # Test Libs "@maven//:com_typesafe_akka_akka_testkit_2_12", "@maven//:com_typesafe_akka_akka_http_testkit_2_12", - "@maven//:com_jsuereth_scala_arm_2_12", "@maven//:com_typesafe_akka_akka_actor_2_12", "@maven//:com_typesafe_akka_akka_http_2_12", "@maven//:com_typesafe_akka_akka_http_core_2_12", @@ -175,9 +174,7 @@ scala_library( "@maven//:com_typesafe_akka_akka_stream_2_12", "@maven//:com_typesafe_config", "@maven//:io_spray_spray_json_2_12", - "@maven//:org_eclipse_rdf4j_rdf4j_client", "@maven//:org_scalactic_scalactic_2_12", - "@maven//:org_scalatest_scalatest_2_12", "@maven//:org_scalatest_scalatest_core_2_12", "@maven//:org_scalatest_scalatest_wordspec_2_12", "@maven//:org_scalatest_scalatest_matchers_core_2_12", @@ -236,7 +233,6 @@ scala_library( "@maven//:org_scala_lang_scala_library", "@maven//:org_scala_lang_scala_reflect", "@maven//:org_scalactic_scalactic_2_12", - "@maven//:org_scalatest_scalatest_2_12", "@maven//:org_scalatest_scalatest_core_2_12", "@maven//:org_scalatest_scalatest_wordspec_2_12", "@maven//:org_scalatest_scalatest_matchers_core_2_12", diff --git a/webapi/src/it/scala/org/knora/webapi/ITKnoraLiveSpec.scala b/webapi/src/it/scala/org/knora/webapi/ITKnoraLiveSpec.scala index defdec53c5..e74a8a2324 100644 --- a/webapi/src/it/scala/org/knora/webapi/ITKnoraLiveSpec.scala +++ b/webapi/src/it/scala/org/knora/webapi/ITKnoraLiveSpec.scala @@ -36,8 +36,8 @@ import org.knora.webapi.exceptions.AssertionException import org.knora.webapi.messages.StringFormatter import org.knora.webapi.messages.app.appmessages.{AppStart, AppStop, SetAllowReloadOverHTTPState} import org.knora.webapi.messages.store.triplestoremessages.{RdfDataObject, TriplestoreJsonProtocol} -import org.knora.webapi.messages.util.{JsonLDDocument, JsonLDUtil} -import org.knora.webapi.settings.{KnoraDispatchers, KnoraSettings, KnoraSettingsImpl, _} +import org.knora.webapi.messages.util.rdf.{JsonLDDocument, JsonLDUtil} +import org.knora.webapi.settings._ import org.knora.webapi.util.StartupUtils import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpecLike diff --git a/webapi/src/it/scala/org/knora/webapi/e2e/v2/KnoraSipiIntegrationV2ITSpec.scala b/webapi/src/it/scala/org/knora/webapi/e2e/v2/KnoraSipiIntegrationV2ITSpec.scala index 6ac49ed5e7..b3581c3a21 100644 --- a/webapi/src/it/scala/org/knora/webapi/e2e/v2/KnoraSipiIntegrationV2ITSpec.scala +++ b/webapi/src/it/scala/org/knora/webapi/e2e/v2/KnoraSipiIntegrationV2ITSpec.scala @@ -31,6 +31,7 @@ import org.knora.webapi.exceptions.AssertionException import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.store.triplestoremessages.TriplestoreJsonProtocol import org.knora.webapi.messages.util._ +import org.knora.webapi.messages.util.rdf.{JsonLDArray, JsonLDKeywords, JsonLDDocument, JsonLDObject, JsonLDValue} import org.knora.webapi.messages.v2.routing.authenticationmessages._ import org.knora.webapi.messages.{OntologyConstants, SmartIri, StringFormatter} import org.knora.webapi.sharedtestdata.SharedTestDataADM @@ -157,11 +158,11 @@ class KnoraSipiIntegrationV2ITSpec extends ITKnoraLiveSpec(KnoraSipiIntegrationV private def getValueFromResource(resource: JsonLDDocument, propertyIriInResult: SmartIri, expectedValueIri: IRI): JsonLDObject = { - val resourceIri: IRI = resource.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val resourceIri: IRI = resource.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) val propertyValues: JsonLDArray = getValuesFromResource(resource = resource, propertyIriInResult = propertyIriInResult) val matchingValues: Seq[JsonLDObject] = propertyValues.value.collect { - case jsonLDObject: JsonLDObject if jsonLDObject.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) == expectedValueIri => jsonLDObject + case jsonLDObject: JsonLDObject if jsonLDObject.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) == expectedValueIri => jsonLDObject } if (matchingValues.isEmpty) { @@ -620,7 +621,7 @@ class KnoraSipiIntegrationV2ITSpec extends ITKnoraLiveSpec(KnoraSipiIntegrationV val request = Post(s"$baseApiUrl/v2/resources", HttpEntity(RdfMediaTypes.`application/ld+json`, jsonLdEntity)) ~> addCredentials(BasicHttpCredentials(anythingUserEmail, password)) val responseJsonDoc: JsonLDDocument = getResponseJsonLD(request) - val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) csvResourceIri.set(responseJsonDoc.body.requireIDAsKnoraDataIri.toString) // Get the resource from Knora. @@ -768,7 +769,7 @@ class KnoraSipiIntegrationV2ITSpec extends ITKnoraLiveSpec(KnoraSipiIntegrationV val request = Post(s"$baseApiUrl/v2/resources", HttpEntity(RdfMediaTypes.`application/ld+json`, jsonLdEntity)) ~> addCredentials(BasicHttpCredentials(anythingUserEmail, password)) val responseJsonDoc: JsonLDDocument = getResponseJsonLD(request) - val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) xmlResourceIri.set(responseJsonDoc.body.requireIDAsKnoraDataIri.toString) // Get the resource from Knora. diff --git a/webapi/src/main/resources/application.conf b/webapi/src/main/resources/application.conf index 0ef424ec5f..852d666846 100644 --- a/webapi/src/main/resources/application.conf +++ b/webapi/src/main/resources/application.conf @@ -279,6 +279,19 @@ app { "Benjamin Geer " ] } + + jena-rdf-library { + description = "Use the Jena API for RDF processing. If turned off, use the RDF4J API." + + available-versions = [ 1 ] + default-version = 1 + enabled-by-default = no + override-allowed = yes + + developer-emails = [ + "Benjamin Geer " + ] + } } print-extended-config = false // If true, an extended list of configuration parameters will be printed out at startup. diff --git a/webapi/src/main/scala/org/knora/webapi/RdfMediaTypes.scala b/webapi/src/main/scala/org/knora/webapi/RdfMediaTypes.scala index 00cd6fd518..6f56ea3640 100644 --- a/webapi/src/main/scala/org/knora/webapi/RdfMediaTypes.scala +++ b/webapi/src/main/scala/org/knora/webapi/RdfMediaTypes.scala @@ -48,6 +48,13 @@ object RdfMediaTypes { fileExtensions = List("rdf") ) + val `application/trig`: MediaType.WithFixedCharset = MediaType.customWithFixedCharset( + mainType = "application", + subType = "trig", + charset = HttpCharsets.`UTF-8`, + fileExtensions = List("trig") + ) + /** * A map of MIME types (strings) to supported RDF media types. */ @@ -55,6 +62,7 @@ object RdfMediaTypes { `application/json`, `application/ld+json`, `text/turtle`, + `application/trig`, `application/rdf+xml` ).map { mediaType => mediaType.toString -> mediaType diff --git a/webapi/src/main/scala/org/knora/webapi/app/ApplicationActor.scala b/webapi/src/main/scala/org/knora/webapi/app/ApplicationActor.scala index e52dcd86a4..0c113b1801 100644 --- a/webapi/src/main/scala/org/knora/webapi/app/ApplicationActor.scala +++ b/webapi/src/main/scala/org/knora/webapi/app/ApplicationActor.scala @@ -32,6 +32,7 @@ import com.typesafe.scalalogging.LazyLogging import kamon.Kamon import org.knora.webapi.core.LiveActorMaker import org.knora.webapi.exceptions.{InconsistentTriplestoreDataException, SipiException, UnexpectedMessageException, UnsupportedValueException} +import org.knora.webapi.feature.{FeatureFactoryConfig, KnoraSettingsFeatureFactoryConfig} import org.knora.webapi.http.handler import org.knora.webapi.http.version.ServerVersion import org.knora.webapi.messages.admin.responder.KnoraRequestADM @@ -105,6 +106,11 @@ class ApplicationActor extends Actor with Stash with LazyLogging with AroundDire */ implicit val knoraSettings: KnoraSettingsImpl = KnoraSettings(system) + /** + * The default feature factory configuration, which is used during startup. + */ + val defaultFeatureFactoryConfig: FeatureFactoryConfig = new KnoraSettingsFeatureFactoryConfig(knoraSettings) + /** * Provides the actor materializer (akka-http) */ @@ -353,7 +359,10 @@ class ApplicationActor extends Actor with Stash with LazyLogging with AroundDire /* load ontologies request */ case LoadOntologies() => - responderManager ! LoadOntologiesRequestV2(KnoraSystemInstances.Users.SystemUser) + responderManager ! LoadOntologiesRequestV2( + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) /* load ontologies response */ case SuccessResponseV2(_) => diff --git a/webapi/src/main/scala/org/knora/webapi/app/BUILD.bazel b/webapi/src/main/scala/org/knora/webapi/app/BUILD.bazel index f01008e604..7f7baa0e04 100644 --- a/webapi/src/main/scala/org/knora/webapi/app/BUILD.bazel +++ b/webapi/src/main/scala/org/knora/webapi/app/BUILD.bazel @@ -10,6 +10,7 @@ scala_library( "//webapi/src/main/scala/org/knora/webapi", "//webapi/src/main/scala/org/knora/webapi/core", "//webapi/src/main/scala/org/knora/webapi/exceptions", + "//webapi/src/main/scala/org/knora/webapi/feature", "//webapi/src/main/scala/org/knora/webapi/http/handler", "//webapi/src/main/scala/org/knora/webapi/http/version", "//webapi/src/main/scala/org/knora/webapi/instrumentation", @@ -54,6 +55,8 @@ scala_binary( "@maven//:ch_qos_logback_logback_core", "@maven//:com_typesafe_akka_akka_slf4j_2_12", "@maven//:org_slf4j_log4j_over_slf4j", + "@maven//:org_glassfish_jakarta_json", + "@maven//:org_scala_lang_modules_scala_java8_compat_2_12", ], ) diff --git a/webapi/src/main/scala/org/knora/webapi/exceptions/Exceptions.scala b/webapi/src/main/scala/org/knora/webapi/exceptions/Exceptions.scala index b506339a24..956a983b4e 100644 --- a/webapi/src/main/scala/org/knora/webapi/exceptions/Exceptions.scala +++ b/webapi/src/main/scala/org/knora/webapi/exceptions/Exceptions.scala @@ -467,6 +467,14 @@ case class TestConfigurationException(message: String) extends ApplicationConfig */ case class FeatureToggleException(message: String, cause: Option[Throwable] = None) extends ApplicationConfigurationException(message) +/** + * Indicates that RDF processing failed. + * + * @param message a description of the error. + * @param cause the original exception representing the cause of the error, if any. + */ +case class RdfProcessingException(message: String, cause: Option[Throwable] = None) extends InternalServerException(message) + /** * Helper functions for error handling. */ @@ -482,7 +490,7 @@ object ExceptionUtil { SerializationUtils.serialize(e) true } catch { - case serEx: SerializationException => false + case _: SerializationException => false } } diff --git a/webapi/src/main/scala/org/knora/webapi/feature/BUILD.bazel b/webapi/src/main/scala/org/knora/webapi/feature/BUILD.bazel index 28ecf4f484..f3f8ad4b80 100644 --- a/webapi/src/main/scala/org/knora/webapi/feature/BUILD.bazel +++ b/webapi/src/main/scala/org/knora/webapi/feature/BUILD.bazel @@ -9,12 +9,9 @@ scala_library( deps = [ "//webapi/src/main/scala/org/knora/webapi", "//webapi/src/main/scala/org/knora/webapi/exceptions", - "//webapi/src/main/scala/org/knora/webapi/messages", "//webapi/src/main/scala/org/knora/webapi/settings", "@maven//:com_typesafe_akka_akka_actor_2_12", "@maven//:com_typesafe_akka_akka_http_2_12", "@maven//:com_typesafe_akka_akka_http_core_2_12", - "@maven//:com_typesafe_scala_logging_scala_logging_2_12", - "@maven//:org_apache_jena_apache_jena_libs", ], ) diff --git a/webapi/src/main/scala/org/knora/webapi/feature/FeatureFactory.scala b/webapi/src/main/scala/org/knora/webapi/feature/FeatureFactory.scala index c956c84b3c..36b649c80e 100644 --- a/webapi/src/main/scala/org/knora/webapi/feature/FeatureFactory.scala +++ b/webapi/src/main/scala/org/knora/webapi/feature/FeatureFactory.scala @@ -23,12 +23,12 @@ import akka.http.scaladsl.model.{HttpHeader, HttpResponse} import akka.http.scaladsl.model.headers.RawHeader import akka.http.scaladsl.server.RequestContext import org.knora.webapi.exceptions.{BadRequestException, FeatureToggleException} -import org.knora.webapi.messages.StringFormatter import org.knora.webapi.settings.KnoraSettings.FeatureToggleBaseConfig import org.knora.webapi.settings.KnoraSettingsImpl import scala.annotation.tailrec import scala.util.{Failure, Success, Try} +import scala.util.control.Exception._ /** * A tagging trait for module-specific factories that produce implementations of features. @@ -362,8 +362,7 @@ object RequestContextFeatureFactoryConfig { * @param parent the parent [[FeatureFactoryConfig]]. */ class RequestContextFeatureFactoryConfig(requestContext: RequestContext, - parent: FeatureFactoryConfig)(implicit stringFormatter: StringFormatter) extends OverridingFeatureFactoryConfig(parent) { - + parent: FeatureFactoryConfig) extends OverridingFeatureFactoryConfig(parent) { import FeatureToggle._ import RequestContextFeatureFactoryConfig._ @@ -392,7 +391,7 @@ class RequestContextFeatureFactoryConfig(requestContext: RequestContext, } val maybeVersion: Option[Int] = featureNameAndVersion.drop(1).headOption.map { - versionStr => stringFormatter.validateInt(versionStr, throw BadRequestException(s"Invalid version number '$versionStr' in feature toggle $featureName")) + versionStr: String => allCatch.opt(versionStr.toInt).getOrElse(throw BadRequestException(s"Invalid version number '$versionStr' in feature toggle $featureName")) } featureName -> FeatureToggle( diff --git a/webapi/src/main/scala/org/knora/webapi/http/handler/KnoraExceptionHandler.scala b/webapi/src/main/scala/org/knora/webapi/http/handler/KnoraExceptionHandler.scala index 63f040b518..74a54a5553 100644 --- a/webapi/src/main/scala/org/knora/webapi/http/handler/KnoraExceptionHandler.scala +++ b/webapi/src/main/scala/org/knora/webapi/http/handler/KnoraExceptionHandler.scala @@ -26,7 +26,7 @@ import com.typesafe.scalalogging.LazyLogging import org.knora.webapi.exceptions.{InternalServerException, RequestRejectedException} import org.knora.webapi.http.status.{ApiStatusCodesV1, ApiStatusCodesV2} import org.knora.webapi.messages.OntologyConstants -import org.knora.webapi.messages.util.{JsonLDDocument, JsonLDObject, JsonLDString} +import org.knora.webapi.messages.util.rdf.{JsonLDDocument, JsonLDObject, JsonLDString} import org.knora.webapi.settings.KnoraSettingsImpl import spray.json.{JsNumber, JsObject, JsString, JsValue} diff --git a/webapi/src/main/scala/org/knora/webapi/messages/BUILD.bazel b/webapi/src/main/scala/org/knora/webapi/messages/BUILD.bazel index 72f363decd..3a7ba37c53 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/BUILD.bazel +++ b/webapi/src/main/scala/org/knora/webapi/messages/BUILD.bazel @@ -10,6 +10,7 @@ scala_library( "//webapi/src/main/scala/org/knora/webapi", "//webapi/src/main/scala/org/knora/webapi/annotation", "//webapi/src/main/scala/org/knora/webapi/exceptions", + "//webapi/src/main/scala/org/knora/webapi/feature", "//webapi/src/main/scala/org/knora/webapi/settings", "//webapi/src/main/scala/org/knora/webapi/util", "//webapi/src/main/scala/org/knora/webapi/util/cache", @@ -34,14 +35,10 @@ scala_library( "@maven//:org_apache_jena_apache_jena_libs", "@maven//:org_eclipse_rdf4j_rdf4j_client", "@maven//:org_jodd_jodd", - "@maven//:org_scala_lang_modules_scala_java8_compat_2_12", "@maven//:org_scala_lang_modules_scala_xml_2_12", "@maven//:org_scala_lang_scala_library", "@maven//:org_scala_lang_scala_reflect", "@maven//:org_slf4j_slf4j_api", "@maven//:org_springframework_security_spring_security_core", - # The following dependency is needed even though Bazel says they are unncessary. - # Please don't remove them! - "@maven//:org_glassfish_jakarta_json", ], ) diff --git a/webapi/src/main/scala/org/knora/webapi/messages/OntologyConstants.scala b/webapi/src/main/scala/org/knora/webapi/messages/OntologyConstants.scala index 061ca8681d..fdafcc18ea 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/OntologyConstants.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/OntologyConstants.scala @@ -113,6 +113,11 @@ object OntologyConstants { val Int: IRI = XsdPrefixExpansion + "int" val Integer: IRI = XsdPrefixExpansion + "integer" val NonNegativeInteger: IRI = XsdPrefixExpansion + "nonNegativeInteger" + + lazy val integerTypes: Set[IRI] = Set( + Int, Integer, NonNegativeInteger + ) + val Decimal: IRI = XsdPrefixExpansion + "decimal" val Uri: IRI = XsdPrefixExpansion + "anyURI" val Pattern: IRI = XsdPrefixExpansion + "pattern" @@ -1031,9 +1036,9 @@ object OntologyConstants { val File: IRI = KnoraApiV2PrefixExpansion + "File" - // The set of custom datatypes defined in knora-api in the simple schema. InstanceChecker relies on - // this. - val KnoraDatatypes: Set[IRI] = Set( + // The set of custom datatypes defined in knora-api in the simple schema. InstanceChecker and + // JenaNodeFactory rely on this. + lazy val KnoraDatatypes: Set[IRI] = Set( Date, ListNode, Geom, diff --git a/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/groupsmessages/GroupsMessagesADM.scala b/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/groupsmessages/GroupsMessagesADM.scala index 1010c33d0d..b74b37dc56 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/groupsmessages/GroupsMessagesADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/groupsmessages/GroupsMessagesADM.scala @@ -24,6 +24,7 @@ import java.util.UUID import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport import org.knora.webapi.IRI import org.knora.webapi.exceptions.BadRequestException +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.admin.responder.projectsmessages.{ProjectADM, ProjectsADMJsonProtocol} import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.admin.responder.{KnoraRequestADM, KnoraResponseADM} @@ -114,86 +115,108 @@ sealed trait GroupsResponderRequestADM extends KnoraRequestADM /** * Get all information about all groups. * - * @param requestingUser the user initiating the request. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. */ -case class GroupsGetADM(requestingUser: UserADM) extends GroupsResponderRequestADM +case class GroupsGetADM(featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM) extends GroupsResponderRequestADM /** * Get all information about all groups. * - * @param requestingUser the user initiating the request. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. */ -case class GroupsGetRequestADM(requestingUser: UserADM) extends GroupsResponderRequestADM +case class GroupsGetRequestADM(featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM) extends GroupsResponderRequestADM /** * Get everything about a single group identified through its IRI. A successful response will be * an [[Option[GroupADM] ]], which will be `None` if the group was not found. * - * @param groupIri IRI of the group. - * @param requestingUser the user initiating the request. + * @param groupIri IRI of the group. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. */ -case class GroupGetADM(groupIri: IRI, requestingUser: UserADM) extends GroupsResponderRequestADM +case class GroupGetADM(groupIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM) extends GroupsResponderRequestADM /** * Get everything about a single group identified through its IRI. The response will be a * [[GroupGetResponseADM]], or an error if the group was not found. * - * @param groupIri IRI of the group. - * @param requestingUser the user initiating the request. + * @param groupIri IRI of the group. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. */ -case class GroupGetRequestADM(groupIri: IRI, requestingUser: UserADM) extends GroupsResponderRequestADM +case class GroupGetRequestADM(groupIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM) extends GroupsResponderRequestADM /** * Get everything about a multiple groups identified by their IRIs. The response will be a * [[Set[GroupGetResponseADM] ]], or an error if one or more groups was not found. * - * @param groupIris the IRIs of the groups being requested. - * @param requestingUser the user initiating the request. + * @param groupIris the IRIs of the groups being requested. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. */ -case class MultipleGroupsGetRequestADM(groupIris: Set[IRI], requestingUser: UserADM) extends GroupsResponderRequestADM +case class MultipleGroupsGetRequestADM(groupIris: Set[IRI], + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM) extends GroupsResponderRequestADM /** * Returns all members of the group identified by iri. * - * @param groupIri IRI of the group. - * @param requestingUser the user initiating the request. + * @param groupIri IRI of the group. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. */ -case class GroupMembersGetRequestADM(groupIri: IRI, requestingUser: UserADM) extends GroupsResponderRequestADM +case class GroupMembersGetRequestADM(groupIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM) extends GroupsResponderRequestADM /** * Requests the creation of a new group. * - * @param createRequest the [[CreateGroupApiRequestADM]] information for creating the new group. - * @param requestingUser the user initiating the request. - * @param apiRequestID the ID of the API request. + * @param createRequest the [[CreateGroupApiRequestADM]] information for creating the new group. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. + * @param apiRequestID the ID of the API request. */ case class GroupCreateRequestADM(createRequest: CreateGroupApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends GroupsResponderRequestADM /** * Request updating of an existing group. * - * @param groupIri the IRI of the group to be updated. - * @param changeGroupRequest the data which needs to be update. - * @param requestingUser the user initiating the request. - * @param apiRequestID the ID of the API request. + * @param groupIri the IRI of the group to be updated. + * @param changeGroupRequest the data which needs to be update. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. + * @param apiRequestID the ID of the API request. */ case class GroupChangeRequestADM(groupIri: IRI, changeGroupRequest: ChangeGroupApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends GroupsResponderRequestADM /** * Request changing the status (active/inactive) of an existing group. * - * @param groupIri the IRI of the group to be deleted. - * @param changeGroupRequest the data which needs to be update. - * @param requestingUser the user initiating the request. - * @param apiRequestID the ID of the API request. + * @param groupIri the IRI of the group to be deleted. + * @param changeGroupRequest the data which needs to be update. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. + * @param apiRequestID the ID of the API request. */ case class GroupChangeStatusRequestADM(groupIri: IRI, changeGroupRequest: ChangeGroupApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends GroupsResponderRequestADM diff --git a/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/listsmessages/ListsMessagesADM.scala b/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/listsmessages/ListsMessagesADM.scala index 91ad852b5d..fb5e66a7dc 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/listsmessages/ListsMessagesADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/listsmessages/ListsMessagesADM.scala @@ -24,6 +24,7 @@ import java.util.UUID import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport import org.knora.webapi._ import org.knora.webapi.exceptions.BadRequestException +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.StringFormatter import org.knora.webapi.messages.admin.responder.listsmessages.ListsMessagesUtilADM._ import org.knora.webapi.messages.admin.responder.usersmessages._ @@ -62,7 +63,7 @@ case class CreateListApiRequestADM(id: Option[IRI] = None, if (!stringFormatter.isKnoraProjectIriStr(projectIri)) { throw BadRequestException(PROJECT_IRI_INVALID_ERROR) } - + if (labels.isEmpty) { throw BadRequestException(LABEL_MISSING_ERROR) } @@ -172,38 +173,46 @@ sealed trait ListsResponderRequestADM extends KnoraRequestADM /** * Requests a list of all lists or the lists inside a project. A successful response will be a [[ListsGetResponseADM]] * - * @param projectIri the IRI of the project. - * @param requestingUser the user making the request. + * @param projectIri the IRI of the project. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ case class ListsGetRequestADM(projectIri: Option[IRI] = None, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends ListsResponderRequestADM /** * Requests a list. A successful response will be a [[ListGetResponseADM]] * - * @param iri the IRI of the list. - * @param requestingUser the user making the request. + * @param iri the IRI of the list. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ case class ListGetRequestADM(iri: IRI, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends ListsResponderRequestADM /** * Request basic information about a list. A successful response will be a [[ListInfoGetResponseADM]] * - * @param iri the IRI of the list node. - * @param requestingUser the user making the request. + * @param iri the IRI of the list node. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ case class ListInfoGetRequestADM(iri: IRI, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends ListsResponderRequestADM /** * Request basic information about a list node. A successful response will be a [[ListNodeInfoGetResponseADM]] * - * @param iri the IRI of the list node. - * @param requestingUser the user making the request. + * @param iri the IRI of the list node. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ case class ListNodeInfoGetRequestADM(iri: IRI, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends ListsResponderRequestADM @@ -221,24 +230,28 @@ case class NodePathGetRequestADM(iri: IRI, /** * Requests the creation of a new list. * - * @param createListRequest the [[CreateListApiRequestADM]] information used for creating the new list. - * @param requestingUser the user creating the new list. - * @param apiRequestID the ID of the API request. + * @param createListRequest the [[CreateListApiRequestADM]] information used for creating the new list. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user creating the new list. + * @param apiRequestID the ID of the API request. */ case class ListCreateRequestADM(createListRequest: CreateListApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends ListsResponderRequestADM /** * Request updating basic information of an existing list. * - * @param listIri the IRI of the list to be updated. - * @param changeListRequest the data which needs to be update. - * @param requestingUser the user initiating the request. - * @param apiRequestID the ID of the API request. + * @param listIri the IRI of the list to be updated. + * @param changeListRequest the data which needs to be update. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. + * @param apiRequestID the ID of the API request. */ case class ListInfoChangeRequestADM(listIri: IRI, changeListRequest: ChangeListInfoApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends ListsResponderRequestADM @@ -247,11 +260,13 @@ case class ListInfoChangeRequestADM(listIri: IRI, * * @param parentNodeIri the IRI of the list node to which we want to attach the newly created node. * @param createChildNodeRequest the new node information. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the user making the request. * @param apiRequestID the ID of the API request. */ case class ListChildNodeCreateRequestADM(parentNodeIri: IRI, createChildNodeRequest: CreateChildNodeApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends ListsResponderRequestADM @@ -965,7 +980,7 @@ trait ListADMJsonProtocol extends SprayJsonSupport with DefaultJsonProtocol with implicit val createListApiRequestADMFormat: RootJsonFormat[CreateListApiRequestADM] = jsonFormat(CreateListApiRequestADM, "id", "projectIri", "name", "labels", "comments") - implicit val createListNodeApiRequestADMFormat: RootJsonFormat[CreateChildNodeApiRequestADM] = jsonFormat(CreateChildNodeApiRequestADM, "id" , "parentNodeIri", "projectIri", "name", "labels", "comments") + implicit val createListNodeApiRequestADMFormat: RootJsonFormat[CreateChildNodeApiRequestADM] = jsonFormat(CreateChildNodeApiRequestADM, "id", "parentNodeIri", "projectIri", "name", "labels", "comments") implicit val changeListInfoApiRequestADMFormat: RootJsonFormat[ChangeListInfoApiRequestADM] = jsonFormat(ChangeListInfoApiRequestADM, "listIri", "projectIri", "name", "labels", "comments") implicit val nodePathGetResponseADMFormat: RootJsonFormat[NodePathGetResponseADM] = jsonFormat(NodePathGetResponseADM, "elements") implicit val listsGetResponseADMFormat: RootJsonFormat[ListsGetResponseADM] = jsonFormat(ListsGetResponseADM, "lists") diff --git a/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/permissionsmessages/PermissionsMessagesADM.scala b/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/permissionsmessages/PermissionsMessagesADM.scala index 09663516b0..c6c9c4f234 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/permissionsmessages/PermissionsMessagesADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/permissionsmessages/PermissionsMessagesADM.scala @@ -24,6 +24,7 @@ import java.util.UUID import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport import org.knora.webapi._ import org.knora.webapi.exceptions.{BadRequestException, ForbiddenException, InconsistentTriplestoreDataException} +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.OntologyConstants import org.knora.webapi.messages.admin.responder.permissionsmessages.PermissionDataType.PermissionProfileType import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectsADMJsonProtocol @@ -48,7 +49,7 @@ import org.knora.webapi.messages.store.triplestoremessages.TriplestoreJsonProtoc case class CreateAdministrativePermissionAPIRequestADM(id: Option[IRI] = None, forProject: IRI, forGroup: IRI, - hasPermissions: Set[PermissionADM]) extends PermissionsADMJsonProtocol{ + hasPermissions: Set[PermissionADM]) extends PermissionsADMJsonProtocol { def toJsValue: JsValue = createAdministrativePermissionAPIRequestADMFormat.write(this) @@ -80,14 +81,14 @@ case class CreateDefaultObjectAccessPermissionAPIRequestADM(id: Option[IRI] = No stringFormatter.validateProjectIri(forProject, throw BadRequestException(s"Invalid project IRI")) stringFormatter.validateOptionalPermissionIri(id, throw BadRequestException(s"Invalid permission IRI")) forGroup match { - case Some(iri:IRI) => - if(forResourceClass.isDefined) + case Some(iri: IRI) => + if (forResourceClass.isDefined) throw BadRequestException("Not allowed to supply groupIri and resourceClassIri together.") else if (forProperty.isDefined) throw BadRequestException("Not allowed to supply groupIri and propertyIri together.") else Some(iri) case None => - if(forResourceClass.isEmpty && forProperty.isEmpty) { + if (forResourceClass.isEmpty && forProperty.isEmpty) { throw BadRequestException("Either a group, a resource class, a property, or a combination of resource class and property must be given.") } else None } @@ -120,11 +121,13 @@ sealed trait PermissionsResponderRequestADM extends KnoraRequestADM * @param groupIris the groups the user is member of. * @param isInProjectAdminGroups the projects for which the user is member of the ProjectAdmin group. * @param isInSystemAdminGroup the flag denoting users membership in the SystemAdmin group. + * @param featureFactoryConfig the feature factory configuration. */ case class PermissionDataGetADM(projectIris: Seq[IRI], groupIris: Seq[IRI], isInProjectAdminGroups: Seq[IRI], isInSystemAdminGroup: Boolean, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM ) extends PermissionsResponderRequestADM { if (!requestingUser.isSystemUser) throw ForbiddenException("Permission data can only by queried by a SystemUser.") @@ -134,14 +137,16 @@ case class PermissionDataGetADM(projectIris: Seq[IRI], * A message that requests all permissions defined inside a project. * A successful response will be a [[PermissionsForProjectGetResponseADM]]. * - * @param projectIri the project for which the permissions are queried. - * @param requestingUser the user initiation the request. - * @param apiRequestID the API request ID. + * @param projectIri the project for which the permissions are queried. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiation the request. + * @param apiRequestID the API request ID. */ case class PermissionsForProjectGetRequestADM(projectIri: IRI, - requestingUser: UserADM, - apiRequestID: UUID - ) extends PermissionsResponderRequestADM { + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID + ) extends PermissionsResponderRequestADM { implicit protected val stringFormatter: StringFormatter = StringFormatter.getInstanceForConstantOntologies stringFormatter.validateProjectIri(projectIri, throw BadRequestException(s"Invalid project IRI")) @@ -174,10 +179,10 @@ case class AdministrativePermissionsForProjectGetRequestADM(projectIri: IRI, // Check user's permission for the operation if (!requestingUser.isSystemAdmin - && !requestingUser.permissions.isProjectAdmin(projectIri)) { - // not a system or project admin - throw ForbiddenException("Administrative permission can only be queried by system and project admin.") - } + && !requestingUser.permissions.isProjectAdmin(projectIri)) { + // not a system or project admin + throw ForbiddenException("Administrative permission can only be queried by system and project admin.") + } } /** @@ -244,14 +249,17 @@ case class AdministrativePermissionForProjectGroupGetRequestADM(projectIri: IRI, groupIri: IRI, requestingUser: UserADM ) extends PermissionsResponderRequestADM + /** * Create a single [[AdministrativePermissionADM]]. * - * @param createRequest the API create request payload. - * @param requestingUser the requesting user. - * @param apiRequestID the API request ID. + * @param createRequest the API create request payload. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the requesting user. + * @param apiRequestID the API request ID. */ case class AdministrativePermissionCreateRequestADM(createRequest: CreateAdministrativePermissionAPIRequestADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID ) extends PermissionsResponderRequestADM { @@ -378,14 +386,14 @@ case class DefaultObjectAccessPermissionGetADM(projectIri: IRI, } groupIri match { - case Some(iri:IRI) => - if(resourceClassIri.isDefined) + case Some(iri: IRI) => + if (resourceClassIri.isDefined) throw BadRequestException("Not allowed to supply groupIri and resourceClassIri together.") else if (propertyIri.isDefined) throw BadRequestException("Not allowed to supply groupIri and propertyIri together.") else Some(iri) case None => - if(resourceClassIri.isEmpty && propertyIri.isEmpty) { + if (resourceClassIri.isEmpty && propertyIri.isEmpty) { throw BadRequestException("Either a group, a resource class, a property, or a combination of resource class and property must be given.") } else None } @@ -475,14 +483,14 @@ case class DefaultObjectAccessPermissionsStringForResourceClassGetADM(projectIri } if (!stringFormatter.toSmartIri(resourceClassIri).isKnoraEntityIri) { - throw BadRequestException(s"Invalid resource class IRI: $resourceClassIri") + throw BadRequestException(s"Invalid resource class IRI: $resourceClassIri") } if (targetUser.isAnonymousUser) throw BadRequestException("Anonymous Users are not allowed.") -// if (!requestingUser.projects.containsSlice(targetUser.projects)) { -// throw ForbiddenException(s"Target user is not a member of the same project as the requesting user.") -// } + // if (!requestingUser.projects.containsSlice(targetUser.projects)) { + // throw ForbiddenException(s"Target user is not a member of the same project as the requesting user.") + // } } /** @@ -527,18 +535,20 @@ case class DefaultObjectAccessPermissionsStringForPropertyGetADM(projectIri: IRI // if (!requestingUser.projects.containsSlice(targetUser.projects)) { -// throw ForbiddenException(s"Target user is not a member of the same project as the requesting user.") -// } + // throw ForbiddenException(s"Target user is not a member of the same project as the requesting user.") + // } } /** * Create a single [[DefaultObjectAccessPermissionADM]]. * * @param createRequest the create request. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the requesting user. * @param apiRequestID the API request ID. */ case class DefaultObjectAccessPermissionCreateRequestADM(createRequest: CreateDefaultObjectAccessPermissionAPIRequestADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID ) extends PermissionsResponderRequestADM { @@ -564,7 +574,7 @@ case class DefaultObjectAccessPermissionCreateRequestADM(createRequest: CreateDe * @param allPermissions the retrieved sequence of [[PermissionInfoADM]] */ case class PermissionsForProjectGetResponseADM(allPermissions: Set[PermissionInfoADM] - ) extends KnoraResponseADM with PermissionsADMJsonProtocol { + ) extends KnoraResponseADM with PermissionsADMJsonProtocol { def toJsValue = permissionsForProjectGetResponseADMFormat.write(this) } @@ -797,7 +807,7 @@ case class PermissionsDataADM(groupsPerProject: Map[IRI, Seq[IRI]] = Map.empty[I * Represents 'knora-base:AdministrativePermission' * * @param iri the IRI of the permission. - * @param permissionType the type of the permission. + * @param permissionType the type of the permission. */ case class PermissionInfoADM(iri: IRI, permissionType: IRI) extends Jsonable with PermissionsADMJsonProtocol { @@ -872,6 +882,7 @@ case class PermissionADM(name: String, ) extends Jsonable with PermissionsADMJsonProtocol { def toJsValue = permissionADMFormat.write(this) + override def toString: String = name } @@ -1057,9 +1068,9 @@ trait PermissionsADMJsonProtocol extends SprayJsonSupport with DefaultJsonProtoc } implicit val createAdministrativePermissionAPIRequestADMFormat: RootJsonFormat[CreateAdministrativePermissionAPIRequestADM] = rootFormat(lazyFormat(jsonFormat(CreateAdministrativePermissionAPIRequestADM, "id", "forProject", "forGroup", "hasPermissions"))) -// implicit val changeAdministrativePermissionAPIRequestADMFormat: RootJsonFormat[ChangeAdministrativePermissionAPIRequestADM] = jsonFormat(ChangeAdministrativePermissionAPIRequestADM, "iri", "forProject", "forGroup","hasOldPermissions", "hasNewPermissions") + // implicit val changeAdministrativePermissionAPIRequestADMFormat: RootJsonFormat[ChangeAdministrativePermissionAPIRequestADM] = jsonFormat(ChangeAdministrativePermissionAPIRequestADM, "iri", "forProject", "forGroup","hasOldPermissions", "hasNewPermissions") implicit val createDefaultObjectAccessPermissionAPIRequestADMFormat: RootJsonFormat[CreateDefaultObjectAccessPermissionAPIRequestADM] = rootFormat(lazyFormat(jsonFormat(CreateDefaultObjectAccessPermissionAPIRequestADM, "id", "forProject", "forGroup", "forResourceClass", "forProperty", "hasPermissions"))) -// implicit val changeDefaultObjectAccessPermissionAPIRequestADMFormat: RootJsonFormat[ChangeDefaultObjectAccessPermissionAPIRequestADM] = jsonFormat(ChangeDefaultObjectAccessPermissionAPIRequestADM, "iri", "forProject", "forGroup", "forResourceClass", "forProperty", "hasPermissions") + // implicit val changeDefaultObjectAccessPermissionAPIRequestADMFormat: RootJsonFormat[ChangeDefaultObjectAccessPermissionAPIRequestADM] = jsonFormat(ChangeDefaultObjectAccessPermissionAPIRequestADM, "iri", "forProject", "forGroup", "forResourceClass", "forProperty", "hasPermissions") implicit val permissionADMFormat: JsonFormat[PermissionADM] = jsonFormat(PermissionADM.apply, "name", "additionalInformation", "permissionCode") // apply needed because we have an companion object of a case class implicit val permissionInfoADMFormat: JsonFormat[PermissionInfoADM] = lazyFormat(jsonFormat(PermissionInfoADM, "iri", "permissionType")) diff --git a/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/projectsmessages/ProjectsMessagesADM.scala b/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/projectsmessages/ProjectsMessagesADM.scala index d301e33423..b4eea9eb1d 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/projectsmessages/ProjectsMessagesADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/projectsmessages/ProjectsMessagesADM.scala @@ -31,6 +31,7 @@ import org.knora.webapi.messages.admin.responder.{KnoraRequestADM, KnoraResponse import org.knora.webapi.messages.store.triplestoremessages.{StringLiteralV2, TriplestoreJsonProtocol} import org.knora.webapi.messages.v1.responder.projectmessages.ProjectInfoV1 import org.knora.webapi.IRI +import org.knora.webapi.feature.FeatureFactoryConfig import spray.json.{DefaultJsonProtocol, JsValue, JsonFormat, RootJsonFormat} import org.knora.webapi.messages.StringFormatter @@ -108,7 +109,7 @@ case class ChangeProjectApiRequestADM(shortname: Option[String] = None, // Messages /** - * An abstract trait representing a request message that can be sent to [[ProjectsResponderADM]]. + * An abstract trait representing a request message that can be sent to [[org.knora.webapi.responders.admin.ProjectsResponderADM]]. */ sealed trait ProjectsResponderRequestADM extends KnoraRequestADM @@ -118,109 +119,134 @@ sealed trait ProjectsResponderRequestADM extends KnoraRequestADM * Get all information about all projects in form of [[ProjectsGetResponseADM]]. The ProjectsGetRequestV1 returns either * something or a NotFound exception if there are no projects found. Administration permission checking is performed. * - * @param requestingUser the user making the request. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ -case class ProjectsGetRequestADM(requestingUser: UserADM) extends ProjectsResponderRequestADM +case class ProjectsGetRequestADM(featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM) extends ProjectsResponderRequestADM /** * Get all information about all projects in form of a sequence of [[ProjectADM]]. Returns an empty sequence if * no projects are found. Administration permission checking is skipped. * - * @param requestingUser the user making the request. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ -case class ProjectsGetADM(requestingUser: UserADM) extends ProjectsResponderRequestADM +case class ProjectsGetADM(featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM) extends ProjectsResponderRequestADM /** * Get info about a single project identified either through its IRI, shortname or shortcode. The response is in form * of [[ProjectGetResponseADM]]. External use. * - * @param identifier the IRI, email, or username of the project. - * @param requestingUser the user making the request. + * @param identifier the IRI, email, or username of the project. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ case class ProjectGetRequestADM(identifier: ProjectIdentifierADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends ProjectsResponderRequestADM /** * Get info about a single project identified either through its IRI, shortname or shortcode. The response is in form * of [[ProjectADM]]. Internal use only. * - * @param identifier the IRI, email, or username of the project. - * @param requestingUser the user making the request. + * @param identifier the IRI, email, or username of the project. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ case class ProjectGetADM(identifier: ProjectIdentifierADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends ProjectsResponderRequestADM /** * Returns all users belonging to a project identified either through its IRI, shortname or shortcode. * - * @param identifier the IRI, email, or username of the project. - * @param requestingUser the user making the request. + * @param identifier the IRI, email, or username of the project. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ case class ProjectMembersGetRequestADM(identifier: ProjectIdentifierADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends ProjectsResponderRequestADM /** * Returns all admin users of a project identified either through its IRI, shortname or shortcode. * - * @param identifier the IRI, email, or username of the project. - * @param requestingUser the user making the request. + * @param identifier the IRI, email, or username of the project. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ case class ProjectAdminMembersGetRequestADM(identifier: ProjectIdentifierADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends ProjectsResponderRequestADM /** * Returns all unique keywords for all projects. * - * @param requestingUser the user making the request. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ -case class ProjectsKeywordsGetRequestADM(requestingUser: UserADM) extends ProjectsResponderRequestADM +case class ProjectsKeywordsGetRequestADM(featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM) extends ProjectsResponderRequestADM /** * Returns all keywords for a project identified through IRI. * - * @param projectIri the IRI of the project. - * @param requestingUser the user making the request. + * @param projectIri the IRI of the project. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ case class ProjectKeywordsGetRequestADM(projectIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends ProjectsResponderRequestADM /** * Return project's RestrictedView settings. A successful response will be a [[ProjectRestrictedViewSettingsADM]] * - * @param identifier the identifier of the project. - * @param requestingUser the user making the request. + * @param identifier the identifier of the project. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ @ApiMayChange -case class ProjectRestrictedViewSettingsGetADM(identifier: ProjectIdentifierADM, requestingUser: UserADM) extends ProjectsResponderRequestADM +case class ProjectRestrictedViewSettingsGetADM(identifier: ProjectIdentifierADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM) extends ProjectsResponderRequestADM /** * Return project's RestrictedView settings. A successful response will be a [[ProjectRestrictedViewSettingsGetResponseADM]]. * - * @param identifier the identifier of the project. - * @param requestingUser the user making the request. + * @param identifier the identifier of the project. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ @ApiMayChange case class ProjectRestrictedViewSettingsGetRequestADM(identifier: ProjectIdentifierADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends ProjectsResponderRequestADM /** * Requests all the data in the project. A successful response will be a [[ProjectDataGetResponseADM]]. * - * @param projectIdentifier the identifier of the project. - * @param requestingUser the user making the request. + * @param projectIdentifier the identifier of the project. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ case class ProjectDataGetRequestADM(projectIdentifier: ProjectIdentifierADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends ProjectsResponderRequestADM /** * Requests the creation of a new project. * - * @param createRequest the [[CreateProjectApiRequestADM]] information for creation a new project. - * @param requestingUser the user making the request. - * @param apiRequestID the ID of the API request. + * @param createRequest the [[CreateProjectApiRequestADM]] information for creation a new project. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. + * @param apiRequestID the ID of the API request. */ case class ProjectCreateRequestADM(createRequest: CreateProjectApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends ProjectsResponderRequestADM @@ -234,6 +260,7 @@ case class ProjectCreateRequestADM(createRequest: CreateProjectApiRequestADM, */ case class ProjectChangeRequestADM(projectIri: IRI, changeProjectRequest: ChangeProjectApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends ProjectsResponderRequestADM diff --git a/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/sipimessages/SipiMessagesADM.scala b/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/sipimessages/SipiMessagesADM.scala index 8a8fd5c164..25f1457b9d 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/sipimessages/SipiMessagesADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/sipimessages/SipiMessagesADM.scala @@ -20,6 +20,7 @@ package org.knora.webapi.messages.admin.responder.sipimessages import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.admin.responder.projectsmessages.{ProjectRestrictedViewSettingsADM, ProjectsADMJsonProtocol} import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.admin.responder.{KnoraRequestADM, KnoraResponseADM} @@ -33,11 +34,15 @@ sealed trait SipiResponderRequestADM extends KnoraRequestADM /** * A Knora v1 API request message that requests information about a `FileValue`. * - * @param projectID the project shortcode. - * @param filename the name of the file belonging to the file value to be queried. - * @param requestingUser the profile of the user making the request. + * @param projectID the project shortcode. + * @param filename the name of the file belonging to the file value to be queried. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the profile of the user making the request. */ -case class SipiFileInfoGetRequestADM(projectID: String, filename: String, requestingUser: UserADM) extends SipiResponderRequestADM +case class SipiFileInfoGetRequestADM(projectID: String, + filename: String, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM) extends SipiResponderRequestADM /** * Represents the Knora API v1 JSON response to a request for a information about a `FileValue`. diff --git a/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/storesmessages/StoresMessagesADM.scala b/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/storesmessages/StoresMessagesADM.scala index e2655ec990..b9bd03d237 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/storesmessages/StoresMessagesADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/storesmessages/StoresMessagesADM.scala @@ -20,6 +20,7 @@ package org.knora.webapi.messages.admin.responder.storesmessages import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.admin.responder.{KnoraRequestADM, KnoraResponseADM} import org.knora.webapi.messages.store.triplestoremessages.{RdfDataObject, TriplestoreJsonProtocol} import spray.json._ @@ -34,11 +35,14 @@ sealed trait StoreResponderRequestADM extends KnoraRequestADM * Requests to load the triplestore with data referenced inside [[RdfDataObject]]. Any data contained inside the * triplestore will be deleted first. * - * @param rdfDataObjects a sequence of [[RdfDataObject]] objects containing the path to the data and the name of - * the named graph into which the data should be loaded. - * @param prependDefaults should a default set of [[RdfDataObject]]s be prepended. The default is `true`. + * @param rdfDataObjects a sequence of [[RdfDataObject]] objects containing the path to the data and the name of + * the named graph into which the data should be loaded. + * @param prependDefaults should a default set of [[RdfDataObject]]s be prepended. The default is `false`. + * @param featureFactoryConfig the feature factory configuration. */ -case class ResetTriplestoreContentRequestADM(rdfDataObjects: Seq[RdfDataObject], prependDefaults: Boolean = false) extends StoreResponderRequestADM +case class ResetTriplestoreContentRequestADM(rdfDataObjects: Seq[RdfDataObject], + prependDefaults: Boolean = false, + featureFactoryConfig: FeatureFactoryConfig) extends StoreResponderRequestADM case class ResetTriplestoreContentResponseADM(message: String) extends KnoraResponseADM with StoresADMJsonProtocol { def toJsValue = resetTriplestoreContentResponseADMFormat.write(this) diff --git a/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/usersmessages/UsersMessagesADM.scala b/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/usersmessages/UsersMessagesADM.scala index a31deb5a39..228d967ab1 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/usersmessages/UsersMessagesADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/admin/responder/usersmessages/UsersMessagesADM.scala @@ -24,6 +24,7 @@ import java.util.UUID import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport import org.knora.webapi._ import org.knora.webapi.exceptions.{BadRequestException, DataConversionException, InconsistentTriplestoreDataException} +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.admin.responder.groupsmessages.{GroupADM, GroupsADMJsonProtocol} import org.knora.webapi.messages.admin.responder.permissionsmessages.{PermissionsADMJsonProtocol, PermissionsDataADM} import org.knora.webapi.messages.admin.responder.projectsmessages.{ProjectADM, ProjectsADMJsonProtocol} @@ -159,9 +160,11 @@ sealed trait UsersResponderRequestADM extends KnoraRequestADM * no users are found. Administration permission checking is skipped. * * @param userInformationTypeADM the extent of the information returned. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the user that is making the request. */ case class UsersGetADM(userInformationTypeADM: UserInformationTypeADM = UserInformationTypeADM.SHORT, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends UsersResponderRequestADM /** @@ -169,9 +172,11 @@ case class UsersGetADM(userInformationTypeADM: UserInformationTypeADM = UserInfo * something or a NotFound exception if there are no users found. Administration permission checking is performed. * * @param userInformationTypeADM the extent of the information returned. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the user initiating the request. */ case class UsersGetRequestADM(userInformationTypeADM: UserInformationTypeADM = UserInformationTypeADM.SHORT, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends UsersResponderRequestADM /** @@ -179,10 +184,12 @@ case class UsersGetRequestADM(userInformationTypeADM: UserInformationTypeADM = U * * @param identifier the IRI, email, or username of the user to be queried. * @param userInformationTypeADM the extent of the information returned. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the user initiating the request. */ case class UserGetADM(identifier: UserIdentifierADM, userInformationTypeADM: UserInformationTypeADM = UserInformationTypeADM.SHORT, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends UsersResponderRequestADM { } @@ -191,60 +198,70 @@ case class UserGetADM(identifier: UserIdentifierADM, * * @param identifier the IRI, email, or username of the user to be queried. * @param userInformationTypeADM the extent of the information returned. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the user initiating the request. */ case class UserGetRequestADM(identifier: UserIdentifierADM, userInformationTypeADM: UserInformationTypeADM = UserInformationTypeADM.SHORT, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends UsersResponderRequestADM { } /** * Requests the creation of a new user. * - * @param createRequest the [[CreateUserApiRequestADM]] information used for creating the new user. - * @param requestingUser the user creating the new user. - * @param apiRequestID the ID of the API request. + * @param createRequest the [[CreateUserApiRequestADM]] information used for creating the new user. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user creating the new user. + * @param apiRequestID the ID of the API request. */ case class UserCreateRequestADM(createRequest: CreateUserApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends UsersResponderRequestADM /** * Request updating of an existing user. * - * @param userIri the IRI of the user to be updated. - * @param changeUserRequest the data which needs to be update. - * @param requestingUser the user initiating the request. - * @param apiRequestID the ID of the API request. + * @param userIri the IRI of the user to be updated. + * @param changeUserRequest the data which needs to be update. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. + * @param apiRequestID the ID of the API request. */ case class UserChangeBasicUserInformationRequestADM(userIri: IRI, changeUserRequest: ChangeUserApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends UsersResponderRequestADM /** * Request updating the users password. * - * @param userIri the IRI of the user to be updated. - * @param changeUserRequest the [[ChangeUserApiRequestADM]] object containing the old and new password. - * @param requestingUser the user initiating the request. - * @param apiRequestID the ID of the API request. + * @param userIri the IRI of the user to be updated. + * @param changeUserRequest the [[ChangeUserApiRequestADM]] object containing the old and new password. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. + * @param apiRequestID the ID of the API request. */ case class UserChangePasswordRequestADM(userIri: IRI, changeUserRequest: ChangeUserApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends UsersResponderRequestADM /** * Request updating the users status ('knora-base:isActiveUser' property) * - * @param userIri the IRI of the user to be updated. - * @param changeUserRequest the [[ChangeUserApiRequestADM]] containing the new status (true / false). - * @param requestingUser the user initiating the request. - * @param apiRequestID the ID of the API request. + * @param userIri the IRI of the user to be updated. + * @param changeUserRequest the [[ChangeUserApiRequestADM]] containing the new status (true / false). + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. + * @param apiRequestID the ID of the API request. */ case class UserChangeStatusRequestADM(userIri: IRI, changeUserRequest: ChangeUserApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends UsersResponderRequestADM @@ -252,125 +269,141 @@ case class UserChangeStatusRequestADM(userIri: IRI, /** * Request updating the users system admin status ('knora-base:isInSystemAdminGroup' property) * - * @param userIri the IRI of the user to be updated. - * @param changeUserRequest the [[ChangeUserApiRequestADM]] containing - * the new system admin membership status (true / false). - * @param requestingUser the user initiating the request. - * @param apiRequestID the ID of the API request. + * @param userIri the IRI of the user to be updated. + * @param changeUserRequest the [[ChangeUserApiRequestADM]] containing + * the new system admin membership status (true / false). + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. + * @param apiRequestID the ID of the API request. */ case class UserChangeSystemAdminMembershipStatusRequestADM(userIri: IRI, changeUserRequest: ChangeUserApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends UsersResponderRequestADM /** * Requests user's project memberships. * - * @param userIri the IRI of the user. - * @param requestingUser the user initiating the request. - * @param apiRequestID the ID of the API request. + * @param userIri the IRI of the user. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. */ case class UserProjectMembershipsGetRequestADM(userIri: IRI, - requestingUser: UserADM, - apiRequestID: UUID) extends UsersResponderRequestADM + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM) extends UsersResponderRequestADM /** * Requests adding the user to a project. * - * @param userIri the IRI of the user to be updated. - * @param projectIri the IRI of the project. - * @param requestingUser the user initiating the request. - * @param apiRequestID the ID of the API request. + * @param userIri the IRI of the user to be updated. + * @param projectIri the IRI of the project. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. + * @param apiRequestID the ID of the API request. */ case class UserProjectMembershipAddRequestADM(userIri: IRI, projectIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends UsersResponderRequestADM /** * Requests removing the user from a project. * - * @param userIri the IRI of the user to be updated. - * @param projectIri the IRI of the project. - * @param requestingUser the user initiating the request. - * @param apiRequestID the ID of the API request. + * @param userIri the IRI of the user to be updated. + * @param projectIri the IRI of the project. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. + * @param apiRequestID the ID of the API request. */ case class UserProjectMembershipRemoveRequestADM(userIri: IRI, projectIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends UsersResponderRequestADM /** * Requests user's project admin memberships. * - * @param userIri the IRI of the user. - * @param requestingUser the user initiating the request. - * @param apiRequestID the ID of the API request. + * @param userIri the IRI of the user. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. + * @param apiRequestID the ID of the API request. */ case class UserProjectAdminMembershipsGetRequestADM(userIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends UsersResponderRequestADM /** * Requests adding the user to a project as project admin. * - * @param userIri the IRI of the user to be updated. - * @param projectIri the IRI of the project. - * @param requestingUser the user initiating the request. - * @param apiRequestID the ID of the API request. + * @param userIri the IRI of the user to be updated. + * @param projectIri the IRI of the project. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. + * @param apiRequestID the ID of the API request. */ case class UserProjectAdminMembershipAddRequestADM(userIri: IRI, projectIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends UsersResponderRequestADM /** * Requests removing the user from a project as project admin. * - * @param userIri the IRI of the user to be updated. - * @param projectIri the IRI of the project. - * @param requestingUser the user initiating the request. - * @param apiRequestID the ID of the API request. + * @param userIri the IRI of the user to be updated. + * @param projectIri the IRI of the project. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. + * @param apiRequestID the ID of the API request. */ case class UserProjectAdminMembershipRemoveRequestADM(userIri: IRI, projectIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends UsersResponderRequestADM /** * Requests user's group memberships. * - * @param userIri the IRI of the user. - * @param requestingUser the user initiating the request. - * @param apiRequestID the ID of the API request. + * @param userIri the IRI of the user. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. */ case class UserGroupMembershipsGetRequestADM(userIri: IRI, - requestingUser: UserADM, - apiRequestID: UUID) extends UsersResponderRequestADM + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM) extends UsersResponderRequestADM /** * Requests adding the user to a group. * - * @param userIri the IRI of the user to be updated. - * @param groupIri the IRI of the group. - * @param requestingUser the user initiating the request. - * @param apiRequestID the ID of the API request. + * @param userIri the IRI of the user to be updated. + * @param groupIri the IRI of the group. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. + * @param apiRequestID the ID of the API request. */ case class UserGroupMembershipAddRequestADM(userIri: IRI, groupIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends UsersResponderRequestADM /** * Requests removing the user from a group. * - * @param userIri the IRI of the user to be updated. - * @param groupIri the IRI of the group. - * @param requestingUser the user initiating the request. - * @param apiRequestID the ID of the API request. + * @param userIri the IRI of the user to be updated. + * @param groupIri the IRI of the group. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. + * @param apiRequestID the ID of the API request. */ case class UserGroupMembershipRemoveRequestADM(userIri: IRI, groupIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends UsersResponderRequestADM diff --git a/webapi/src/main/scala/org/knora/webapi/messages/store/triplestoremessages/TriplestoreMessages.scala b/webapi/src/main/scala/org/knora/webapi/messages/store/triplestoremessages/TriplestoreMessages.scala index b31aa0e89c..b175a05e62 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/store/triplestoremessages/TriplestoreMessages.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/store/triplestoremessages/TriplestoreMessages.scala @@ -19,27 +19,24 @@ package org.knora.webapi.messages.store.triplestoremessages -import java.io.{File, StringReader} +import java.io.File import java.time.Instant import akka.event.LoggingAdapter import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport import org.apache.commons.lang3.StringUtils -import org.eclipse.rdf4j -import org.eclipse.rdf4j.model.Statement -import org.eclipse.rdf4j.rio.RDFHandler -import org.eclipse.rdf4j.rio.turtle.TurtleParser import org.knora.webapi._ -import org.knora.webapi.exceptions.{BadRequestException, DataConversionException, InconsistentTriplestoreDataException, NotImplementedException, TriplestoreResponseException} +import org.knora.webapi.exceptions._ +import org.knora.webapi.feature.FeatureFactoryConfig +import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.store.StoreRequest import org.knora.webapi.messages.store.triplestoremessages.TriplestoreStatus.TriplestoreStatus -import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.util.ErrorHandlingMap -import spray.json.{DefaultJsonProtocol, DeserializationException, JsObject, JsString, JsValue, JsonFormat, NullOptions, RootJsonFormat, _} +import org.knora.webapi.messages.util.rdf._ import org.knora.webapi.messages.{OntologyConstants, SmartIri, StringFormatter} +import spray.json._ import scala.collection.mutable -import scala.compat.java8.OptionConverters._ import scala.util.{Failure, Success, Try} ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -127,9 +124,11 @@ case class VariableResultsRow(rowMap: ErrorHandlingMap[String, String]) { * Represents a SPARQL CONSTRUCT query to be sent to the triplestore. A successful response will be a * [[SparqlConstructResponse]]. * - * @param sparql the SPARQL string. + * @param sparql the SPARQL string. + * @param featureFactoryConfig the feature factory configuration. */ -case class SparqlConstructRequest(sparql: String) extends TriplestoreRequest +case class SparqlConstructRequest(sparql: String, + featureFactoryConfig: FeatureFactoryConfig) extends TriplestoreRequest /** * Represents a SPARQL CONSTRUCT query to be sent to the triplestore. The triplestore's will be @@ -139,7 +138,9 @@ case class SparqlConstructRequest(sparql: String) extends TriplestoreRequest * @param graphIri the named graph IRI to be used in the TriG file. * @param outputFile the file to be written. */ -case class SparqlConstructFileRequest(sparql: String, graphIri: IRI, outputFile: File) extends TriplestoreRequest +case class SparqlConstructFileRequest(sparql: String, + graphIri: IRI, + outputFile: File) extends TriplestoreRequest /** * A response to a [[SparqlConstructRequest]]. @@ -152,9 +153,11 @@ case class SparqlConstructResponse(statements: Map[IRI, Seq[(IRI, String)]]) * Represents a SPARQL CONSTRUCT query to be sent to the triplestore. A successful response will be a * [[SparqlExtendedConstructResponse]]. * - * @param sparql the SPARQL string. + * @param sparql the SPARQL string. + * @param featureFactoryConfig the feature factory configuration. */ -case class SparqlExtendedConstructRequest(sparql: String) extends TriplestoreRequest +case class SparqlExtendedConstructRequest(sparql: String, + featureFactoryConfig: FeatureFactoryConfig) extends TriplestoreRequest /** * Parses Turtle documents and converts them to [[SparqlExtendedConstructResponse]] objects. @@ -168,83 +171,80 @@ object SparqlExtendedConstructResponse { private val logDelimiter = "\n" + StringUtils.repeat('=', 80) + "\n" /** - * Converts a graph in parsed Turtle to a [[SparqlExtendedConstructResponse]]. + * Parses a Turtle document, converting it to a [[SparqlExtendedConstructResponse]]. + * + * @param turtleStr the Turtle document. + * @param rdfFormatUtil an [[RdfFormatUtil]]. + * @param log a [[LoggingAdapter]]. + * @return a [[SparqlExtendedConstructResponse]] representing the document. */ - class ConstructResponseTurtleHandler extends RDFHandler { + def parseTurtleResponse(turtleStr: String, rdfFormatUtil: RdfFormatUtil, log: LoggingAdapter): Try[SparqlExtendedConstructResponse] = { + val parseTry = Try { + implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance - implicit private val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance + val statementMap: mutable.Map[SubjectV2, ConstructPredicateObjects] = mutable.Map.empty + val rdfModel: RdfModel = rdfFormatUtil.parseToRdfModel(rdfStr = turtleStr, rdfFormat = Turtle) - /** - * A collection of all the statements in the input file, grouped and sorted by subject IRI. - */ - private val statements: mutable.Map[SubjectV2, ConstructPredicateObjects] = mutable.Map.empty + for (st: Statement <- rdfModel.getStatements) { + val subject: SubjectV2 = st.subj match { + case iriNode: IriNode => IriSubjectV2(iriNode.iri) + case blankNode: BlankNode => BlankNodeSubjectV2(blankNode.id) + } - override def handleComment(comment: IRI): Unit = {} + val predicateIri: SmartIri = st.pred.iri.toSmartIri - /** - * Adds a statement to the collection `statements`. - * - * @param st the statement to be added. - */ - override def handleStatement(st: Statement): Unit = { - val subject: SubjectV2 = st.getSubject match { - case iri: rdf4j.model.IRI => IriSubjectV2(iri.stringValue) - case blankNode: rdf4j.model.BNode => BlankNodeSubjectV2(blankNode.getID) - case other => throw InconsistentTriplestoreDataException(s"Unsupported subject in construct query result: $other") - } + val objectLiteral: LiteralV2 = st.obj match { + case iriNode: IriNode => IriLiteralV2(value = iriNode.iri) + case blankNode: BlankNode => BlankNodeLiteralV2(value = blankNode.id) - val predicateIri: SmartIri = st.getPredicate.stringValue.toSmartIri - - val objectLiteral: LiteralV2 = st.getObject match { - case iri: rdf4j.model.IRI => IriLiteralV2(value = iri.stringValue) - case blankNode: rdf4j.model.BNode => BlankNodeLiteralV2(value = blankNode.getID) - - case literal: rdf4j.model.Literal => literal.getDatatype.toString match { - case OntologyConstants.Rdf.LangString => StringLiteralV2(value = literal.stringValue, language = literal.getLanguage.asScala) - case OntologyConstants.Xsd.String => StringLiteralV2(value = literal.stringValue, language = None) - case OntologyConstants.Xsd.Boolean => BooleanLiteralV2(value = literal.booleanValue) - case OntologyConstants.Xsd.Int | OntologyConstants.Xsd.Integer | OntologyConstants.Xsd.NonNegativeInteger => IntLiteralV2(value = literal.intValue) - case OntologyConstants.Xsd.Decimal => DecimalLiteralV2(value = literal.decimalValue) - case OntologyConstants.Xsd.DateTime => DateTimeLiteralV2(stringFormatter.xsdDateTimeStampToInstant(literal.stringValue, throw InconsistentTriplestoreDataException(s"Invalid xsd:dateTime: ${literal.stringValue}"))) - case OntologyConstants.Xsd.Uri => IriLiteralV2(value = literal.stringValue) - case unknown => throw NotImplementedException(s"The literal type '$unknown' is not implemented.") - } + case literal: RdfLiteral => + literal match { + case datatypeLiteral: DatatypeLiteral => + datatypeLiteral.datatype match { + case datatypeIri if OntologyConstants.Xsd.integerTypes.contains(datatypeIri) => + IntLiteralV2( + datatypeLiteral.integerValue(throw InconsistentTriplestoreDataException(s"Invalid integer: ${datatypeLiteral.value}")).toInt + ) - case other => throw InconsistentTriplestoreDataException(s"Unsupported object in construct query result: $other") - } + case OntologyConstants.Xsd.DateTime => + DateTimeLiteralV2( + stringFormatter.xsdDateTimeStampToInstant( + datatypeLiteral.value, + throw InconsistentTriplestoreDataException(s"Invalid xsd:dateTime: ${datatypeLiteral.value}") + ) + ) - val currentStatementsForSubject: Map[SmartIri, Seq[LiteralV2]] = statements.getOrElse(subject, Map.empty[SmartIri, Seq[LiteralV2]]) - val currentStatementsForPredicate: Seq[LiteralV2] = currentStatementsForSubject.getOrElse(predicateIri, Seq.empty[LiteralV2]) + case OntologyConstants.Xsd.Boolean => + BooleanLiteralV2( + datatypeLiteral.booleanValue(throw InconsistentTriplestoreDataException(s"Invalid xsd:boolean: ${datatypeLiteral.value}")) + ) - val updatedPredicateStatements = currentStatementsForPredicate :+ objectLiteral - val updatedSubjectStatements = currentStatementsForSubject + (predicateIri -> updatedPredicateStatements) + case OntologyConstants.Xsd.String => StringLiteralV2(value = datatypeLiteral.value, language = None) - statements += (subject -> updatedSubjectStatements) - } + case OntologyConstants.Xsd.Decimal => DecimalLiteralV2( + datatypeLiteral.decimalValue(throw InconsistentTriplestoreDataException(s"Invalid xsd:decimal: ${datatypeLiteral.value}")) + ) - override def endRDF(): Unit = {} + case OntologyConstants.Xsd.Uri => IriLiteralV2(datatypeLiteral.value) - override def handleNamespace(prefix: IRI, uri: IRI): Unit = {} + case unknown => throw NotImplementedException(s"The literal type '$unknown' is not implemented.") + } - override def startRDF(): Unit = {} + case stringWithLanguage: StringWithLanguage => + StringLiteralV2(value = stringWithLanguage.value, language = Some(stringWithLanguage.language)) + } + } - def getConstructResponse: SparqlExtendedConstructResponse = SparqlExtendedConstructResponse(statements.toMap) - } + val currentStatementsForSubject: Map[SmartIri, Seq[LiteralV2]] = statementMap.getOrElse(subject, Map.empty[SmartIri, Seq[LiteralV2]]) + val currentStatementsForPredicate: Seq[LiteralV2] = currentStatementsForSubject.getOrElse(predicateIri, Seq.empty[LiteralV2]) - /** - * Parses a Turtle document, converting it to a [[SparqlExtendedConstructResponse]]. - * - * @param turtleStr the Turtle document. - * @param log a [[LoggingAdapter]]. - * @return a [[SparqlExtendedConstructResponse]] representing the document. - */ - def parseTurtleResponse(turtleStr: String, log: LoggingAdapter): Try[SparqlExtendedConstructResponse] = { - val parseTry = Try { - val turtleParser = new TurtleParser() - val handler = new ConstructResponseTurtleHandler - turtleParser.setRDFHandler(handler) - turtleParser.parse(new StringReader(turtleStr), "") - handler.getConstructResponse + val updatedPredicateStatements = currentStatementsForPredicate :+ objectLiteral + val updatedSubjectStatements = currentStatementsForSubject + (predicateIri -> updatedPredicateStatements) + + statementMap += (subject -> updatedSubjectStatements) + } + + SparqlExtendedConstructResponse(statementMap.toMap) } parseTry match { @@ -270,13 +270,14 @@ case class SparqlExtendedConstructResponse(statements: Map[SubjectV2, SparqlExte * @param graphIri the IRI of the named graph. * @param outputFile the destination file. */ -case class NamedGraphFileRequest(graphIri: IRI, outputFile: File) extends TriplestoreRequest +case class NamedGraphFileRequest(graphIri: IRI, + outputFile: File) extends TriplestoreRequest /** * Requests a named graph, which will be returned as Turtle. A successful response * will be a [[NamedGraphDataResponse]]. * - * @param graphIri the IRI of the named graph. + * @param graphIri the IRI of the named graph. */ case class NamedGraphDataRequest(graphIri: IRI) extends TriplestoreRequest @@ -604,9 +605,11 @@ case class BlankNodeLiteralV2(value: String) extends LiteralV2 { */ case class StringLiteralV2(value: String, language: Option[String] = None) extends LiteralV2 with OntologyLiteralV2 with Ordered[StringLiteralV2] { override def toString: String = value - if(language.isDefined && value.isEmpty) { + + if (language.isDefined && value.isEmpty) { throw BadRequestException(s"String value is missing.") } + def compare(that: StringLiteralV2): Int = this.value.compareTo(that.value) } diff --git a/webapi/src/main/scala/org/knora/webapi/messages/util/ConstructResponseUtilV2.scala b/webapi/src/main/scala/org/knora/webapi/messages/util/ConstructResponseUtilV2.scala index 1046fd64e7..aaecdc1766 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/util/ConstructResponseUtilV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/util/ConstructResponseUtilV2.scala @@ -28,6 +28,7 @@ import akka.util.Timeout import akka.pattern.ask import org.knora.webapi._ import org.knora.webapi.exceptions.{AssertionException, InconsistentTriplestoreDataException, NotImplementedException} +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.admin.responder.projectsmessages.{ProjectGetRequestADM, ProjectGetResponseADM, ProjectIdentifierADM} import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.store.triplestoremessages.SparqlExtendedConstructResponse.ConstructPredicateObjects @@ -43,6 +44,7 @@ import org.knora.webapi.messages.{OntologyConstants, SmartIri, StringFormatter} import org.knora.webapi.settings.KnoraSettingsImpl import org.knora.webapi.util.ActorUtil import org.knora.webapi.messages.IriConversions._ + import scala.concurrent.{ExecutionContext, Future} object ConstructResponseUtilV2 { @@ -873,6 +875,7 @@ object ConstructResponseUtilV2 { * @param mappings the mappings needed for standoff conversions and XSL transformations. * @param queryStandoff if `true`, make separate queries to get the standoff for the text value. * @param responderManager the Knora responder manager. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the user making the request. * @return a [[TextValueContentV2]]. */ @@ -883,6 +886,7 @@ object ConstructResponseUtilV2 { mappings: Map[IRI, MappingAndXSLTransformation], queryStandoff: Boolean, responderManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM)(implicit stringFormatter: StringFormatter, timeout: Timeout, executionContext: ExecutionContext): Future[TextValueContentV2] = { // Any knora-base:TextValue may have a language val valueLanguageOption: Option[String] = valueObject.maybeStringObject(OntologyConstants.KnoraBase.ValueHasLanguage.toSmartIri) @@ -912,7 +916,12 @@ object ConstructResponseUtilV2 { // concatenated together and returned in a GetStandoffResponseV2. for { - standoffResponse <- (responderManager ? GetRemainingStandoffFromTextValueRequestV2(resourceIri = resourceIri, valueIri = valueObject.subjectIri, requestingUser = requestingUser)).mapTo[GetStandoffResponseV2] + standoffResponse <- (responderManager ? GetRemainingStandoffFromTextValueRequestV2( + resourceIri = resourceIri, + valueIri = valueObject.subjectIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + )).mapTo[GetStandoffResponseV2] } yield standoff ++ standoffResponse.standoff } else { // We're not supposed to get any more standoff here, either because we have all of it already, @@ -1007,6 +1016,7 @@ object ConstructResponseUtilV2 { * @param versionDate if defined, represents the requested time in the the resources' version history. * @param responderManager the Knora responder manager. * @param targetSchema the schema of the response. + * @param featureFactoryConfig the feature factory configuration. * @param settings the application's settings. * @param requestingUser the user making the request. * @return a [[LinkValueContentV2]]. @@ -1019,6 +1029,7 @@ object ConstructResponseUtilV2 { versionDate: Option[Instant], responderManager: ActorRef, targetSchema: ApiV2Schema, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, requestingUser: UserADM)(implicit stringFormatter: StringFormatter, timeout: Timeout, executionContext: ExecutionContext): Future[LinkValueContentV2] = { val referredResourceIri: IRI = if (valueObject.isIncomingLink) { @@ -1049,6 +1060,7 @@ object ConstructResponseUtilV2 { responderManager = responderManager, requestingUser = requestingUser, targetSchema = targetSchema, + featureFactoryConfig = featureFactoryConfig, settings = settings ) } yield linkValue.copy( @@ -1064,14 +1076,15 @@ object ConstructResponseUtilV2 { /** * Given a [[ValueRdfData]], constructs a [[ValueContentV2]], considering the specific type of the given [[ValueRdfData]]. * - * @param valueObject the given [[ValueRdfData]]. - * @param mappings the mappings needed for standoff conversions and XSL transformations. - * @param queryStandoff if `true`, make separate queries to get the standoff for text values. - * @param versionDate if defined, represents the requested time in the the resources' version history. - * @param responderManager the Knora responder manager. - * @param targetSchema the schema of the response. - * @param settings the application's settings. - * @param requestingUser the user making the request. + * @param valueObject the given [[ValueRdfData]]. + * @param mappings the mappings needed for standoff conversions and XSL transformations. + * @param queryStandoff if `true`, make separate queries to get the standoff for text values. + * @param versionDate if defined, represents the requested time in the the resources' version history. + * @param responderManager the Knora responder manager. + * @param targetSchema the schema of the response. + * @param featureFactoryConfig the feature factory configuration. + * @param settings the application's settings. + * @param requestingUser the user making the request. * @return a [[ValueContentV2]] representing a value. */ private def createValueContentV2FromValueRdfData(resourceIri: IRI, @@ -1081,6 +1094,7 @@ object ConstructResponseUtilV2 { versionDate: Option[Instant] = None, responderManager: ActorRef, targetSchema: ApiV2Schema, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, requestingUser: UserADM)(implicit stringFormatter: StringFormatter, timeout: Timeout, executionContext: ExecutionContext): Future[ValueContentV2] = { // every knora-base:Value (any of its subclasses) has a string representation, but it is not necessarily returned with text values. @@ -1101,6 +1115,7 @@ object ConstructResponseUtilV2 { mappings = mappings, queryStandoff = queryStandoff, responderManager = responderManager, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) @@ -1184,7 +1199,11 @@ object ConstructResponseUtilV2 { targetSchema match { case ApiV2Simple => for { - nodeResponse <- (responderManager ? NodeGetRequestV2(listNodeIri, requestingUser)).mapTo[NodeGetResponseV2] + nodeResponse <- (responderManager ? NodeGetRequestV2( + nodeIri = listNodeIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + )).mapTo[NodeGetResponseV2] } yield listNode.copy( listNodeLabel = nodeResponse.node.getLabelInPreferredLanguage(userLang = requestingUser.lang, fallbackLang = settings.fallbackLanguage) ) @@ -1192,7 +1211,6 @@ object ConstructResponseUtilV2 { case ApiV2Complex => FastFuture.successful(listNode) } - case OntologyConstants.KnoraBase.IntervalValue => FastFuture.successful(IntervalValueContentV2( ontologySchema = InternalSchema, @@ -1219,6 +1237,7 @@ object ConstructResponseUtilV2 { responderManager = responderManager, requestingUser = requestingUser, targetSchema = targetSchema, + featureFactoryConfig = featureFactoryConfig, settings = settings ) @@ -1248,6 +1267,7 @@ object ConstructResponseUtilV2 { * @param versionDate if defined, represents the requested time in the the resources' version history. * @param responderManager the Knora responder manager. * @param targetSchema the schema of the response. + * @param featureFactoryConfig the feature factory configuration. * @param settings the application's settings. * @param requestingUser the user making the request. * @return a [[ReadResourceV2]]. @@ -1259,6 +1279,7 @@ object ConstructResponseUtilV2 { versionDate: Option[Instant], responderManager: ActorRef, targetSchema: ApiV2Schema, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, requestingUser: UserADM)(implicit stringFormatter: StringFormatter, timeout: Timeout, executionContext: ExecutionContext): Future[ReadResourceV2] = { def getDeletionInfo(rdfData: RdfData): Option[DeletionInfo] = { @@ -1307,6 +1328,7 @@ object ConstructResponseUtilV2 { responderManager = responderManager, requestingUser = requestingUser, targetSchema = targetSchema, + featureFactoryConfig = featureFactoryConfig, settings = settings ) @@ -1369,7 +1391,12 @@ object ConstructResponseUtilV2 { } for { - projectResponse: ProjectGetResponseADM <- (responderManager ? ProjectGetRequestADM(ProjectIdentifierADM(maybeIri = Some(resourceAttachedToProject)), requestingUser = requestingUser)).mapTo[ProjectGetResponseADM] + projectResponse: ProjectGetResponseADM <- (responderManager ? ProjectGetRequestADM( + identifier = ProjectIdentifierADM(maybeIri = Some(resourceAttachedToProject)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + )).mapTo[ProjectGetResponseADM] + valueObjects <- ActorUtil.sequenceSeqFuturesInMap(valueObjectFutures) } yield ReadResourceV2( resourceIri = resourceIri, @@ -1401,6 +1428,7 @@ object ConstructResponseUtilV2 { * @param versionDate if defined, represents the requested time in the the resources' version history. * @param responderManager the Knora responder manager. * @param targetSchema the schema of response. + * @param featureFactoryConfig the feature factory configuration. * @param settings the application's settings. * @param requestingUser the user making the request. * @return a collection of [[ReadResourceV2]] representing the search results. @@ -1414,6 +1442,7 @@ object ConstructResponseUtilV2 { versionDate: Option[Instant], responderManager: ActorRef, targetSchema: ApiV2Schema, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, requestingUser: UserADM)(implicit stringFormatter: StringFormatter, timeout: Timeout, executionContext: ExecutionContext): Future[ReadResourcesSequenceV2] = { @@ -1430,6 +1459,7 @@ object ConstructResponseUtilV2 { versionDate = versionDate, responderManager = responderManager, targetSchema = targetSchema, + featureFactoryConfig = featureFactoryConfig, settings = settings, requestingUser = requestingUser ) diff --git a/webapi/src/main/scala/org/knora/webapi/messages/util/PermissionUtilADM.scala b/webapi/src/main/scala/org/knora/webapi/messages/util/PermissionUtilADM.scala index 3372983a01..eca1b935ea 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/util/PermissionUtilADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/util/PermissionUtilADM.scala @@ -34,6 +34,7 @@ import org.knora.webapi.messages.store.triplestoremessages.{LiteralV2, SparqlExt import org.knora.webapi.messages.v1.responder.usermessages.UserProfileV1 import org.knora.webapi.messages.{OntologyConstants, SmartIri, StringFormatter} import GroupedProps.{ValueLiterals, ValueProps} +import org.knora.webapi.feature.FeatureFactoryConfig import scala.concurrent.{ExecutionContext, Future} @@ -677,12 +678,14 @@ object PermissionUtilADM extends LazyLogging { * Given a permission literal, checks that it refers to valid permissions and groups. * * @param permissionLiteral the permission literal. + * @param featureFactoryConfig the feature factory configuration. * @param responderManager a reference to the responder manager. * @param timeout a timeout for `ask` messages. * @param executionContext an execution context for futures. * @return the validated permission literal, normalised and reformatted. */ def validatePermissions(permissionLiteral: String, + featureFactoryConfig: FeatureFactoryConfig, responderManager: ActorRef) (implicit timeout: Timeout, executionContext: ExecutionContext): Future[String] = { val stringFormatter = StringFormatter.getGeneralInstance @@ -697,7 +700,11 @@ object PermissionUtilADM extends LazyLogging { validatedProjectSpecificGroupIris: Set[IRI] = projectSpecificGroupIris.map(iri => stringFormatter.validateAndEscapeIri(iri, throw BadRequestException(s"Invalid group IRI: $iri"))) // Check that those groups exist. - _ <- (responderManager ? MultipleGroupsGetRequestADM(groupIris = validatedProjectSpecificGroupIris, requestingUser = KnoraSystemInstances.Users.SystemUser)).mapTo[Set[GroupGetResponseADM]] + _ <- (responderManager ? MultipleGroupsGetRequestADM( + groupIris = validatedProjectSpecificGroupIris, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + )).mapTo[Set[GroupGetResponseADM]] // Reformat the permission literal. permissionADMs: Set[PermissionADM] = parsedPermissions.flatMap { diff --git a/webapi/src/main/scala/org/knora/webapi/messages/util/RdfFormatUtil.scala b/webapi/src/main/scala/org/knora/webapi/messages/util/RdfFormatUtil.scala deleted file mode 100644 index e078ce35f9..0000000000 --- a/webapi/src/main/scala/org/knora/webapi/messages/util/RdfFormatUtil.scala +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright © 2015-2018 the contributors (see Contributors.md). - * - * This file is part of Knora. - * - * Knora is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Knora is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public - * License along with Knora. If not, see . - */ - -package org.knora.webapi.messages.util - -import java.io.{StringReader, StringWriter} - -import akka.http.scaladsl.model.MediaType -import org.apache.jena -import org.eclipse.rdf4j -import org.knora.webapi.RdfMediaTypes -import org.knora.webapi.exceptions.AssertionException - -/** - * Utilities for converting RDF between different formats. - * - * // TODO: Make this into a façade as per https://dasch.myjetbrains.com/youtrack/issue/DSP-902. - */ -object RdfFormatUtil { - /** - * Parses RDF to a [[jena.graph.Graph]]. - * - * @param rdfStr the RDF to be parsed. - * @param mediaType the format of the request entity. Must be one of the supported types - * `application/ld+json`, `text/turtle`, or `application/rdf+xml`. - * @return the corresponding [[jena.graph.Graph]]. - */ - def parseToJenaGraph(rdfStr: String, mediaType: MediaType.NonBinary): jena.graph.Graph = { - // Create an empty Jena Graph. - val modelMaker: jena.rdf.model.ModelMaker = jena.rdf.model.ModelFactory.createMemModelMaker - val graphMaker: jena.graph.GraphMaker = modelMaker.getGraphMaker - val graph: jena.graph.Graph = graphMaker.createGraph - - // Convert the media type to a Jena RDF format name. - val rdfLang: jena.riot.Lang = mediaType match { - case RdfMediaTypes.`application/ld+json` => jena.riot.RDFLanguages.JSONLD - case RdfMediaTypes.`text/turtle` => jena.riot.RDFLanguages.TURTLE - case RdfMediaTypes.`application/rdf+xml` => jena.riot.RDFLanguages.RDFXML - case other => throw AssertionException(s"Unsupported media type: $other") - } - - // Construct and configure an RDF parser, and parse the RDF. - jena.riot.RDFParser.create() - .source(new StringReader(rdfStr)) - .lang(rdfLang) - .errorHandler(jena.riot.system.ErrorHandlerFactory.errorHandlerStrictNoLogging) - .parse(graph) - - graph - } - - /** - * Parses RDF to a [[JsonLDDocument]]. - * - * @param rdfStr the RDF to be parsed. - * @param mediaType the format of the request entity. Must be one of the supported types - * `application/ld+json`, `text/turtle`, or `application/rdf+xml`. - * @return the corresponding [[JsonLDDocument]]. - */ - def parseToJsonLDDocument(rdfStr: String, mediaType: MediaType.NonBinary): JsonLDDocument = { - // Which format is the input in? - mediaType match { - case RdfMediaTypes.`application/ld+json` => - // JSON-LD. Parse it with JsonLDUtil. - JsonLDUtil.parseJsonLD(rdfStr) - - case _ => - // Some other format. Parse it with RDF4J. - - val rdfFormat = mediaType match { - case RdfMediaTypes.`text/turtle` => rdf4j.rio.RDFFormat.TURTLE - case RdfMediaTypes.`application/rdf+xml` => rdf4j.rio.RDFFormat.RDFXML - case other => throw AssertionException(s"Unsupported media type: $other") - } - - val model: rdf4j.model.Model = - rdf4j.rio.Rio.parse(new StringReader(rdfStr), "", rdfFormat, null) - - // Convert the model to a JsonLDDocument. - JsonLDUtil.fromRDF4JModel(model) - } - } - - /** - * Formats RDF as an API response in the requested media type. - * - * @param model an RDF4J model. - * @param mediaType the specific media type selected for the response. - * @return the model formatted in the specified format. - */ - def formatRDF4JModel(model: rdf4j.model.Model, - mediaType: MediaType.NonBinary): String = { - // A StringWriter to collect the formatted output. - val stringWriter = new StringWriter() - - // Which format is the input in? - mediaType match { - case RdfMediaTypes.`application/ld+json` => - // JSON-LD. Use JsonLDUtil for the conversion. - JsonLDUtil.fromRDF4JModel(model).toPrettyString - - case _ => - // Some other format. Construct an RDF4J RDFWriter for it. - val rdfWriter: rdf4j.rio.RDFWriter = mediaType match { - case RdfMediaTypes.`text/turtle` => rdf4j.rio.Rio.createWriter(rdf4j.rio.RDFFormat.TURTLE, stringWriter) - case RdfMediaTypes.`application/rdf+xml` => new rdf4j.rio.rdfxml.util.RDFXMLPrettyWriter(stringWriter) - case other => throw AssertionException(s"Unsupported media type: $other") - } - - // Configure the RDFWriter. - rdfWriter.getWriterConfig.set[java.lang.Boolean](rdf4j.rio.helpers.BasicWriterSettings.INLINE_BLANK_NODES, true). - set[java.lang.Boolean](rdf4j.rio.helpers.BasicWriterSettings.PRETTY_PRINT, true) - - // Format the RDF. - rdf4j.rio.Rio.write(model, rdfWriter) - stringWriter.toString - } - } -} diff --git a/webapi/src/main/scala/org/knora/webapi/messages/util/UserUtilADM.scala b/webapi/src/main/scala/org/knora/webapi/messages/util/UserUtilADM.scala index 198987397f..7f14050cc3 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/util/UserUtilADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/util/UserUtilADM.scala @@ -25,6 +25,7 @@ import akka.util.Timeout import akka.pattern.ask import org.knora.webapi.IRI import org.knora.webapi.exceptions.ForbiddenException +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.StringFormatter import org.knora.webapi.messages.admin.responder.usersmessages._ @@ -43,11 +44,13 @@ object UserUtilADM { * @param requestingUser the requesting user. * @param requestedUserIri the IRI of the requested user. * @param projectIri the IRI of the project. + * @param featureFactoryConfig the feature factory configuration. * @return a [[UserADM]] representing the requested user. */ def switchToUser(requestingUser: UserADM, requestedUserIri: IRI, projectIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, responderManager: ActorRef)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[UserADM] = { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance @@ -60,6 +63,7 @@ object UserUtilADM { userResponse: UserResponseADM <- (responderManager ? UserGetRequestADM( identifier = UserIdentifierADM(maybeIri = Some(requestedUserIri)), userInformationTypeADM = UserInformationTypeADM.FULL, + featureFactoryConfig = featureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser )).mapTo[UserResponseADM] } yield userResponse.user diff --git a/webapi/src/main/scala/org/knora/webapi/messages/util/ValueUtilV1.scala b/webapi/src/main/scala/org/knora/webapi/messages/util/ValueUtilV1.scala index 3cde095b97..d219380ccd 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/util/ValueUtilV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/util/ValueUtilV1.scala @@ -24,6 +24,7 @@ import akka.pattern._ import akka.util.Timeout import org.knora.webapi._ import org.knora.webapi.exceptions.{InconsistentTriplestoreDataException, NotImplementedException, OntologyConstraintException} +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.store.triplestoremessages.VariableResultsRow import org.knora.webapi.messages.util.GroupedProps._ @@ -48,15 +49,20 @@ class ValueUtilV1(private val settings: KnoraSettingsImpl) { /** * Given a [[ValueProps]] containing details of a `knora-base:Value` object, creates a [[ApiValueV1]]. * - * @param valueProps a [[GroupedProps.ValueProps]] resulting from querying the `Value`, in which the keys are RDF predicates, - * and the values are lists of the objects of each predicate. + * @param valueProps a [[GroupedProps.ValueProps]] resulting from querying the `Value`, in which the keys are RDF predicates, + * and the values are lists of the objects of each predicate. + * @param featureFactoryConfig the feature factory configuration. * @return a [[ApiValueV1]] representing the `Value`. */ - def makeValueV1(valueProps: ValueProps, projectShortcode: String, responderManager: ActorRef, userProfile: UserADM)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[ApiValueV1] = { + def makeValueV1(valueProps: ValueProps, + projectShortcode: String, + responderManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[ApiValueV1] = { val valueTypeIri = valueProps.literalData(OntologyConstants.Rdf.Type).literals.head valueTypeIri match { - case OntologyConstants.KnoraBase.TextValue => makeTextValue(valueProps, responderManager, userProfile) + case OntologyConstants.KnoraBase.TextValue => makeTextValue(valueProps, responderManager, featureFactoryConfig, userProfile) case OntologyConstants.KnoraBase.IntValue => makeIntValue(valueProps, responderManager, userProfile) case OntologyConstants.KnoraBase.DecimalValue => makeDecimalValue(valueProps, responderManager, userProfile) case OntologyConstants.KnoraBase.BooleanValue => makeBooleanValue(valueProps, responderManager, userProfile) @@ -556,13 +562,19 @@ class ValueUtilV1(private val settings: KnoraSettingsImpl) { /** * Creates a [[TextValueWithStandoffV1]] from the given string and the standoff nodes. * - * @param utf8str the string representation. - * @param valueProps the properties of the TextValue with standoff. - * @param responderManager the responder manager. - * @param userProfile the client that is making the request. + * @param utf8str the string representation. + * @param valueProps the properties of the TextValue with standoff. + * @param responderManager the responder manager. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the client that is making the request. * @return a [[TextValueWithStandoffV1]]. */ - private def makeTextValueWithStandoff(utf8str: String, language: Option[String] = None, valueProps: ValueProps, responderManager: ActorRef, userProfile: UserADM)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[TextValueWithStandoffV1] = { + private def makeTextValueWithStandoff(utf8str: String, + language: Option[String] = None, + valueProps: ValueProps, + responderManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[TextValueWithStandoffV1] = { // get the IRI of the mapping val mappingIri = valueProps.literalData.getOrElse(OntologyConstants.KnoraBase.ValueHasMapping, throw InconsistentTriplestoreDataException(s"no mapping IRI associated with standoff belonging to textValue ${valueProps.valueIri}")).literals.head @@ -571,7 +583,11 @@ class ValueUtilV1(private val settings: KnoraSettingsImpl) { // get the mapping and the related standoff entities // v2 responder is used here directly, v1 responder would inernally use v2 responder anyway and do unnecessary back and forth conversions - mappingResponse: GetMappingResponseV2 <- (responderManager ? GetMappingRequestV2(mappingIri = mappingIri, requestingUser = userProfile)).mapTo[GetMappingResponseV2] + mappingResponse: GetMappingResponseV2 <- (responderManager ? GetMappingRequestV2( + mappingIri = mappingIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = userProfile + )).mapTo[GetMappingResponseV2] standoffTags: Seq[StandoffTagV2] <- StandoffTagUtilV2.createStandoffTagsV2FromSelectResults( standoffAssertions = valueProps.standoff, @@ -605,10 +621,14 @@ class ValueUtilV1(private val settings: KnoraSettingsImpl) { /** * Converts a [[ValueProps]] into a [[TextValueV1]]. * - * @param valueProps a [[ValueProps]] representing the SPARQL query results to be converted. + * @param valueProps a [[ValueProps]] representing the SPARQL query results to be converted. + * @param featureFactoryConfig the feature factory configuration. * @return a [[TextValueV1]]. */ - private def makeTextValue(valueProps: ValueProps, responderManager: ActorRef, userProfile: UserADM)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[ApiValueV1] = { + private def makeTextValue(valueProps: ValueProps, + responderManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[ApiValueV1] = { val valueHasString: String = valueProps.literalData.get(OntologyConstants.KnoraBase.ValueHasString).map(_.literals.head).getOrElse(throw InconsistentTriplestoreDataException(s"Value ${valueProps.valueIri} has no knora-base:valueHasString")) @@ -616,7 +636,14 @@ class ValueUtilV1(private val settings: KnoraSettingsImpl) { if (valueProps.standoff.nonEmpty) { // there is standoff markup - makeTextValueWithStandoff(valueHasString, valueHasLanguage, valueProps, responderManager, userProfile) + makeTextValueWithStandoff( + utf8str = valueHasString, + language = valueHasLanguage, + valueProps = valueProps, + responderManager = responderManager, + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) } else { // there is no standoff markup diff --git a/webapi/src/main/scala/org/knora/webapi/messages/util/JsonLDUtil.scala b/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/JsonLDUtil.scala similarity index 74% rename from webapi/src/main/scala/org/knora/webapi/messages/util/JsonLDUtil.scala rename to webapi/src/main/scala/org/knora/webapi/messages/util/rdf/JsonLDUtil.scala index 1953e39e5f..aea2091f92 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/util/JsonLDUtil.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/JsonLDUtil.scala @@ -17,10 +17,9 @@ * License along with Knora. If not, see . */ -package org.knora.webapi.messages.util +package org.knora.webapi.messages.util.rdf import java.io.{StringReader, StringWriter} -import java.math.BigInteger import java.util import java.util.UUID @@ -29,30 +28,30 @@ import com.apicatalog.jsonld.document._ import javax.json._ import javax.json.stream.JsonGenerator import org.apache.commons.lang3.builder.HashCodeBuilder -import org.eclipse.rdf4j import org.knora.webapi._ -import org.knora.webapi.exceptions.{BadRequestException, InconsistentTriplestoreDataException, InvalidJsonLDException, InvalidRdfException} +import org.knora.webapi.exceptions._ import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.store.triplestoremessages.StringLiteralV2 import org.knora.webapi.messages.{OntologyConstants, SmartIri, StringFormatter} -import org.knora.webapi.util.JavaUtil._ import scala.collection.JavaConverters._ +import scala.util.control.Exception._ /* -The classes in this file provide a Scala API for formatting and parsing JSON-LD. The implementation -uses the javax.json API and a Java implementation of the JSON-LD API -(currently ). This shields the rest of Knora from the details -of the JSON-LD implementation. These classes also provide Knora-specific JSON-LD functionality to facilitate -reading data from Knora API requests and constructing Knora API responses. +The classes in this file provide a Scala API for formatting and parsing JSON-LD, and for converting +between JSON-LD documents and RDF models. These classes also provide Knora-specific JSON-LD functionality +to facilitate reading data from Knora API requests and constructing Knora API responses. + +The implementation uses the javax.json API and a Java implementation of the JSON-LD API + (currently ). */ /** - * Constant strings used in JSON-LD. + * Constant keywords used in JSON-LD. */ -object JsonLDConstants { +object JsonLDKeywords { val CONTEXT: String = "@context" val ID: String = "@id" @@ -65,7 +64,10 @@ object JsonLDConstants { val VALUE: String = "@value" - val all: Set[String] = Set(CONTEXT, ID, TYPE, GRAPH, LANGUAGE, VALUE) + /** + * The set of JSON-LD keywords that are supported by [[JsonLDUtil]]. + */ + val allSupported: Set[String] = Set(CONTEXT, ID, TYPE, GRAPH, LANGUAGE, VALUE) } /** @@ -154,24 +156,24 @@ case class JsonLDObject(value: Map[String, JsonLDValue]) extends JsonLDValue { } /** - * Recursively adds the contents of this JSON-LD object representing triples (rather than a literal) - * to an [[rdf4j.model.Model]]. + * Recursively adds the contents of a JSON-LD entity to an [[RdfModel]]. * * @param model the model being constructed. * @return the subject of the contents of this JSON-LD object (an IRI or a blank node). */ - def addToModel(model: rdf4j.model.Model) - (implicit stringFormatter: StringFormatter, - valueFactory: rdf4j.model.ValueFactory): rdf4j.model.Resource = { + def addToModel(model: RdfModel) + (implicit stringFormatter: StringFormatter): RdfResource = { + val nodeFactory: RdfNodeFactory = model.getNodeFactory + // If this object has an @id, use it as the subject, otherwise generate a blank node ID. - val rdfSubj: rdf4j.model.Resource = maybeStringWithValidation(JsonLDConstants.ID, stringFormatter.toSmartIriWithErr) match { + val rdfSubj: RdfResource = maybeStringWithValidation(JsonLDKeywords.ID, stringFormatter.toSmartIriWithErr) match { case Some(subjectIri: SmartIri) => // It's an IRI. - valueFactory.createIRI(subjectIri.toString) + nodeFactory.makeIriNode(subjectIri.toString) case None => // Generate a blank node ID. - valueFactory.createBNode() + nodeFactory.makeBlankNode } // Add rdf:type statements to the model. @@ -183,10 +185,10 @@ case class JsonLDObject(value: Map[String, JsonLDValue]) extends JsonLDValue { // Add the IRI predicates and their objects. - val predicates = value.keySet -- JsonLDConstants.all + val predicates = value.keySet -- JsonLDKeywords.allSupported for (pred <- predicates) { - val rdfPred: rdf4j.model.IRI = valueFactory.createIRI(pred) + val rdfPred: IriNode = nodeFactory.makeIriNode(pred) val obj: JsonLDValue = value(pred) addJsonLDValueToModel( @@ -201,111 +203,130 @@ case class JsonLDObject(value: Map[String, JsonLDValue]) extends JsonLDValue { } /** - * Adds `rdf:type` statements to an [[rdf4j.model.Model]] to specify the types of - * a JSON-LD object that represents triples (rather than a literal). + * Adds `rdf:type` statements to an [[RdfModel]] to specify the types of a JSON-LD entity. * * @param model the model being constructed. * @param rdfSubj the subject of this JSON-LD object. */ - private def addRdfTypesToModel(model: rdf4j.model.Model, - rdfSubj: rdf4j.model.Resource) - (implicit stringFormatter: StringFormatter, - valueFactory: rdf4j.model.ValueFactory): Unit = { - value.get(JsonLDConstants.TYPE) match { + private def addRdfTypesToModel(model: RdfModel, + rdfSubj: RdfResource) + (implicit stringFormatter: StringFormatter): Unit = { + val nodeFactory: RdfNodeFactory = model.getNodeFactory + + def addRdfType(typeIri: JsonLDString): Unit = { + model.add( + subj = rdfSubj, + pred = nodeFactory.makeIriNode(OntologyConstants.Rdf.Type), + obj = nodeFactory.makeIriNode(typeIri.value) + ) + } + + def invalidType: Nothing = throw InvalidJsonLDException("The objects of @type must be strings") + + // Does this JSON-LD object have a @type? + value.get(JsonLDKeywords.TYPE) match { case Some(rdfTypes: JsonLDValue) => + // Yes. How many types does it have? rdfTypes match { - case jsonLDString: JsonLDString => - // It has just one @type. - model.add( - rdfSubj, - valueFactory.createIRI(OntologyConstants.Rdf.Type), - valueFactory.createIRI(jsonLDString.value) - ) + case typeIri: JsonLDString => + // Just one. + addRdfType(typeIri) case jsonLDArray: JsonLDArray => - // It has more than one @type. + // More than one. for (elem <- jsonLDArray.value) { + // Is the object of @type a JsonLDString? elem match { - case jsonLDString: JsonLDString => - model.add( - rdfSubj, - valueFactory.createIRI(OntologyConstants.Rdf.Type), - valueFactory.createIRI(jsonLDString.value) - ) - - case _ => throw InvalidJsonLDException("The objects of @type must be strings") + case typeIri: JsonLDString => + // Yes. Add the type to the model. + addRdfType(typeIri) + + case _ => + // No. The JSON-LD is invalid. + invalidType } } - case _ => throw InvalidJsonLDException("The objects of @type must be strings") + case _ => invalidType } - case None => () + case None => + // This JSON-LD object doesn't have a @type. + () } } /** - * Adds the contents of `@graph` to an [[rdf4j.model.Model]]. + * Adds the contents of `@graph` to an [[RdfModel]]. * * @param model the model being constructed. */ - private def addGraphToModel(model: rdf4j.model.Model) - (implicit stringFormatter: StringFormatter, - valueFactory: rdf4j.model.ValueFactory): Unit = { - value.get(JsonLDConstants.GRAPH) match { + private def addGraphToModel(model: RdfModel) + (implicit stringFormatter: StringFormatter): Unit = { + def invalidGraph: Nothing = throw InvalidJsonLDException("The object of @graph must be a JSON-LD array of JSON-LD objects") + + // Does this JSON-LD object have a @graph? + value.get(JsonLDKeywords.GRAPH) match { case Some(graphContents: JsonLDValue) => + // Yes. The object of @graph should be an array. graphContents match { case jsonLDArray: JsonLDArray => + // Add each of the array's elements to the model. for (elem <- jsonLDArray.value) { + // Is the element a JsonLDObject? elem match { case jsonLDObject: JsonLDObject => + // Yes. Add it to the model. jsonLDObject.addToModel(model) case _ => - throw InvalidJsonLDException("The object of @graph must be a JSON-LD array of JSON-LD objects") + // No. The JSON-LD is invalid. + invalidGraph } } - case _ => - throw InvalidJsonLDException("The object of @graph must be a JSON-LD array of JSON-LD objects") + case _ => invalidGraph } - case None => () + case None => + // This JSON-LD object doesn't have a @graph. + () } } /** - * Recursively adds a [[JsonLDValue]] to an [[rdf4j.model.Model]], using the specified subject and predicate. + * Recursively adds a [[JsonLDValue]] to an [[RdfModel]], using the specified subject and predicate. * * @param model the model being constructed. * @param rdfSubj the subject. * @param rdfPred the predicate. * @param jsonLDValue the value to be added. */ - private def addJsonLDValueToModel(model: rdf4j.model.Model, - rdfSubj: rdf4j.model.Resource, - rdfPred: rdf4j.model.IRI, + private def addJsonLDValueToModel(model: RdfModel, + rdfSubj: RdfResource, + rdfPred: IriNode, jsonLDValue: JsonLDValue) - (implicit stringFormatter: StringFormatter, - valueFactory: rdf4j.model.ValueFactory): Unit = { + (implicit stringFormatter: StringFormatter): Unit = { + val nodeFactory: RdfNodeFactory = model.getNodeFactory + // Which type of JSON-LD value is this? jsonLDValue match { case jsonLDObject: JsonLDObject => // It's a JSON-LD object. What does it represent? - val rdfObj: rdf4j.model.Value = if (jsonLDObject.isIri) { + val rdfObj: RdfNode = if (jsonLDObject.isIri) { // An IRI. - valueFactory.createIRI(jsonLDObject.requireString(JsonLDConstants.ID)) + nodeFactory.makeIriNode(jsonLDObject.requireString(JsonLDKeywords.ID)) } else if (jsonLDObject.isDatatypeValue) { // A literal. - valueFactory.createLiteral( - jsonLDObject.requireString(JsonLDConstants.VALUE), - valueFactory.createIRI(jsonLDObject.requireString(JsonLDConstants.TYPE)) + nodeFactory.makeDatatypeLiteral( + value = jsonLDObject.requireString(JsonLDKeywords.VALUE), + datatype = jsonLDObject.requireString(JsonLDKeywords.TYPE) ) } else if (jsonLDObject.isStringWithLang) { // A string literal with a language tag. - valueFactory.createLiteral( - jsonLDObject.requireString(JsonLDConstants.VALUE), - jsonLDObject.requireString(JsonLDConstants.LANGUAGE) + nodeFactory.makeStringWithLanguage( + value = jsonLDObject.requireString(JsonLDKeywords.VALUE), + language = jsonLDObject.requireString(JsonLDKeywords.LANGUAGE) ) } else { // Triples. Recurse to add its contents to the model. @@ -314,9 +335,9 @@ case class JsonLDObject(value: Map[String, JsonLDValue]) extends JsonLDValue { // Add a triple linking the subject to the object. model.add( - rdfSubj, - rdfPred, - rdfObj + subj = rdfSubj, + pred = rdfPred, + obj = rdfObj ) case jsonLDArray: JsonLDArray => @@ -334,9 +355,9 @@ case class JsonLDObject(value: Map[String, JsonLDValue]) extends JsonLDValue { case jsonLDString: JsonLDString => // It's a string literal. model.add( - rdfSubj, - rdfPred, - valueFactory.createLiteral(jsonLDString.value) + subj = rdfSubj, + pred = rdfPred, + obj = nodeFactory.makeStringLiteral(jsonLDString.value) ) case jsonLDBoolean: JsonLDBoolean => @@ -344,16 +365,17 @@ case class JsonLDObject(value: Map[String, JsonLDValue]) extends JsonLDValue { model.add( rdfSubj, rdfPred, - valueFactory.createLiteral(jsonLDBoolean.value) + nodeFactory.makeBooleanLiteral(jsonLDBoolean.value) ) case jsonLDInt: JsonLDInt => - // It's an integer literal. Use a BigInteger rather than an Int, - // so we get xsd:integer rather than xsd:int. model.add( - rdfSubj, - rdfPred, - valueFactory.createLiteral(new BigInteger(jsonLDInt.value.toString, 10)) + subj = rdfSubj, + pred = rdfPred, + obj = nodeFactory.makeDatatypeLiteral( + value = jsonLDInt.value.toString, + datatype = OntologyConstants.Xsd.Integer + ) ) } } @@ -363,21 +385,21 @@ case class JsonLDObject(value: Map[String, JsonLDValue]) extends JsonLDValue { * Returns `true` if this JSON-LD object represents an IRI value. */ def isIri: Boolean = { - value.keySet == Set(JsonLDConstants.ID) + value.keySet == Set(JsonLDKeywords.ID) } /** * Returns `true` if this JSON-LD object represents a string literal with a language tag. */ def isStringWithLang: Boolean = { - value.keySet == Set(JsonLDConstants.VALUE, JsonLDConstants.LANGUAGE) + value.keySet == Set(JsonLDKeywords.VALUE, JsonLDKeywords.LANGUAGE) } /** * Returns `true` if this JSON-LD object represents a datatype value. */ def isDatatypeValue: Boolean = { - value.keySet == Set(JsonLDConstants.TYPE, JsonLDConstants.VALUE) + value.keySet == Set(JsonLDKeywords.TYPE, JsonLDKeywords.VALUE) } /** @@ -390,7 +412,7 @@ case class JsonLDObject(value: Map[String, JsonLDValue]) extends JsonLDValue { */ def toIri[T](validationFun: (String, => Nothing) => T): T = { if (isIri) { - val id: IRI = requireString(JsonLDConstants.ID) + val id: IRI = requireString(JsonLDKeywords.ID) validationFun(id, throw BadRequestException(s"Invalid IRI: $id")) } else { throw BadRequestException(s"This JSON-LD object does not represent an IRI: $this") @@ -408,13 +430,13 @@ case class JsonLDObject(value: Map[String, JsonLDValue]) extends JsonLDValue { */ def toDatatypeValueLiteral[T](expectedDatatype: SmartIri, validationFun: (String, => Nothing) => T): T = { if (isDatatypeValue) { - val datatype: IRI = requireString(JsonLDConstants.TYPE) + val datatype: IRI = requireString(JsonLDKeywords.TYPE) if (datatype != expectedDatatype.toString) { throw BadRequestException(s"Expected datatype value of type <$expectedDatatype>, found <$datatype>") } - val value: String = requireString(JsonLDConstants.VALUE) + val value: String = requireString(JsonLDKeywords.VALUE) validationFun(value, throw BadRequestException(s"Invalid datatype value literal: $value")) } else { throw BadRequestException(s"This JSON-LD object does not represent a datatype value: $this") @@ -673,7 +695,7 @@ case class JsonLDObject(value: Map[String, JsonLDValue]) extends JsonLDValue { def requireIDAsKnoraDataIri: SmartIri = { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance - val iri = requireStringWithValidation(JsonLDConstants.ID, stringFormatter.toSmartIriWithErr) + val iri = requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.toSmartIriWithErr) if (!iri.isKnoraDataIri) { throw BadRequestException(s"Invalid Knora data IRI: $iri") @@ -690,7 +712,7 @@ case class JsonLDObject(value: Map[String, JsonLDValue]) extends JsonLDValue { def maybeIDAsKnoraDataIri: Option[SmartIri] = { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance - val maybeIri: Option[SmartIri] = maybeStringWithValidation(JsonLDConstants.ID, stringFormatter.toSmartIriWithErr) + val maybeIri: Option[SmartIri] = maybeStringWithValidation(JsonLDKeywords.ID, stringFormatter.toSmartIriWithErr) maybeIri.foreach { iri => @@ -720,7 +742,7 @@ case class JsonLDObject(value: Map[String, JsonLDValue]) extends JsonLDValue { def requireTypeAsKnoraApiV2ComplexTypeIri: SmartIri = { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance - val typeIri = requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val typeIri = requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) if (!(typeIri.isKnoraEntityIri && typeIri.getOntologySchema.contains(ApiV2Complex))) { throw BadRequestException(s"Invalid Knora API v2 complex type IRI: $typeIri") @@ -738,7 +760,7 @@ case class JsonLDObject(value: Map[String, JsonLDValue]) extends JsonLDValue { def requireResourcePropertyApiV2ComplexValue: (SmartIri, JsonLDObject) = { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance - val resourceProps: Map[IRI, JsonLDValue] = value - JsonLDConstants.ID - JsonLDConstants.TYPE + val resourceProps: Map[IRI, JsonLDValue] = value - JsonLDKeywords.ID - JsonLDKeywords.TYPE if (resourceProps.isEmpty) { throw BadRequestException("No value submitted") @@ -812,13 +834,13 @@ case class JsonLDArray(value: Seq[JsonLDValue]) extends JsonLDValue { def toObjsWithLang: Seq[StringLiteralV2] = { value.map { case obj: JsonLDObject => - val lang = obj.requireStringWithValidation(JsonLDConstants.LANGUAGE, stringFormatter.toSparqlEncodedString) + val lang = obj.requireStringWithValidation(JsonLDKeywords.LANGUAGE, stringFormatter.toSparqlEncodedString) if (!LanguageCodes.SupportedLanguageCodes(lang)) { throw BadRequestException(s"Unsupported language code: $lang") } - val text = obj.requireStringWithValidation(JsonLDConstants.VALUE, stringFormatter.toSparqlEncodedString) + val text = obj.requireStringWithValidation(JsonLDKeywords.VALUE, stringFormatter.toSparqlEncodedString) StringLiteralV2(text, Some(lang)) case other => throw BadRequestException(s"Expected JSON-LD object: $other") @@ -998,26 +1020,20 @@ case class JsonLDDocument(body: JsonLDObject, context: JsonLDObject = JsonLDObje } /** - * Converts this JSON-LD document to an [[rdf4j.model.Model]], for conversion to - * other RDF formats. + * Converts this JSON-LD document to an [[RdfModel]]. + * + * @param modelFactory an [[RdfModelFactory]]. */ - def toRDF4JModel: rdf4j.model.Model = { + def toRdfModel(modelFactory: RdfModelFactory): RdfModel = { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance - - // Make an RDF4J ValueFactory for constructing RDF4J values. - implicit val valueFactory: rdf4j.model.impl.SimpleValueFactory = rdf4j.model.impl.SimpleValueFactory.getInstance - - // Make an empty RDF4J model. - val model = new rdf4j.model.impl.LinkedHashModel() + val model: RdfModel = modelFactory.makeEmptyModel // Add the prefixes and namespaces from the JSON-LD context to the model. for ((prefix: String, namespaceValue: JsonLDValue) <- context.value) { - val namespace: rdf4j.model.Namespace = namespaceValue match { - case jsonLDString: JsonLDString => new rdf4j.model.impl.SimpleNamespace(prefix, jsonLDString.value) + namespaceValue match { + case jsonLDString: JsonLDString => model.setNamespace(prefix, jsonLDString.value) case _ => throw InvalidJsonLDException("The keys and values of @context must be strings") } - - model.setNamespace(namespace) } // Recursively add the JSON-LD document body to the model. @@ -1027,7 +1043,7 @@ case class JsonLDDocument(body: JsonLDObject, context: JsonLDObject = JsonLDObje } /** - * Utility functions for working with JSON-LD. + * A tool for working with JSON-LD. */ object JsonLDUtil { @@ -1098,7 +1114,7 @@ object JsonLDUtil { * @return the JSON-LD representation of the IRI as an object value. */ def iriToJsonLDObject(iri: IRI): JsonLDObject = { - JsonLDObject(Map(JsonLDConstants.ID -> JsonLDString(iri))) + JsonLDObject(Map(JsonLDKeywords.ID -> JsonLDString(iri))) } /** @@ -1110,8 +1126,8 @@ object JsonLDUtil { */ def objectWithLangToJsonLDObject(obj: String, lang: String): JsonLDObject = { JsonLDObject(Map( - JsonLDConstants.VALUE -> JsonLDString(obj), - JsonLDConstants.LANGUAGE -> JsonLDString(lang) + JsonLDKeywords.VALUE -> JsonLDString(obj), + JsonLDKeywords.LANGUAGE -> JsonLDString(lang) )) } @@ -1132,8 +1148,8 @@ object JsonLDUtil { } JsonLDObject(Map( - JsonLDConstants.VALUE -> JsonLDString(strValue), - JsonLDConstants.TYPE -> JsonLDString(datatype.toString) + JsonLDKeywords.VALUE -> JsonLDString(strValue), + JsonLDKeywords.TYPE -> JsonLDString(datatype.toString) )) } @@ -1202,7 +1218,12 @@ object JsonLDUtil { case jsonObject: JsonObject => val content: Map[IRI, JsonLDValue] = jsonObject.keySet.asScala.toSet.map { - key: IRI => key -> jsonValueToJsonLDValue(jsonObject.get(key)) + key: IRI => + if (key.startsWith("@") && !JsonLDKeywords.allSupported.contains(key)) { + throw BadRequestException(s"JSON-LD keyword $key is not supported") + } + + key -> jsonValueToJsonLDValue(jsonObject.get(key)) }.toMap JsonLDObject(content) @@ -1225,7 +1246,7 @@ object JsonLDUtil { } /** - * Converts an [[rdf4j.model.Model]] to a [[JsonLDDocument]]. There can be more than one valid + * Converts an [[RdfModel]] to a [[JsonLDDocument]]. There can be more than one valid * way to nest objects in the converted JSON-LD. This implementation takes the following * approach: * @@ -1236,67 +1257,67 @@ object JsonLDUtil { * * An error is returned if the same blank node is used more than once. * - * @param model the model to be read. + * @param model the [[RdfModel]] to be read. * @return the corresponding [[JsonLDDocument]]. */ - def fromRDF4JModel(model: rdf4j.model.Model): JsonLDDocument = { + def fromRdfModel(model: RdfModel): JsonLDDocument = { + if (model.getContexts.nonEmpty) { + throw BadRequestException("Named graphs in JSON-LD are not supported") + } + implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance // Make a JSON-LD context from the model's namespaces. - val namespaces: Set[rdf4j.model.Namespace] = model.getNamespaces.asScala.toSet - - val contextMap: Map[IRI, JsonLDString] = namespaces.map { - namespace: rdf4j.model.Namespace => - namespace.getPrefix -> JsonLDString(namespace.getName) - }.toMap + val contextMap: Map[IRI, JsonLDString] = model.getNamespaces.map { + case (prefix, namespace) => prefix -> JsonLDString(namespace) + } - val context = JsonLDObject(contextMap) + val context: JsonLDObject = JsonLDObject(contextMap) // Is the model empty? val body: JsonLDObject = if (model.isEmpty) { // Yes. Just make an empty JSON-LD object. JsonLDObject(Map.empty) } else { - // No. Copy the model, so we can modify our copy. - val modelCopy = new rdf4j.model.impl.LinkedHashModel(model) - // Get the set of subjects in the model. - val subjects: Set[rdf4j.model.Resource] = modelCopy.subjects.asScala.toSet + val subjects: Set[RdfResource] = model.getSubjects + + // Make a Set to collect the subjects that have already been processed. + val processedSubjects: collection.mutable.Set[RdfResource] = collection.mutable.Set.empty - // Make an empty collection of top-level JSON-LD objects. This is a mutable collection - // so JSON-LD objects can be added to it and later removed when they are inlined. - val topLevelObjects: collection.mutable.Map[rdf4j.model.Resource, JsonLDObject] = collection.mutable.Map.empty + // Make a Map to collect the top-level entities. We first assume that an entity is at the top level, + // and add it to this collection. Later, it can be inlined (nested inside another entity) and removed + // from this collection. + val topLevelEntities: collection.mutable.Map[RdfResource, JsonLDObject] = collection.mutable.Map.empty // Make a JSON-LD object for each entity, inlining them as we go along. - for (subj: rdf4j.model.Resource <- subjects) { - // Get the statements about the entity. - val statements: Set[rdf4j.model.Statement] = modelCopy.filter(subj, null, null).asScala.toSet - - // Have we already processed this entity? - if (statements.isEmpty) { - // Yes. Skip it. - () - } else { - // No. Make a JSON-LD object representing the entity and any nested entities. - val jsonLDObject = entityToJsonLDObject( + for (subj: RdfResource <- subjects) { + // Have we already processed this subject? + if (!processedSubjects.contains(subj)) { + // No. Get the statements about it. + val statements: Set[Statement] = model.find(Some(subj), None, None) + + // Make a JsonLDObject representing the entity and any nested entities. + val jsonLDObject: JsonLDObject = entityToJsonLDObject( subj = subj, statements = statements, - model = modelCopy, - topLevelObjects = topLevelObjects + model = model, + topLevelEntities = topLevelEntities, + processedSubjects = processedSubjects ) - // Add it to the collection of top-level objects. - topLevelObjects += (subj -> jsonLDObject) + // Add it to the collection of top-level entities. + topLevelEntities += (subj -> jsonLDObject) } } - // Is there more than one top-level object? - if (topLevelObjects.size > 1) { - // Yes. Make a @graph. - JsonLDObject(Map(JsonLDConstants.GRAPH -> JsonLDArray(topLevelObjects.values.toVector))) + // Is there just one top-level entity? + if (topLevelEntities.size == 1) { + // Yes. Use it as the body of the document. + topLevelEntities.values.head } else { - // No. Use the single top-level object as the body of the document. - topLevelObjects.values.head + // No. Make a @graph. + JsonLDObject(Map(JsonLDKeywords.GRAPH -> JsonLDArray(topLevelEntities.values.toVector))) } } @@ -1304,85 +1325,81 @@ object JsonLDUtil { } /** - * Converts an RDF entity to a [[JsonLDObject]]. + * Converts an RDF entity to a [[JsonLDObject]] representing the statements about the entity. * - * @param subj the subject of the entity. - * @param statements the statements representing the entity. - * @param model the RDF4J model that is being read. - * @param topLevelObjects the top-level JSON-LD objects that have been constructed so far. + * @param subj the subject of the entity. + * @param statements the statements representing the entity. + * @param model the [[RdfModel]] that is being read. + * @param topLevelEntities the top-level entities that have been constructed so far. + * @param processedSubjects the subjects that have already been processed. * @return the JSON-LD object that was constructed. */ - private def entityToJsonLDObject(subj: rdf4j.model.Resource, - statements: Set[rdf4j.model.Statement], - model: rdf4j.model.Model, - topLevelObjects: collection.mutable.Map[rdf4j.model.Resource, JsonLDObject]) + private def entityToJsonLDObject(subj: RdfResource, + statements: Set[Statement], + model: RdfModel, + topLevelEntities: collection.mutable.Map[RdfResource, JsonLDObject], + processedSubjects: collection.mutable.Set[RdfResource]) (implicit stringFormatter: StringFormatter): JsonLDObject = { - // Remove the statements from the model. - model.remove(subj, null, null) + // Mark the subject as processed. + processedSubjects += subj // Does this entity have an IRI, or is it a blank node? val idContent: Map[String, JsonLDValue] = subj match { - case iri: rdf4j.model.IRI => + case iriNode: IriNode => // It has an IRI. Use it for the @id. - Map(JsonLDConstants.ID -> JsonLDString(iri.stringValue)) + Map(JsonLDKeywords.ID -> JsonLDString(iriNode.iri)) - case _ => + case _: BlankNode => // It's a blank node. Don't make an @id. Map.empty[String, JsonLDValue] } // Group the statements by predicate. - val groupedByPred: Map[rdf4j.model.IRI, Set[rdf4j.model.Statement]] = statements.groupBy(_.getPredicate) + val groupedByPred: Map[IriNode, Set[Statement]] = statements.groupBy(_.pred) // Make JSON-LD content representing the predicates and their objects. val predsAndObjs: Map[IRI, JsonLDValue] = groupedByPred.keySet.map { - pred: rdf4j.model.IRI => - val predStatements: Set[rdf4j.model.Statement] = groupedByPred(pred) - val predIri: IRI = pred.stringValue + pred: IriNode => + val predStatements: Set[Statement] = groupedByPred(pred) + val predIri: IRI = pred.iri // Is the predicate rdf:type? - if (predIri == OntologyConstants.Rdf.Type) { - // Yes. Add @type. Is there just one rdf:type? - val rdfType: JsonLDValue = if (predStatements.size == 1) { - // Yes. - JsonLDString(predStatements.head.getObject.stringValue) - } else { - // No. Make a JSON-LD array. - JsonLDArray( - predStatements.map { - statement => JsonLDString(statement.getObject.stringValue) - }.toVector - ) - - } - - JsonLDConstants.TYPE -> rdfType + val (jsonLDKey: String, jsonLDObjs: Vector[JsonLDValue]) = if (predIri == OntologyConstants.Rdf.Type) { + // Yes. Add @type. + val typeList: Vector[JsonLDString] = predStatements.map { + statement => + statement.obj match { + case iriNode: IriNode => JsonLDString(iriNode.iri) + case other => throw InvalidRdfException(s"Unexpected object of rdf:type: $other") + } + }.toVector + + JsonLDKeywords.TYPE -> typeList } else { // The predicate is not rdf:type. Convert its objects. - val objs: Seq[JsonLDValue] = predStatements.map(_.getObject).map { - case resource: rdf4j.model.Resource => - // The object is an entity. Recurse to get it. - rdf4jResourceToJsonLDValue( + val objs: Vector[JsonLDValue] = predStatements.map(_.obj).map { + case resource: RdfResource => + // The object is an entity. Recurse to get it and inline it here. + referencedRdfResourceToJsonLDValue( resource = resource, model = model, - topLevelObjects = topLevelObjects + topLevelEntities = topLevelEntities, + processedSubjects = processedSubjects ) - case literal: rdf4j.model.Literal => rdf4jLiteralToJsonLDValue(literal) - - case other => throw InvalidRdfException(s"Unexpected RDF value: ${other.stringValue}") + case literal: RdfLiteral => rdfLiteralToJsonLDValue(literal) }.toVector - // Does the predicate have just one object? - val jsonLDValue = if (objs.size == 1) { - // Yes. - objs.head - } else { - // No. Make a JSON-LD array. - JsonLDArray(objs) - } + predIri -> objs + } - predIri -> jsonLDValue + // Does the predicate have just one object? + if (jsonLDObjs.size == 1) { + // Yes. + jsonLDKey -> jsonLDObjs.head + } else { + // No. Make a JSON-LD array. + jsonLDKey -> JsonLDArray(jsonLDObjs) } }.toMap @@ -1390,98 +1407,97 @@ object JsonLDUtil { } /** - * Converts an [[rdf4j.model.Literal]] to a [[JsonLDValue]]. + * Converts an [[RdfLiteral]] to a [[JsonLDValue]]. * * @param literal the literal to be converted. * @return the corresponding JSON-LD value. */ - private def rdf4jLiteralToJsonLDValue(literal: rdf4j.model.Literal) - (implicit stringFormatter: StringFormatter): JsonLDValue = { - // Is this a string literal with a language tag? - literal.getLanguage.toOption match { - case Some(language) => - // Yes. - objectWithLangToJsonLDObject(obj = literal.getLabel, lang = language) + private def rdfLiteralToJsonLDValue(literal: RdfLiteral) + (implicit stringFormatter: StringFormatter): JsonLDValue = { + literal match { + case stringWithLanguage: StringWithLanguage => + objectWithLangToJsonLDObject(obj = stringWithLanguage.value, lang = stringWithLanguage.language) - case None => - // No. Is there a native JSON-LD type for it? - val datatypeIri: IRI = literal.getDatatype.stringValue + case datatypeLiteral: DatatypeLiteral => + // Is there a native JSON-LD type for this literal? + val datatypeIri: IRI = datatypeLiteral.datatype + val datatypeValue: String = datatypeLiteral.value datatypeIri match { - case OntologyConstants.Xsd.String => - // String. - JsonLDString(literal.stringValue) + case OntologyConstants.Xsd.String => JsonLDString(datatypeValue) case OntologyConstants.Xsd.Int | OntologyConstants.Xsd.Integer => - // Integer. - JsonLDInt(literal.intValue) + JsonLDInt(allCatch.opt(datatypeValue.toInt).getOrElse(throw InvalidRdfException(s"Invalid integer: $datatypeValue"))) case OntologyConstants.Xsd.Boolean => - // Boolean. - JsonLDBoolean(literal.booleanValue) + JsonLDBoolean(allCatch.opt(datatypeValue.toBoolean).getOrElse(throw InvalidRdfException(s"Invalid boolean: $datatypeValue"))) case _ => // There's no native JSON-LD type for this literal. // Make a JSON-LD object representing a datatype value. - datatypeValueToJsonLDObject(value = literal.getLabel, datatype = datatypeIri.toSmartIri) + datatypeValueToJsonLDObject(value = datatypeValue, datatype = datatypeIri.toSmartIri) } } } /** - * Converts an [[rdf4j.model.Resource]] to a [[JsonLDValue]]. + * Given an [[RdfResource]] that is referred to by another entity, make a [[JsonLDValue]] to + * represent the referenced resource. This will be either a complete entity for nesting, or just + * the referenced resource's IRI. * - * @param resource the resource to be converted. - * @param model the RDF4J model that is being read. - * @param topLevelObjects the top-level JSON-LD objects that have been constructed so far. + * @param resource the resource to be converted. + * @param model the [[RdfModel]] that is being read. + * @param topLevelEntities the top-level entities that have been constructed so far. + * @param processedSubjects the subjects that have already been processed. * @return a JSON-LD value representing the resource. */ - private def rdf4jResourceToJsonLDValue(resource: rdf4j.model.Resource, - model: rdf4j.model.Model, - topLevelObjects: collection.mutable.Map[rdf4j.model.Resource, JsonLDObject]) - (implicit stringFormatter: StringFormatter): JsonLDValue = { - // Have we already made a top-level JSON-LD object for this entity? - topLevelObjects.get(resource) match { + private def referencedRdfResourceToJsonLDValue(resource: RdfResource, + model: RdfModel, + topLevelEntities: collection.mutable.Map[RdfResource, JsonLDObject], + processedSubjects: collection.mutable.Set[RdfResource]) + (implicit stringFormatter: StringFormatter): JsonLDValue = { + // How we deal with circular references: the referenced resource is not yet in topLevelEntities, but it + // is already marked as processed. Therefore we will return its IRI rather than inlining it. + + // Is this entity already in topLevelEntities? + topLevelEntities.get(resource) match { case Some(jsonLDObject) => - // Yes. Remove it from the top level and inline it here. - topLevelObjects -= resource + // Yes. Remove it from the top level so it can be inlined. + topLevelEntities -= resource jsonLDObject case None => // No. Is it a Knora ontology entity? resource match { - case iri: rdf4j.model.IRI if iri.stringValue.toSmartIri.isKnoraDefinitionIri => + case iriNode: IriNode if iriNode.iri.toSmartIri.isKnoraDefinitionIri => // Yes. Just use its IRI, because we don't inline ontology entities. - iriToJsonLDObject(iri.stringValue) + iriToJsonLDObject(iriNode.iri) case _ => - // It's not a Knora ontology entity. Is it still in the model? - if (model.contains(resource, null, null)) { - // Yes. Recurse to get it, and inline it here. - - val resourceStatements: Set[rdf4j.model.Statement] = model.filter(resource, null, null).asScala.toSet + // It's not a Knora ontology entity. See if it's in the model. + val resourceStatements: Set[Statement] = model.find(Some(resource), None, None) + // Is it in the model and not yet marked as processed? + if (resourceStatements.nonEmpty && !processedSubjects.contains(resource)) { + // Yes. Recurse to get it so it can be inlined. entityToJsonLDObject( subj = resource, statements = resourceStatements, model = model, - topLevelObjects = topLevelObjects + topLevelEntities = topLevelEntities, + processedSubjects = processedSubjects ) } else { - // It's not in the model. Maybe it was already inlined somewhere else, - // or maybe it wasn't provided in the model. Does it have an IRI? + // No. Maybe it was already inlined, or maybe it wasn't provided + // in the model. Does it have an IRI? resource match { - case iri: rdf4j.model.IRI => + case iriNode: IriNode => // Yes. Just use that. - iriToJsonLDObject(iri.stringValue) + iriToJsonLDObject(iriNode.iri) - case blankNode: rdf4j.model.BNode => + case blankNode: BlankNode => // No, it's a blank node. This shouldn't happen. - throw InvalidRdfException(s"Blank node ${blankNode.stringValue} was not found or is referenced in more than one place") - - case _ => - // Other resource types aren't supported. - throw InvalidRdfException(s"Unexpected RDF resource: ${resource.stringValue}") + throw InvalidRdfException(s"Blank node ${blankNode.id} was not found or is referenced in more than one place") } } } diff --git a/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/RdfFeatureFactory.scala b/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/RdfFeatureFactory.scala new file mode 100644 index 0000000000..b8359043fb --- /dev/null +++ b/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/RdfFeatureFactory.scala @@ -0,0 +1,86 @@ +/* + * Copyright © 2015-2019 the contributors (see Contributors.md). + * + * This file is part of Knora. + * + * Knora is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Knora is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with Knora. If not, see . + */ + +package org.knora.webapi.messages.util.rdf + +import org.knora.webapi.feature.{FeatureFactory, FeatureFactoryConfig} +import org.knora.webapi.messages.util.rdf.jenaimpl.{JenaFormatUtil, JenaModelFactory, JenaNodeFactory} +import org.knora.webapi.messages.util.rdf.rdf4jimpl.{RDF4JFormatUtil, RDF4JModelFactory, RDF4JNodeFactory} + +/** + * A feature factory that creates RDF processing tools. + */ +object RdfFeatureFactory extends FeatureFactory { + /** + * The name of the feature toggle that enables the Jena implementation of the RDF façade. + */ + private val JENA_TOGGLE_NAME = "jena-rdf-library" + + // Jena factory singletons. + private val jenaNodeFactory = new JenaNodeFactory + private val jenaModelFactory = new JenaModelFactory(jenaNodeFactory) + private val jenaFormatUtil = new JenaFormatUtil(jenaModelFactory) + + // RDF4J factory singletons. + private val rdf4jNodeFactory = new RDF4JNodeFactory + private val rdf4jModelFactory = new RDF4JModelFactory(rdf4jNodeFactory) + private val rdf4jFormatUtil = new RDF4JFormatUtil(modelFactory = rdf4jModelFactory, nodeFactory = rdf4jNodeFactory) + + /** + * Returns an [[RdfModelFactory]]. + * + * @param featureFactoryConfig the feature factory configuration. + * @return an [[RdfModelFactory]]. + */ + def getRdfModelFactory(featureFactoryConfig: FeatureFactoryConfig): RdfModelFactory = { + if (featureFactoryConfig.getToggle(JENA_TOGGLE_NAME).isEnabled) { + jenaModelFactory + } else { + rdf4jModelFactory + } + } + + /** + * Returns an [[RdfNodeFactory]]. + * + * @param featureFactoryConfig the feature factory configuration. + * @return an [[RdfNodeFactory]]. + */ + def getRdfNodeFactory(featureFactoryConfig: FeatureFactoryConfig): RdfNodeFactory = { + if (featureFactoryConfig.getToggle(JENA_TOGGLE_NAME).isEnabled) { + jenaNodeFactory + } else { + rdf4jNodeFactory + } + } + + /** + * Returns an [[RdfFormatUtil]]. + * + * @param featureFactoryConfig the feature factory configuration. + * @return an [[RdfFormatUtil]]. + */ + def getRdfFormatUtil(featureFactoryConfig: FeatureFactoryConfig): RdfFormatUtil = { + if (featureFactoryConfig.getToggle(JENA_TOGGLE_NAME).isEnabled) { + jenaFormatUtil + } else { + rdf4jFormatUtil + } + } +} diff --git a/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/RdfFormatUtil.scala b/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/RdfFormatUtil.scala new file mode 100644 index 0000000000..eec405341f --- /dev/null +++ b/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/RdfFormatUtil.scala @@ -0,0 +1,211 @@ +/* + * Copyright © 2015-2019 the contributors (see Contributors.md). + * + * This file is part of Knora. + * + * Knora is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Knora is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with Knora. If not, see . + */ + +package org.knora.webapi.messages.util.rdf + +import akka.http.scaladsl.model.MediaType +import org.knora.webapi.RdfMediaTypes +import org.knora.webapi.exceptions.{BadRequestException, InvalidRdfException} + +/** + * A trait for supported RDF formats. + */ +sealed trait RdfFormat { + /** + * `true` if this format supports named graphs. + */ + val supportsNamedGraphs: Boolean + + /** + * The [[MediaType]] that represents this format. + */ + val toMediaType: MediaType +} + +/** + * A trait for formats other than JSON-LD. + */ +sealed trait NonJsonLD extends RdfFormat + +object RdfFormat { + /** + * Converts a [[MediaType]] to an [[RdfFormat]]. + * + * @param mediaType a [[MediaType]]. + * @return the corresponding [[RdfFormat]]. + */ + def fromMediaType(mediaType: MediaType): RdfFormat = { + mediaType match { + case RdfMediaTypes.`application/ld+json` => JsonLD + case RdfMediaTypes.`text/turtle` => Turtle + case RdfMediaTypes.`application/trig` => TriG + case RdfMediaTypes.`application/rdf+xml` => RdfXml + case other => throw InvalidRdfException(s"Unsupported RDF media type: $other") + } + } +} + +/** + * Represents JSON-LD format. + */ +case object JsonLD extends RdfFormat { + override def toString: String = "JSON-LD" + + override val toMediaType: MediaType = RdfMediaTypes.`application/ld+json` + + // We don't support named graphs in JSON-LD. + override val supportsNamedGraphs: Boolean = false +} + +/** + * Represents Turtle format. + */ +case object Turtle extends NonJsonLD { + override def toString: String = "Turtle" + + override val toMediaType: MediaType = RdfMediaTypes.`text/turtle` + + override val supportsNamedGraphs: Boolean = false +} + +/** + * Represents TriG format. + */ +case object TriG extends NonJsonLD { + override def toString: String = "TriG" + + override val toMediaType: MediaType = RdfMediaTypes.`application/trig` + + override val supportsNamedGraphs: Boolean = true +} + +/** + * Represents RDF-XML format. + */ +case object RdfXml extends NonJsonLD { + override def toString: String = "RDF/XML" + + override val toMediaType: MediaType = RdfMediaTypes.`application/rdf+xml` + + override val supportsNamedGraphs: Boolean = false +} + +/** + * Formats and parses RDF. + */ +trait RdfFormatUtil { + /** + * Returns an [[RdfModelFactory]] with the same underlying implementation as this [[RdfFormatUtil]]. + */ + def getRdfModelFactory: RdfModelFactory + + /** + * Parses an RDF string to an [[RdfModel]]. + * + * @param rdfStr the RDF string to be parsed. + * @param rdfFormat the format of the string. + * @return the corresponding [[RdfModel]]. + */ + def parseToRdfModel(rdfStr: String, rdfFormat: RdfFormat): RdfModel = { + rdfFormat match { + case JsonLD => + // Use JsonLDUtil to parse JSON-LD, and to convert the + // resulting JsonLDDocument to an RdfModel. + JsonLDUtil.parseJsonLD(rdfStr).toRdfModel(getRdfModelFactory) + + case nonJsonLD: NonJsonLD => + // Use an implementation-specific function to parse other formats. + parseNonJsonLDToRdfModel(rdfStr = rdfStr, rdfFormat = nonJsonLD) + } + } + + /** + * Parses an RDF string to a [[JsonLDDocument]]. + * + * @param rdfStr the RDF string to be parsed. + * @param rdfFormat the format of the string. + * @return the corresponding [[JsonLDDocument]]. + */ + def parseToJsonLDDocument(rdfStr: String, rdfFormat: RdfFormat): JsonLDDocument = { + rdfFormat match { + case JsonLD => + // Use JsonLDUtil to parse JSON-LD. + JsonLDUtil.parseJsonLD(rdfStr) + + case nonJsonLD: NonJsonLD => + // Use an implementation-specific function to parse other formats to an RdfModel. + // Use JsonLDUtil to convert the resulting model to a JsonLDDocument. + JsonLDUtil.fromRdfModel(parseNonJsonLDToRdfModel(rdfStr = rdfStr, rdfFormat = nonJsonLD)) + } + } + + /** + * Converts an [[RdfModel]] to a string. + * + * @param rdfModel the model to be formatted. + * @param rdfFormat the format to be used. + * @param prettyPrint if `true`, the output should be pretty-printed. + * @return a string representation of the RDF model. + */ + def format(rdfModel: RdfModel, rdfFormat: RdfFormat, prettyPrint: Boolean = true): String = { + rdfFormat match { + case JsonLD => + // Use JsonLDUtil to convert to JSON-LD. + val jsonLDDocument: JsonLDDocument = JsonLDUtil.fromRdfModel(rdfModel) + + if (prettyPrint) { + jsonLDDocument.toPrettyString + } else { + jsonLDDocument.toCompactString + } + + case nonJsonLD: NonJsonLD => + // Some formats can't represent named graphs. + if (rdfModel.getContexts.nonEmpty && !nonJsonLD.supportsNamedGraphs) { + throw BadRequestException(s"Named graphs are not supported in $rdfFormat") + } + + // Use an implementation-specific function to convert to other formats. + formatNonJsonLD( + rdfModel = rdfModel, + rdfFormat = nonJsonLD, + prettyPrint = prettyPrint + ) + } + } + + /** + * Parses RDF in a format other than JSON-LD to an [[RdfModel]]. + * + * @param rdfStr the RDF string to be parsed. + * @param rdfFormat the format of the string. + * @return the corresponding [[RdfModel]]. + */ + protected def parseNonJsonLDToRdfModel(rdfStr: String, rdfFormat: NonJsonLD): RdfModel + + /** + * Converts an [[RdfModel]] to a string in a format other than JSON-LD. + * + * @param rdfModel the model to be formatted. + * @param rdfFormat the format to be used. + * @param prettyPrint if `true`, the output should be pretty-printed. + * @return a string representation of the RDF model. + */ + protected def formatNonJsonLD(rdfModel: RdfModel, rdfFormat: NonJsonLD, prettyPrint: Boolean): String +} diff --git a/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/RdfModel.scala b/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/RdfModel.scala new file mode 100644 index 0000000000..abd80deced --- /dev/null +++ b/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/RdfModel.scala @@ -0,0 +1,335 @@ +/* + * Copyright © 2015-2019 the contributors (see Contributors.md). + * + * This file is part of Knora. + * + * Knora is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Knora is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with Knora. If not, see . + */ + +package org.knora.webapi.messages.util.rdf + +import org.knora.webapi.IRI +import org.knora.webapi.messages.OntologyConstants + +import scala.util.control.Exception.allCatch + +/** + * Represents an RDF subject, predicate, or object. + */ +trait RdfNode { + /** + * The lexical representation of this node. + */ + def stringValue: String +} + +/** + * Represents an RDF node that can be used as a subject. + */ +trait RdfResource extends RdfNode + +/** + * Represents a blank node. + */ +trait BlankNode extends RdfResource { + def id: String +} + +/** + * Represents an IRI used as an RDF resource. + */ +trait IriNode extends RdfResource { + def iri: IRI +} + +/** + * Represents an RDF literal. + */ +trait RdfLiteral extends RdfNode + +/** + * Represents a literal value with a datatype. + */ +trait DatatypeLiteral extends RdfLiteral { + /** + * The lexical value of this literal. + */ + def value: String + + /** + * The datatype IRI of this literal. + */ + def datatype: IRI + + /** + * The boolean value of this literal. + * + * @param errorFun a function that throws an exception. It will + * be called if this literal is not a boolean. + */ + def booleanValue(errorFun: => Nothing): Boolean = { + if (datatype == OntologyConstants.Xsd.Boolean) { + allCatch.opt(value.toBoolean).getOrElse(errorFun) + } else { + errorFun + } + } + + /** + * The integer value of this literal. + * + * @param errorFun a function that throws an exception. It will + * be called if this literal is not an integer. + */ + def integerValue(errorFun: => Nothing): BigInt = { + if (OntologyConstants.Xsd.integerTypes.contains(datatype)) { + allCatch.opt(BigInt(value)).getOrElse(errorFun) + } else { + errorFun + } + } + + /** + * The decimal value of this literal. + * + * @param errorFun a function that throws an exception. It will + * be called if this literal is not a decimal. + */ + def decimalValue(errorFun: => Nothing): BigDecimal = { + if (datatype == OntologyConstants.Xsd.Decimal) { + allCatch.opt(BigDecimal(value)).getOrElse(errorFun) + } else { + errorFun + } + } +} + +/** + * Represents a string value with a language tag. + */ +trait StringWithLanguage extends RdfLiteral { + def value: String + + def language: String +} + +/** + * Represents an RDF statement. + */ +trait Statement { + def subj: RdfResource + + def pred: IriNode + + def obj: RdfNode + + def context: Option[IRI] +} + +/** + * Represents an RDF model consisting of a default graph and/or one or more named graphs. + */ +trait RdfModel { + /** + * Returns an [[RdfNodeFactory]] that can be used create nodes for use with this model. + */ + def getNodeFactory: RdfNodeFactory + + /** + * Adds a statement to the model. + * + * @param statement the statement to be added. + */ + def addStatement(statement: Statement): Unit + + /** + * Adds one or more statements to the model. + * + * @param statements the statements to be added. + */ + def addStatements(statements: Set[Statement]): Unit = { + for (statement <- statements) { + addStatement(statement) + } + } + + /** + * Constructs a statement and adds it to the model. + * + * @param subj the subject. + * @param pred the predicate. + * @param obj the object. + * @param context the IRI of a named graph, or `None` to use the default graph. + */ + def add(subj: RdfResource, pred: IriNode, obj: RdfNode, context: Option[IRI] = None): Unit + + /** + * Removes statements that match a pattern. + * + * @param subj the subject, or `None` to match any subject. + * @param pred the predicate, or `None` to match any predicate. + * @param obj the object, or `None` to match any object. + * @param context the IRI of a named graph, or `None` to match any graph. + */ + def remove(subj: Option[RdfResource], pred: Option[IriNode], obj: Option[RdfNode], context: Option[IRI] = None): Unit + + /** + * Removes a statement from the model. + */ + def removeStatement(statement: Statement): Unit + + /** + * Returns the set of all statements in the model. + */ + def getStatements: Set[Statement] + + /** + * Returns statements that match a pattern. + * + * @param subj the subject, or `None` to match any subject. + * @param pred the predicate, or `None` to match any predicate. + * @param obj the object, or `None` to match any object. + * @param context the IRI of a named graph, or `None` to match any graph. + * @return the statements matching the pattern. + */ + def find(subj: Option[RdfResource], pred: Option[IriNode], obj: Option[RdfNode], context: Option[IRI] = None): Set[Statement] + + /** + * Returns a set of all the subjects in the model. + */ + def getSubjects: Set[RdfResource] + + /** + * Adds a namespace declaration to the model. + * + * @param prefix the namespace prefix. + * @param namespace the namespace. + */ + def setNamespace(prefix: String, namespace: IRI): Unit + + /** + * Returns the namespace declarations in the model. + * + * @return a map of prefixes to namespaces. + */ + def getNamespaces: Map[String, IRI] + + /** + * Returns `true` if this model is empty. + */ + def isEmpty: Boolean + + /** + * Returns `true` if this model is isomorphic with another RDF model. + * + * @param otherRdfModel another [[RdfModel]]. + */ + def isIsomorphicWith(otherRdfModel: RdfModel): Boolean + + /** + * Returns the IRIs of the named graphs in the model. + */ + def getContexts: Set[IRI] + + override def hashCode(): Int = super.hashCode() + + override def equals(obj: Any): Boolean = { + obj match { + case thatRdfModel: RdfModel => isIsomorphicWith(thatRdfModel) + case _ => false + } + } +} + +/** + * Represents a factory that can create RDF nodes and statements. + */ +trait RdfNodeFactory { + /** + * Constructs a blank node with a generated ID. + * + * @return a [[BlankNode]]. + */ + def makeBlankNode: BlankNode + + /** + * Constructs a blank node with the specified ID. + * + * @param id the blank node ID. + * @return a [[BlankNode]]. + */ + def makeBlankNodeWithID(id: String): BlankNode + + /** + * Constructs an IRI node. + * + * @param iri the IRI. + * @return an [[IriNode]]. + */ + def makeIriNode(iri: IRI): IriNode + + /** + * Constructs a literal value with a datatype. + * + * @param value the lexical value of the literal. + * @param datatype the datatype IRI. + * @return a [[DatatypeLiteral]]. + */ + def makeDatatypeLiteral(value: String, datatype: IRI): DatatypeLiteral + + /** + * Creates an `xsd:string`. + * + * @param value the string value. + * @return a [[DatatypeLiteral]]. + */ + def makeStringLiteral(value: String): DatatypeLiteral = { + makeDatatypeLiteral(value = value, datatype = OntologyConstants.Xsd.String) + } + + /** + * Constructs a string with a language tag. + * + * @param value the string. + * @param language the language tag. + */ + def makeStringWithLanguage(value: String, language: String): StringWithLanguage + + /** + * Constructs an `xsd:boolean`. + * + * @param value the boolean value. + * @return a [[DatatypeLiteral]]. + */ + def makeBooleanLiteral(value: Boolean): DatatypeLiteral = { + makeDatatypeLiteral(value = value.toString, datatype = OntologyConstants.Xsd.Boolean) + } + + /** + * Constructs a statement. + * + * @param subj the subject. + * @param pred the predicate. + * @param obj the object. + * @param context the IRI of the named graph, or `None` to use the default graph. + */ + def makeStatement(subj: RdfResource, pred: IriNode, obj: RdfNode, context: Option[IRI] = None): Statement +} + +/** + * A factory that creates [[RdfModel]] instances. + */ +trait RdfModelFactory { + def makeEmptyModel: RdfModel +} diff --git a/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/jenaimpl/JenaFormatUtil.scala b/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/jenaimpl/JenaFormatUtil.scala new file mode 100644 index 0000000000..5a99fd34c0 --- /dev/null +++ b/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/jenaimpl/JenaFormatUtil.scala @@ -0,0 +1,89 @@ +/* + * Copyright © 2015-2019 the contributors (see Contributors.md). + * + * This file is part of Knora. + * + * Knora is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Knora is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with Knora. If not, see . + */ + +package org.knora.webapi.messages.util.rdf.jenaimpl + +import java.io.{StringReader, StringWriter} + +import org.apache.jena +import org.knora.webapi.feature.Feature +import org.knora.webapi.messages.util.rdf._ + +/** + * An implementation of [[RdfFormatUtil]] that uses the Jena API. + */ +class JenaFormatUtil(private val modelFactory: JenaModelFactory) extends RdfFormatUtil with Feature { + override def getRdfModelFactory: RdfModelFactory = modelFactory + + override def parseNonJsonLDToRdfModel(rdfStr: String, rdfFormat: NonJsonLD): RdfModel = { + val jenaModel: JenaModel = modelFactory.makeEmptyModel + + val parsingLang: jena.riot.Lang = rdfFormat match { + case Turtle => jena.riot.RDFLanguages.TURTLE + case TriG => jena.riot.RDFLanguages.TRIG + case RdfXml => jena.riot.RDFLanguages.RDFXML + } + + jena.riot.RDFParser.create() + .source(new StringReader(rdfStr)) + .lang(parsingLang) + .errorHandler(jena.riot.system.ErrorHandlerFactory.errorHandlerStrictNoLogging) + .parse(jenaModel.getDataset) + + jenaModel + } + + override def formatNonJsonLD(rdfModel: RdfModel, rdfFormat: NonJsonLD, prettyPrint: Boolean): String = { + import JenaConversions._ + + val datasetGraph: jena.sparql.core.DatasetGraph = rdfModel.asJenaDataset.asDatasetGraph + val stringWriter: StringWriter = new StringWriter + + rdfFormat match { + case Turtle => + val rdfFormat: jena.riot.RDFFormat = if (prettyPrint) { + jena.riot.RDFFormat.TURTLE_PRETTY + } else { + jena.riot.RDFFormat.TURTLE_FLAT + } + + jena.riot.RDFDataMgr.write(stringWriter, datasetGraph.getDefaultGraph, rdfFormat) + + case RdfXml => + val rdfFormat: jena.riot.RDFFormat = if (prettyPrint) { + jena.riot.RDFFormat.RDFXML_PRETTY + } else { + jena.riot.RDFFormat.RDFXML_PLAIN + } + + jena.riot.RDFDataMgr.write(stringWriter, datasetGraph.getDefaultGraph, rdfFormat) + + case TriG => + val rdfFormat: jena.riot.RDFFormat = if (prettyPrint) { + jena.riot.RDFFormat.TRIG_PRETTY + } else { + jena.riot.RDFFormat.TRIG_FLAT + } + + jena.riot.RDFDataMgr.write(stringWriter, datasetGraph, rdfFormat) + } + + stringWriter.toString + } +} diff --git a/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/jenaimpl/JenaModel.scala b/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/jenaimpl/JenaModel.scala new file mode 100644 index 0000000000..77c560966a --- /dev/null +++ b/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/jenaimpl/JenaModel.scala @@ -0,0 +1,387 @@ +/* + * Copyright © 2015-2019 the contributors (see Contributors.md). + * + * This file is part of Knora. + * + * Knora is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Knora is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with Knora. If not, see . + */ + +package org.knora.webapi.messages.util.rdf.jenaimpl + +import org.apache.jena +import org.knora.webapi.IRI +import org.knora.webapi.exceptions.RdfProcessingException +import org.knora.webapi.feature.Feature +import org.knora.webapi.messages.OntologyConstants +import org.knora.webapi.messages.util.rdf._ + +import scala.collection.JavaConverters._ + + +sealed trait JenaNode extends RdfNode { + def node: jena.graph.Node +} + +case class JenaBlankNode(node: jena.graph.Node) extends JenaNode with BlankNode { + override def id: String = node.getBlankNodeId.getLabelString + + override def stringValue: String = id +} + +case class JenaIriNode(node: jena.graph.Node) extends JenaNode with IriNode { + override def iri: IRI = node.getURI + + override def stringValue: String = iri +} + +case class JenaDatatypeLiteral(node: jena.graph.Node) extends JenaNode with DatatypeLiteral { + override def value: String = node.getLiteralLexicalForm + + override def datatype: IRI = node.getLiteralDatatypeURI + + override def stringValue: String = value +} + +case class JenaStringWithLanguage(node: jena.graph.Node) extends JenaNode with StringWithLanguage { + override def value: String = node.getLiteralLexicalForm + + override def language: String = node.getLiteralLanguage + + override def stringValue: String = value +} + +object JenaResource { + def fromJena(node: jena.graph.Node): Option[RdfResource] = { + if (node.isURI) { + Some(JenaIriNode(node)) + } else if (node.isBlank) { + Some(JenaBlankNode(node)) + } else { + None + } + } +} + +case class JenaStatement(quad: jena.sparql.core.Quad) extends Statement { + override def subj: RdfResource = { + val subj: jena.graph.Node = quad.getSubject + JenaResource.fromJena(subj).getOrElse(throw RdfProcessingException(s"Unexpected statement subject: $subj")) + } + + override def pred: IriNode = JenaIriNode(quad.getPredicate) + + override def obj: RdfNode = { + val obj: jena.graph.Node = quad.getObject + + JenaResource.fromJena(obj) match { + case Some(rdfResource) => rdfResource + + case None => + if (obj.isLiteral) { + val literal: jena.graph.impl.LiteralLabel = obj.getLiteral + + if (literal.language != "") { + JenaStringWithLanguage(obj) + } else { + JenaDatatypeLiteral(obj) + } + } else { + throw RdfProcessingException(s"Unexpected statement object: $obj") + } + } + } + + override def context: Option[IRI] = { + Option(quad.getGraph).map(_.getURI) + } +} + +/** + * Provides extension methods for converting between Knora RDF API classes and Jena classes + * (see [[https://docs.scala-lang.org/overviews/core/value-classes.html#extension-methods Extension Methods]]). + */ +object JenaConversions { + + implicit class ConvertibleJenaNode(val self: RdfNode) extends AnyVal { + def asJenaNode: jena.graph.Node = { + self match { + case jenaRdfNode: JenaNode => jenaRdfNode.node + case other => throw RdfProcessingException(s"$other is not a Jena node") + } + } + } + + implicit class ConvertibleJenaQuad(val self: Statement) extends AnyVal { + def asJenaQuad: jena.sparql.core.Quad = { + self match { + case jenaStatement: JenaStatement => jenaStatement.quad + case other => throw RdfProcessingException(s"$other is not a Jena statement") + } + } + } + + implicit class ConvertibleJenaModel(val self: RdfModel) extends AnyVal { + def asJenaDataset: jena.query.Dataset = { + self match { + case model: JenaModel => model.getDataset + case other => throw RdfProcessingException(s"${other.getClass.getName} is not a Jena RDF model") + } + } + } + +} + +/** + * Generates Jena nodes representing contexts. + */ +abstract class JenaContextFactory { + /** + * Converts a named graph IRI to a [[jena.graph.Node]]. + */ + protected def contextIriToNode(context: IRI): jena.graph.Node = { + jena.graph.NodeFactory.createURI(context) + } + + /** + * Converts an optional named graph IRI to a [[jena.graph.Node]], converting + * `None` to the IRI of Jena's default graph. + */ + protected def contextNodeOrDefaultGraph(context: Option[IRI]): jena.graph.Node = { + context.map(contextIriToNode).getOrElse(jena.sparql.core.Quad.defaultGraphIRI) + } + + /** + * Converts an optional named graph IRI to a [[jena.graph.Node]], converting + * `None` to a wildcard that will match any graph. + */ + protected def contextNodeOrWildcard(context: Option[IRI]): jena.graph.Node = { + context.map(contextIriToNode).getOrElse(jena.graph.Node.ANY) + } +} + +/** + * An implementation of [[RdfModel]] that wraps a [[jena.query.Dataset]]. + * + * @param dataset the underlying Jena dataset. + */ +class JenaModel(private val dataset: jena.query.Dataset, + private val nodeFactory: JenaNodeFactory) extends JenaContextFactory with RdfModel with Feature { + + import JenaConversions._ + + private val datasetGraph: jena.sparql.core.DatasetGraph = dataset.asDatasetGraph + + /** + * Returns the underlying [[jena.query.Dataset]]. + */ + def getDataset: jena.query.Dataset = dataset + + override def getNodeFactory: RdfNodeFactory = nodeFactory + + override def addStatement(statement: Statement): Unit = { + datasetGraph.add(statement.asJenaQuad) + } + + override def getStatements: Set[Statement] = datasetGraph.find.asScala.map(JenaStatement).toSet + + /** + * Converts an optional [[RdfNode]] to a [[jena.graph.Node]], converting + * `None` to a wildcard that will match any node. + */ + private def asJenaNodeOrWildcard(node: Option[RdfNode]): jena.graph.Node = { + node.map(_.asJenaNode).getOrElse(jena.graph.Node.ANY) + } + + override def add(subj: RdfResource, pred: IriNode, obj: RdfNode, context: Option[IRI] = None): Unit = { + datasetGraph.add( + contextNodeOrDefaultGraph(context), + subj.asJenaNode, + pred.asJenaNode, + obj.asJenaNode + ) + } + + override def remove(subj: Option[RdfResource], pred: Option[IriNode], obj: Option[RdfNode], context: Option[IRI] = None): Unit = { + datasetGraph.deleteAny( + contextNodeOrWildcard(context), + asJenaNodeOrWildcard(subj), + asJenaNodeOrWildcard(pred), + asJenaNodeOrWildcard(obj) + ) + } + + override def removeStatement(statement: Statement): Unit = { + datasetGraph.delete(statement.asJenaQuad) + } + + override def find(subj: Option[RdfResource], pred: Option[IriNode], obj: Option[RdfNode], context: Option[IRI] = None): Set[Statement] = { + datasetGraph.find( + contextNodeOrWildcard(context), + asJenaNodeOrWildcard(subj), + asJenaNodeOrWildcard(pred), + asJenaNodeOrWildcard(obj) + ).asScala.map(JenaStatement).toSet + } + + override def setNamespace(prefix: String, namespace: IRI): Unit = { + def setNamespaceInGraph(graph: jena.graph.Graph): Unit = { + val prefixMapping: jena.shared.PrefixMapping = graph.getPrefixMapping + prefixMapping.setNsPrefix(prefix, namespace) + } + + // Add the namespace to the default graph. + setNamespaceInGraph(datasetGraph.getDefaultGraph) + + // Add the namespace to all the named graphs in the dataset. + for (graphNode: jena.graph.Node <- datasetGraph.listGraphNodes.asScala) { + val graph: jena.graph.Graph = datasetGraph.getGraph(graphNode) + setNamespaceInGraph(graph) + } + } + + override def getNamespaces: Map[String, IRI] = { + def getNamespacesFromGraph(graph: jena.graph.Graph): Map[String, IRI] = { + val prefixMapping: jena.shared.PrefixMapping = graph.getPrefixMapping + prefixMapping.getNsPrefixMap.asScala.toMap + } + + // Get the namespaces from the default graph. + val defaultGraphNamespaces: Map[String, IRI] = getNamespacesFromGraph(datasetGraph.getDefaultGraph) + + // Get the namespaces used in all the named graphs in the dataset. + val namedGraphNamespaces: Map[String, IRI] = datasetGraph.listGraphNodes.asScala.flatMap { + graphNode: jena.graph.Node => + val graph: jena.graph.Graph = datasetGraph.getGraph(graphNode) + val prefixMapping: jena.shared.PrefixMapping = graph.getPrefixMapping + prefixMapping.getNsPrefixMap.asScala + }.toMap + + defaultGraphNamespaces ++ namedGraphNamespaces + } + + override def isEmpty: Boolean = dataset.isEmpty + + override def getSubjects: Set[RdfResource] = { + datasetGraph.find.asScala.map { + quad: jena.sparql.core.Quad => + val subj: jena.graph.Node = quad.getSubject + JenaResource.fromJena(subj).getOrElse(throw RdfProcessingException(s"Unexpected statement subject: $subj")) + }.toSet + } + + override def isIsomorphicWith(otherRdfModel: RdfModel): Boolean = { + // Jena's DatasetGraph doesn't have a method for this, so we have to do it ourselves. + + val thatDatasetGraph: jena.sparql.core.DatasetGraph = otherRdfModel.asJenaDataset.asDatasetGraph + + // Get the IRIs of the named graphs. + val thisModelNamedGraphIris: Set[jena.graph.Node] = datasetGraph.listGraphNodes.asScala.toSet + val thatModelNamedGraphIris: Set[jena.graph.Node] = thatDatasetGraph.listGraphNodes.asScala.toSet + + // The two models are isomorphic if: + // - They have the same set of named graph IRIs. + // - The default graphs are isomorphic. + // - The named graphs with the same IRIs are isomorphic. + thisModelNamedGraphIris == thatModelNamedGraphIris && + datasetGraph.getDefaultGraph.isIsomorphicWith(thatDatasetGraph.getDefaultGraph) && + thisModelNamedGraphIris.forall { + namedGraphIri: jena.graph.Node => + datasetGraph.getGraph(namedGraphIri).isIsomorphicWith(thatDatasetGraph.getGraph(namedGraphIri)) + } + } + + override def getContexts: Set[IRI] = { + datasetGraph.listGraphNodes.asScala.toSet.map { + node: jena.graph.Node => node.getURI + } + } +} + +/** + * An implementation of [[RdfNodeFactory]] that creates Jena node implementation wrappers. + */ +class JenaNodeFactory extends JenaContextFactory with RdfNodeFactory { + + import JenaConversions._ + + /** + * Represents a custom Knora datatype (used in the simple schema), for registration + * with Jena's TypeMapper. + * + * @param iri the IRI of the datatype. + */ + private class KnoraDatatype(iri: IRI) extends jena.datatypes.BaseDatatype(iri) { + override def unparse(value: java.lang.Object): String = { + value.toString + } + + override def parse(lexicalForm: String): java.lang.Object = { + lexicalForm + } + + override def isEqual(value1: jena.graph.impl.LiteralLabel, value2: jena.graph.impl.LiteralLabel): Boolean = { + value1.getDatatype == value2.getDatatype && value1.getValue.equals(value2.getValue) + } + } + + // Jena's registry of datatypes. + private val typeMapper = jena.datatypes.TypeMapper.getInstance + + // Register Knora's custom datatypes. + for (knoraDatatypeIri <- OntologyConstants.KnoraApiV2Simple.KnoraDatatypes) { + typeMapper.registerDatatype(new KnoraDatatype(knoraDatatypeIri)) + } + + override def makeBlankNode: BlankNode = { + JenaBlankNode(jena.graph.NodeFactory.createBlankNode) + } + + override def makeBlankNodeWithID(id: String): BlankNode = { + JenaBlankNode(jena.graph.NodeFactory.createBlankNode(id)) + } + + override def makeIriNode(iri: IRI): IriNode = { + JenaIriNode(jena.graph.NodeFactory.createURI(iri)) + } + + override def makeDatatypeLiteral(value: String, datatype: IRI): DatatypeLiteral = { + JenaDatatypeLiteral(jena.graph.NodeFactory.createLiteral(value, typeMapper.getTypeByName(datatype))) + } + + override def makeStringWithLanguage(value: String, language: String): StringWithLanguage = { + JenaStringWithLanguage(jena.graph.NodeFactory.createLiteral(value, language)) + } + + override def makeStatement(subj: RdfResource, pred: IriNode, obj: RdfNode, context: Option[IRI]): Statement = { + JenaStatement( + new jena.sparql.core.Quad( + contextNodeOrDefaultGraph(context), + subj.asJenaNode, + pred.asJenaNode, + obj.asJenaNode + ) + ) + } + +} + +/** + * A factory for creating instances of [[JenaModel]]. + */ +class JenaModelFactory(private val nodeFactory: JenaNodeFactory) extends RdfModelFactory { + override def makeEmptyModel: JenaModel = new JenaModel( + dataset = jena.query.DatasetFactory.create, + nodeFactory = nodeFactory + ) +} diff --git a/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/RDF4JFormatUtil.scala b/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/RDF4JFormatUtil.scala new file mode 100644 index 0000000000..2116173143 --- /dev/null +++ b/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/RDF4JFormatUtil.scala @@ -0,0 +1,74 @@ +/* + * Copyright © 2015-2019 the contributors (see Contributors.md). + * + * This file is part of Knora. + * + * Knora is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Knora is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with Knora. If not, see . + */ + +package org.knora.webapi.messages.util.rdf.rdf4jimpl + +import java.io.{StringReader, StringWriter} + +import org.eclipse.rdf4j +import org.knora.webapi.feature.Feature +import org.knora.webapi.messages.util.rdf._ + +/** + * An implementation of [[RdfFormatUtil]] that uses the RDF4J API. + */ +class RDF4JFormatUtil(private val modelFactory: RDF4JModelFactory, + private val nodeFactory: RDF4JNodeFactory) extends RdfFormatUtil with Feature { + override def getRdfModelFactory: RdfModelFactory = modelFactory + + private def rdfFormatToRDF4JFormat(rdfFormat: NonJsonLD): rdf4j.rio.RDFFormat = { + rdfFormat match { + case Turtle => rdf4j.rio.RDFFormat.TURTLE + case TriG => rdf4j.rio.RDFFormat.TRIG + case RdfXml => rdf4j.rio.RDFFormat.RDFXML + } + } + + protected def parseNonJsonLDToRdfModel(rdfStr: String, rdfFormat: NonJsonLD): RdfModel = { + new RDF4JModel( + model = rdf4j.rio.Rio.parse( + new StringReader(rdfStr), + "", + rdfFormatToRDF4JFormat(rdfFormat) + ), + nodeFactory = nodeFactory + ) + } + + override def formatNonJsonLD(rdfModel: RdfModel, rdfFormat: NonJsonLD, prettyPrint: Boolean): String = { + import RDF4JConversions._ + + val stringWriter = new StringWriter + + val rdfWriter: rdf4j.rio.RDFWriter = rdfFormat match { + case Turtle => rdf4j.rio.Rio.createWriter(rdf4j.rio.RDFFormat.TURTLE, stringWriter) + case TriG => rdf4j.rio.Rio.createWriter(rdf4j.rio.RDFFormat.TRIG, stringWriter) + case RdfXml => new rdf4j.rio.rdfxml.util.RDFXMLPrettyWriter(stringWriter) + } + + // Configure the RDFWriter. + rdfWriter.getWriterConfig. + set[java.lang.Boolean](rdf4j.rio.helpers.BasicWriterSettings.INLINE_BLANK_NODES, true). + set[java.lang.Boolean](rdf4j.rio.helpers.BasicWriterSettings.PRETTY_PRINT, true) + + // Format the RDF. + rdf4j.rio.Rio.write(rdfModel.asRDF4JModel, rdfWriter) + stringWriter.toString + } +} diff --git a/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/RDF4JModel.scala b/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/RDF4JModel.scala new file mode 100644 index 0000000000..a3a71eb8e0 --- /dev/null +++ b/webapi/src/main/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/RDF4JModel.scala @@ -0,0 +1,339 @@ +/* + * Copyright © 2015-2019 the contributors (see Contributors.md). + * + * This file is part of Knora. + * + * Knora is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Knora is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with Knora. If not, see . + */ + +package org.knora.webapi.messages.util.rdf.rdf4jimpl + +import org.eclipse.rdf4j +import org.knora.webapi.IRI +import org.knora.webapi.exceptions.RdfProcessingException +import org.knora.webapi.feature.Feature +import org.knora.webapi.messages.util.rdf._ +import org.knora.webapi.util.JavaUtil._ + +import scala.collection.JavaConverters._ + +sealed trait RDF4JNode extends RdfNode { + def rdf4jValue: rdf4j.model.Value + + override def stringValue: String = rdf4jValue.stringValue +} + +sealed trait RDF4JResource extends RDF4JNode with RdfResource { + def resource: rdf4j.model.Resource + + override def rdf4jValue: rdf4j.model.Value = resource +} + +object RDF4JResource { + def fromRDF4J(resource: rdf4j.model.Resource): RDF4JResource = { + resource match { + case iri: rdf4j.model.IRI => RDF4JIriNode(iri) + case blankNode: rdf4j.model.BNode => RDF4JBlankNode(blankNode) + case other => throw RdfProcessingException(s"Unexpected resource: $other") + } + } +} + +case class RDF4JBlankNode(resource: rdf4j.model.BNode) extends RDF4JResource with BlankNode { + override def id: String = resource.getID +} + +case class RDF4JIriNode(resource: rdf4j.model.IRI) extends RDF4JResource with IriNode { + override def iri: IRI = resource.stringValue +} + +sealed trait RDF4JLiteral extends RDF4JNode with RdfLiteral { + def literal: rdf4j.model.Literal + + override def rdf4jValue: rdf4j.model.Value = literal +} + +case class RDF4JDatatypeLiteral(literal: rdf4j.model.Literal) extends RDF4JLiteral with DatatypeLiteral { + override def value: String = literal.getLabel + + override def datatype: IRI = literal.getDatatype.stringValue +} + +case class RDF4JStringWithLanguage(literal: rdf4j.model.Literal) extends RDF4JLiteral with StringWithLanguage { + override def value: String = literal.getLabel + + override def language: String = literal.getLanguage.toOption.getOrElse(throw RdfProcessingException(s"Literal $literal has no language tag")) +} + +case class RDF4JStatement(statement: rdf4j.model.Statement) extends Statement { + override def subj: RdfResource = { + statement.getSubject match { + case resource: rdf4j.model.Resource => RDF4JResource.fromRDF4J(resource) + case other => throw RdfProcessingException(s"Unexpected statement subject: $other") + } + } + + override def pred: IriNode = RDF4JIriNode(statement.getPredicate) + + override def obj: RdfNode = { + statement.getObject match { + case resource: rdf4j.model.Resource => RDF4JResource.fromRDF4J(resource) + + case literal: rdf4j.model.Literal => + if (literal.getLanguage.toOption.isDefined) { + RDF4JStringWithLanguage(literal) + } else { + RDF4JDatatypeLiteral(literal) + } + + case other => throw RdfProcessingException(s"Unexpected statement object: $other") + } + } + + override def context: Option[IRI] = Option(statement.getContext).map(_.stringValue) +} + +/** + * Provides extension methods for converting between Knora RDF API classes and RDF4J classes + * (see [[https://docs.scala-lang.org/overviews/core/value-classes.html#extension-methods Extension Methods]]). + */ +object RDF4JConversions { + + implicit class ConvertibleRDF4JResource(val self: RdfResource) extends AnyVal { + def asRDF4JResource: rdf4j.model.Resource = { + self match { + case rdf4jResource: RDF4JResource => rdf4jResource.resource + case other => throw RdfProcessingException(s"$other is not a RDF4J resource") + } + } + } + + implicit class ConvertibleRDF4JIri(val self: IriNode) extends AnyVal { + def asRDF4JIri: rdf4j.model.IRI = { + self match { + case rdf4jIriNode: RDF4JIriNode => rdf4jIriNode.resource + case other => throw RdfProcessingException(s"$other is not an RDF4J IRI") + } + } + } + + implicit class ConvertibleRDF4JValue(val self: RdfNode) extends AnyVal { + def asRDF4JValue: rdf4j.model.Value = { + self match { + case rdf4jResource: RDF4JNode => rdf4jResource.rdf4jValue + case other => throw RdfProcessingException(s"$other is not an RDF4J value") + } + } + } + + implicit class ConvertibleRDF4JStatement(val self: Statement) extends AnyVal { + def asRDF4JStatement: rdf4j.model.Statement = { + self match { + case rdf4JStatement: RDF4JStatement => rdf4JStatement.statement + case other => throw RdfProcessingException(s"$other is not an RDF4J statement") + } + } + } + + implicit class ConvertibleRDF4JModel(val self: RdfModel) extends AnyVal { + def asRDF4JModel: rdf4j.model.Model = { + self match { + case rdf4JModel: RDF4JModel => rdf4JModel.getModel + case other => throw RdfProcessingException(s"${other.getClass.getName} is not an RDF4J model") + } + } + } + +} + +/** + * An implementation of [[RdfModel]] that wraps an [[rdf4j.model.Model]]. + * + * @param model the underlying RDF4J model. + */ +class RDF4JModel(private val model: rdf4j.model.Model, + private val nodeFactory: RDF4JNodeFactory) extends RdfModel with Feature { + + import RDF4JConversions._ + + private val valueFactory: rdf4j.model.ValueFactory = rdf4j.model.impl.SimpleValueFactory.getInstance + + /** + * Returns the underlying [[rdf4j.model.Model]]. + */ + def getModel: rdf4j.model.Model = model + + override def getNodeFactory: RdfNodeFactory = nodeFactory + + override def getStatements: Set[Statement] = model.asScala.toSet.map(RDF4JStatement) + + override def addStatement(statement: Statement): Unit = { + model.add(statement.asRDF4JStatement) + } + + override def add(subj: RdfResource, pred: IriNode, obj: RdfNode, context: Option[IRI] = None): Unit = { + context match { + case Some(definedContext) => + model.add( + subj.asRDF4JResource, + pred.asRDF4JIri, + obj.asRDF4JValue, + valueFactory.createIRI(definedContext) + ) + + case None => + model.add( + subj.asRDF4JResource, + pred.asRDF4JIri, + obj.asRDF4JValue + ) + } + } + + override def remove(subj: Option[RdfResource], pred: Option[IriNode], obj: Option[RdfNode], context: Option[IRI] = None): Unit = { + context match { + case Some(definedContext) => + model.remove( + subj.map(_.asRDF4JResource).orNull, + pred.map(_.asRDF4JIri).orNull, + obj.map(_.asRDF4JValue).orNull, + valueFactory.createIRI(definedContext) + ) + + case None => + model.remove( + subj.map(_.asRDF4JResource).orNull, + pred.map(_.asRDF4JIri).orNull, + obj.map(_.asRDF4JValue).orNull, + ) + } + } + + override def removeStatement(statement: Statement): Unit = { + remove( + Some(statement.subj), + Some(statement.pred), + Some(statement.obj), + statement.context + ) + } + + override def find(subj: Option[RdfResource], pred: Option[IriNode], obj: Option[RdfNode], context: Option[IRI] = None): Set[Statement] = { + val filteredModel: rdf4j.model.Model = context match { + case Some(definedContext) => + model.filter( + subj.map(_.asRDF4JResource).orNull, + pred.map(_.asRDF4JIri).orNull, + obj.map(_.asRDF4JValue).orNull, + valueFactory.createIRI(definedContext) + ) + + case None => + model.filter( + subj.map(_.asRDF4JResource).orNull, + pred.map(_.asRDF4JIri).orNull, + obj.map(_.asRDF4JValue).orNull, + ) + } + + filteredModel.asScala.map(RDF4JStatement).toSet + } + + override def setNamespace(prefix: String, namespace: IRI): Unit = { + model.setNamespace(new rdf4j.model.impl.SimpleNamespace(prefix, namespace)) + } + + override def getNamespaces: Map[String, IRI] = { + model.getNamespaces.asScala.map { + namespace: rdf4j.model.Namespace => namespace.getPrefix -> namespace.getName + }.toMap + } + + override def isEmpty: Boolean = model.isEmpty + + override def getSubjects: Set[RdfResource] = { + model.subjects.asScala.toSet.map(resource => RDF4JResource.fromRDF4J(resource)) + } + + override def isIsomorphicWith(otherRdfModel: RdfModel): Boolean = { + model == otherRdfModel.asRDF4JModel + } + + override def getContexts: Set[IRI] = { + model.contexts.asScala.toSet.filter(_ != null).map { + context: rdf4j.model.Resource => context.stringValue + } + } +} + +/** + * An implementation of [[RdfNodeFactory]] that creates RDF4J node implementation wrappers. + */ +class RDF4JNodeFactory extends RdfNodeFactory { + + import RDF4JConversions._ + + private val valueFactory: rdf4j.model.ValueFactory = rdf4j.model.impl.SimpleValueFactory.getInstance + + override def makeBlankNode: BlankNode = { + RDF4JBlankNode(valueFactory.createBNode) + } + + override def makeBlankNodeWithID(id: String): BlankNode = { + RDF4JBlankNode(valueFactory.createBNode(id)) + } + + override def makeIriNode(iri: IRI): IriNode = { + RDF4JIriNode(valueFactory.createIRI(iri)) + } + + override def makeDatatypeLiteral(value: String, datatype: IRI): DatatypeLiteral = { + RDF4JDatatypeLiteral(valueFactory.createLiteral(value, valueFactory.createIRI(datatype))) + } + + override def makeStringWithLanguage(value: String, language: String): StringWithLanguage = { + RDF4JStringWithLanguage(valueFactory.createLiteral(value, language)) + } + + override def makeStatement(subj: RdfResource, pred: IriNode, obj: RdfNode, context: Option[IRI]): Statement = { + val statement: rdf4j.model.Statement = context match { + case Some(definedContext) => + valueFactory.createStatement( + subj.asRDF4JResource, + pred.asRDF4JIri, + obj.asRDF4JValue, + valueFactory.createIRI(definedContext) + ) + + case None => + valueFactory.createStatement( + subj.asRDF4JResource, + pred.asRDF4JIri, + obj.asRDF4JValue + ) + } + + RDF4JStatement(statement) + } +} + +/** + * A factory for creating instances of [[RDF4JModel]]. + */ +class RDF4JModelFactory(private val nodeFactory: RDF4JNodeFactory) extends RdfModelFactory { + override def makeEmptyModel: RDF4JModel = new RDF4JModel( + model = new rdf4j.model.impl.LinkedHashModel, + nodeFactory = nodeFactory + ) +} diff --git a/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/ckanmessages/CkanMessagesV1.scala b/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/ckanmessages/CkanMessagesV1.scala index 158dddad13..7ee87e59b2 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/ckanmessages/CkanMessagesV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/ckanmessages/CkanMessagesV1.scala @@ -20,6 +20,7 @@ package org.knora.webapi.messages.v1.responder.ckanmessages import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.v1.responder.{KnoraRequestV1, KnoraResponseV1} import spray.json._ @@ -38,9 +39,14 @@ sealed trait CkanResponderRequestV1 extends KnoraRequestV1 * @param projects * @param limit * @param info + * @param featureFactoryConfig the feature factory configuration. * @param userProfile */ -case class CkanRequestV1(projects: Option[Seq[String]], limit: Option[Int], info: Boolean, userProfile: UserADM) extends CkanResponderRequestV1 +case class CkanRequestV1(projects: Option[Seq[String]], + limit: Option[Int], + info: Boolean, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM) extends CkanResponderRequestV1 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // API response diff --git a/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/ontologymessages/OntologyMessagesV1.scala b/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/ontologymessages/OntologyMessagesV1.scala index 813389bc7e..51377392ab 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/ontologymessages/OntologyMessagesV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/ontologymessages/OntologyMessagesV1.scala @@ -21,6 +21,7 @@ package org.knora.webapi.messages.v1.responder.ontologymessages import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport import org.knora.webapi._ +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.store.triplestoremessages.StringLiteralV2 @@ -43,9 +44,11 @@ sealed trait OntologyResponderRequestV1 extends KnoraRequestV1 * Requests that all ontologies in the repository are loaded. This message must be sent only once, when the application * starts, before it accepts any API requests. A successful response will be a [[LoadOntologiesResponse]]. * - * @param userADM the profile of the user making the request. + * @param featureFactoryConfig the feature factory configuration. + * @param userADM the profile of the user making the request. */ -case class LoadOntologiesRequest(userADM: UserADM) extends OntologyResponderRequestV1 +case class LoadOntologiesRequestV1(featureFactoryConfig: FeatureFactoryConfig, + userADM: UserADM) extends OntologyResponderRequestV1 /** * Indicates that all ontologies were loaded. @@ -166,11 +169,14 @@ case class CheckSubClassResponseV1(isSubClass: Boolean) * Requests information about named graphs containing ontologies. This corresponds to the concept of vocabularies in * the SALSAH prototype. * - * @param projectIris the IRIs of the projects for which named graphs should be returned. If this set is empty, information - * about all ontology named graphs is returned. - * @param userADM the profile of the user making the request. + * @param projectIris the IRIs of the projects for which named graphs should be returned. If this set is empty, information + * about all ontology named graphs is returned. + * @param featureFactoryConfig the feature factory configuration. + * @param userADM the profile of the user making the request. */ -case class NamedGraphsGetRequestV1(projectIris: Set[IRI] = Set.empty[IRI], userADM: UserADM) extends OntologyResponderRequestV1 +case class NamedGraphsGetRequestV1(projectIris: Set[IRI] = Set.empty[IRI], + featureFactoryConfig: FeatureFactoryConfig, + userADM: UserADM) extends OntologyResponderRequestV1 /** * Represents the Knora API V1 response to a [[NamedGraphsGetRequestV1]]. @@ -184,10 +190,13 @@ case class NamedGraphsResponseV1(vocabularies: Seq[NamedGraphV1]) extends KnoraR /** * Requests all resource classes that are defined in the given named graph. * - * @param namedGraph the named graph for which the resource classes shall be returned. - * @param userADM the profile of the user making the request. + * @param namedGraph the named graph for which the resource classes shall be returned. + * @param featureFactoryConfig the feature factory configuration. + * @param userADM the profile of the user making the request. */ -case class ResourceTypesForNamedGraphGetRequestV1(namedGraph: Option[IRI], userADM: UserADM) extends OntologyResponderRequestV1 +case class ResourceTypesForNamedGraphGetRequestV1(namedGraph: Option[IRI], + featureFactoryConfig: FeatureFactoryConfig, + userADM: UserADM) extends OntologyResponderRequestV1 /** * Represents the Knora API V1 response to a [[ResourceTypesForNamedGraphGetRequestV1]]. @@ -203,10 +212,13 @@ case class ResourceTypesForNamedGraphResponseV1(resourcetypes: Seq[ResourceTypeV * Requests all property types that are defined in the given named graph. * If the named graph is not set, the property types of all named graphs are requested. * - * @param namedGraph the named graph to query for or None if all the named graphs should be queried. - * @param userADM the profile of the user making the request. + * @param namedGraph the named graph to query for or None if all the named graphs should be queried. + * @param featureFactoryConfig the feature factory configuration. + * @param userADM the profile of the user making the request. */ -case class PropertyTypesForNamedGraphGetRequestV1(namedGraph: Option[IRI], userADM: UserADM) extends OntologyResponderRequestV1 +case class PropertyTypesForNamedGraphGetRequestV1(namedGraph: Option[IRI], + featureFactoryConfig: FeatureFactoryConfig, + userADM: UserADM) extends OntologyResponderRequestV1 /** * Represents the Knora API V1 response to a [[PropertyTypesForNamedGraphGetRequestV1]]. diff --git a/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/projectmessages/ProjectMessagesV1.scala b/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/projectmessages/ProjectMessagesV1.scala index 399ef614b5..f19831a658 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/projectmessages/ProjectMessagesV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/projectmessages/ProjectMessagesV1.scala @@ -21,6 +21,7 @@ package org.knora.webapi.messages.v1.responder.projectmessages import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport import org.knora.webapi.IRI +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.v1.responder.usermessages.{UserDataV1, UserProfileV1} import org.knora.webapi.messages.v1.responder.{KnoraRequestV1, KnoraResponseV1} import spray.json.{DefaultJsonProtocol, JsValue, JsonFormat, NullOptions, RootJsonFormat} @@ -43,41 +44,54 @@ sealed trait ProjectsResponderRequestV1 extends KnoraRequestV1 * Get all information about all projects in form of [[ProjectsResponseV1]]. The ProjectsGetRequestV1 returns either * something or a NotFound exception if there are no projects found. Administration permission checking is performed. * - * @param userProfile the profile of the user making the request. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. */ -case class ProjectsGetRequestV1(userProfile: Option[UserProfileV1]) extends ProjectsResponderRequestV1 +case class ProjectsGetRequestV1(featureFactoryConfig: FeatureFactoryConfig, + userProfile: Option[UserProfileV1]) extends ProjectsResponderRequestV1 /** * Get all information about all projects in form of a sequence of [[ProjectInfoV1]]. Returns an empty sequence if * no projects are found. Administration permission checking is skipped. * - * @param userProfile the profile of the user making the request. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. */ -case class ProjectsGetV1(userProfile: Option[UserProfileV1]) extends ProjectsResponderRequestV1 +case class ProjectsGetV1(featureFactoryConfig: FeatureFactoryConfig, + userProfile: Option[UserProfileV1]) extends ProjectsResponderRequestV1 /** * Get info about a single project identified through its IRI. A successful response will be a [[ProjectInfoResponseV1]]. * - * @param iri the IRI of the project. - * @param userProfileV1 the profile of the user making the request (optional). + * @param iri the IRI of the project. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfileV1 the profile of the user making the request (optional). */ -case class ProjectInfoByIRIGetRequestV1(iri: IRI, userProfileV1: Option[UserProfileV1]) extends ProjectsResponderRequestV1 +case class ProjectInfoByIRIGetRequestV1(iri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfileV1: Option[UserProfileV1]) extends ProjectsResponderRequestV1 /** * Get info about a single project identified through its IRI. A successful response will be an [[Option[ProjectInfoV1] ]]. * - * @param iri the IRI of the project. - * @param userProfileV1 the profile of the user making the request (optional). + * @param iri the IRI of the project. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfileV1 the profile of the user making the request (optional). */ -case class ProjectInfoByIRIGetV1(iri: IRI, userProfileV1: Option[UserProfileV1]) extends ProjectsResponderRequestV1 +case class ProjectInfoByIRIGetV1(iri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfileV1: Option[UserProfileV1]) extends ProjectsResponderRequestV1 /** * Find everything about a single project identified through its shortname. * - * @param shortname of the project. - * @param userProfileV1 the profile of the user making the request. + * @param shortname of the project. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfileV1 the profile of the user making the request. */ -case class ProjectInfoByShortnameGetRequestV1(shortname: String, userProfileV1: Option[UserProfileV1]) extends ProjectsResponderRequestV1 +case class ProjectInfoByShortnameGetRequestV1(shortname: String, + featureFactoryConfig: FeatureFactoryConfig, + userProfileV1: Option[UserProfileV1]) extends ProjectsResponderRequestV1 // Responses diff --git a/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/resourcemessages/ResourceMessagesV1.scala b/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/resourcemessages/ResourceMessagesV1.scala index 4632844518..b5c0fac37e 100755 --- a/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/resourcemessages/ResourceMessagesV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/resourcemessages/ResourceMessagesV1.scala @@ -25,6 +25,7 @@ import java.util.UUID import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport import org.knora.webapi._ import org.knora.webapi.exceptions.{BadRequestException, DataConversionException, InconsistentTriplestoreDataException, InvalidApiJsonException} +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.OntologyConstants import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectADM import org.knora.webapi.messages.admin.responder.usersmessages.UserADM @@ -157,37 +158,51 @@ sealed trait ResourcesResponderRequestV1 extends KnoraRequestV1 /** * Requests a description of a resource. A successful response will be a [[ResourceInfoResponseV1]]. * - * @param iri the IRI of the resource to be queried. - * @param userProfile the profile of the user making the request. + * @param iri the IRI of the resource to be queried. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. */ -case class ResourceInfoGetRequestV1(iri: IRI, userProfile: UserADM) extends ResourcesResponderRequestV1 +case class ResourceInfoGetRequestV1(iri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM) extends ResourcesResponderRequestV1 /** * Requests a full description of a resource, along with its properties, their values, incoming references, and other * information. A successful response will be a [[ResourceFullResponseV1]]. * - * @param iri the IRI of the resource to be queried. - * @param userADM the profile of the user making the request. - * @param getIncoming if `true`, information about incoming references will be included in the response. + * @param iri the IRI of the resource to be queried. + * @param featureFactoryConfig the feature factory configuration. + * @param userADM the profile of the user making the request. + * @param getIncoming if `true`, information about incoming references will be included in the response. */ -case class ResourceFullGetRequestV1(iri: IRI, userADM: UserADM, getIncoming: Boolean = true) extends ResourcesResponderRequestV1 +case class ResourceFullGetRequestV1(iri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userADM: UserADM, + getIncoming: Boolean = true) extends ResourcesResponderRequestV1 /** * Requests a [[ResourceContextResponseV1]] describing the context of a resource (i.e. the resources that are part of it). * - * @param iri the IRI of the resource to be queried. - * @param userProfile the profile of the user making the request. - * @param resinfo if `true`, the [[ResourceContextResponseV1]] will include a [[ResourceInfoV1]]. + * @param iri the IRI of the resource to be queried. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. + * @param resinfo if `true`, the [[ResourceContextResponseV1]] will include a [[ResourceInfoV1]]. */ -case class ResourceContextGetRequestV1(iri: IRI, userProfile: UserADM, resinfo: Boolean) extends ResourcesResponderRequestV1 +case class ResourceContextGetRequestV1(iri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM, + resinfo: Boolean) extends ResourcesResponderRequestV1 /** * Requests the permissions for the current user on the given resource. A successful response will be a [[ResourceRightsResponseV1]]. * - * @param iri the IRI of the resource to be queried. - * @param userProfile the profile of the user making the request. + * @param iri the IRI of the resource to be queried. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. */ -case class ResourceRightsGetRequestV1(iri: IRI, userProfile: UserADM) extends ResourcesResponderRequestV1 +case class ResourceRightsGetRequestV1(iri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM) extends ResourcesResponderRequestV1 /** * Requests a search for resources matching the given string. @@ -203,19 +218,21 @@ case class ResourceSearchGetRequestV1(searchString: String, resourceTypeIri: Opt /** * Requests the creation of a new resource of the given type with the given properties. * - * @param resourceTypeIri the type of the new resource. - * @param label the rdfs:label of the resource. - * @param values the properties to add: type and value(s): a Map of propertyIris to ApiValueV1. - * @param file a file that has been uploaded to Sipi's temporary storage and should be attached to the resource. - * @param projectIri the IRI of the project the resources is added to. - * @param userProfile the profile of the user making the request. - * @param apiRequestID the ID of the API request. + * @param resourceTypeIri the type of the new resource. + * @param label the rdfs:label of the resource. + * @param values the properties to add: type and value(s): a Map of propertyIris to ApiValueV1. + * @param file a file that has been uploaded to Sipi's temporary storage and should be attached to the resource. + * @param projectIri the IRI of the project the resources is added to. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. + * @param apiRequestID the ID of the API request. */ case class ResourceCreateRequestV1(resourceTypeIri: IRI, label: String, values: Map[IRI, Seq[CreateValueV1WithComment]], file: Option[FileValueV1] = None, projectIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, userProfile: UserADM, apiRequestID: UUID) extends ResourcesResponderRequestV1 @@ -240,13 +257,15 @@ case class OneOfMultipleResourceCreateRequestV1(resourceTypeIri: IRI, /** * Requests the creation of multiple new resources. * - * @param resourcesToCreate the collection of requests for creation of new resources. - * @param projectIri the IRI of the project the resources are added to. - * @param userProfile the profile of the user making the request. - * @param apiRequestID the ID of the API request. + * @param resourcesToCreate the collection of requests for creation of new resources. + * @param projectIri the IRI of the project the resources are added to. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. + * @param apiRequestID the ID of the API request. */ case class MultipleResourceCreateRequestV1(resourcesToCreate: Seq[OneOfMultipleResourceCreateRequestV1], projectIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, userProfile: UserADM, apiRequestID: UUID) extends ResourcesResponderRequestV1 @@ -275,22 +294,28 @@ case class OneOfMultipleResourcesCreateResponseV1(clientResourceID: String, reso * Checks whether a resource belongs to a certain OWL class or to a subclass of that class. This message is used * internally by Knora, and is not part of Knora API v1. A successful response will be a [[ResourceCheckClassResponseV1]]. * - * @param resourceIri the IRI of the resource. - * @param owlClass the IRI of the OWL class to compare the resource's class to. - * @param userProfile the profile of the user making the request. + * @param resourceIri the IRI of the resource. + * @param owlClass the IRI of the OWL class to compare the resource's class to. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. */ -case class ResourceCheckClassRequestV1(resourceIri: IRI, owlClass: IRI, userProfile: UserADM) extends ResourcesResponderRequestV1 +case class ResourceCheckClassRequestV1(resourceIri: IRI, + owlClass: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM) extends ResourcesResponderRequestV1 /** * Requests that a resource is marked as deleted. A successful response will be a [[ResourceDeleteResponseV1]]. * - * @param resourceIri the IRI of the resource to be marked as deleted. - * @param deleteComment an optional comment explaining why the resource is being marked as deleted. - * @param userADM the profile of the user making the request. - * @param apiRequestID the ID of the API request. + * @param resourceIri the IRI of the resource to be marked as deleted. + * @param deleteComment an optional comment explaining why the resource is being marked as deleted. + * @param featureFactoryConfig the feature factory configuration. + * @param userADM the profile of the user making the request. + * @param apiRequestID the ID of the API request. */ case class ResourceDeleteRequestV1(resourceIri: IRI, deleteComment: Option[String], + featureFactoryConfig: FeatureFactoryConfig, userADM: UserADM, apiRequestID: UUID) extends ResourcesResponderRequestV1 @@ -373,9 +398,9 @@ case class ResourceSearchResponseV1(resources: Seq[ResourceSearchResultRowV1] = /** * Describes the answer to a newly created resource [[ResourceCreateRequestV1]]. * - * @param res_id the IRI ow the new resource. - * @param results the values that have been attached to the resource. The key in the Map refers - * to the property IRI and the Seq contains all instances of values of this type. + * @param res_id the IRI ow the new resource. + * @param results the values that have been attached to the resource. The key in the Map refers + * to the property IRI and the Seq contains all instances of values of this type. * @param projectADM the project in which the resource is to be created. */ case class ResourceCreateResponseV1(res_id: IRI, @@ -387,9 +412,12 @@ case class ResourceCreateResponseV1(res_id: IRI, /** * Requests the properties of a given resource. * - * @param iri the iri of the given resource. + * @param iri the iri of the given resource. + * @param featureFactoryConfig the feature factory configuration. */ -case class PropertiesGetRequestV1(iri: IRI, userProfile: UserADM) extends ResourcesResponderRequestV1 +case class PropertiesGetRequestV1(iri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM) extends ResourcesResponderRequestV1 // TODO: refactor PropertiesGetResponseV1 (https://github.com/dhlab-basel/Knora/issues/134#issue-154443186) @@ -406,13 +434,18 @@ case class PropertiesGetResponseV1(properties: PropsGetV1) extends KnoraResponse /** * Requests the label of a resource to be changed. * - * @param resourceIri the IRI of the resource whose label should be changed. - * @param label the new value of the label. - * @param userADM the profile of the user making the request. - * @param apiRequestID the ID of the API request. + * @param resourceIri the IRI of the resource whose label should be changed. + * @param label the new value of the label. + * @param featureFactoryConfig the feature factory configuration. + * @param userADM the profile of the user making the request. + * @param apiRequestID the ID of the API request. * */ -case class ChangeResourceLabelRequestV1(resourceIri: IRI, label: String, userADM: UserADM, apiRequestID: UUID) extends ResourcesResponderRequestV1 +case class ChangeResourceLabelRequestV1(resourceIri: IRI, + label: String, + featureFactoryConfig: FeatureFactoryConfig, + userADM: UserADM, + apiRequestID: UUID) extends ResourcesResponderRequestV1 /** * Represents the answer to a [[ChangeResourceLabelRequestV1]]. diff --git a/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/standoffmessages/StandoffMessagesV1.scala b/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/standoffmessages/StandoffMessagesV1.scala index 23e4015408..d2030dbec4 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/standoffmessages/StandoffMessagesV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/standoffmessages/StandoffMessagesV1.scala @@ -23,6 +23,7 @@ import java.util.UUID import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport import org.knora.webapi.IRI +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.v1.responder.{KnoraRequestV1, KnoraResponseV1} import org.knora.webapi.messages.v1.responder.ontologymessages.StandoffEntityInfoGetResponseV1 @@ -39,12 +40,19 @@ sealed trait StandoffResponderRequestV1 extends KnoraRequestV1 * Represents a request to create a mapping between XML elements and attributes and standoff classes and properties. * A successful response will be a [[CreateMappingResponseV1]]. * - * @param xml the mapping in XML. - * @param projectIri the IRI of the project the mapping belongs to. - * @param mappingName the name of the mapping to be created. - * @param userProfile the profile of the user making the request. + * @param xml the mapping in XML. + * @param projectIri the IRI of the project the mapping belongs to. + * @param mappingName the name of the mapping to be created. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. */ -case class CreateMappingRequestV1(xml: String, label: String, projectIri: IRI, mappingName: String, userProfile: UserADM, apiRequestID: UUID) extends StandoffResponderRequestV1 +case class CreateMappingRequestV1(xml: String, + label: String, + projectIri: IRI, + mappingName: String, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM, + apiRequestID: UUID) extends StandoffResponderRequestV1 /** * Provides the IRI of the created mapping. @@ -59,9 +67,12 @@ case class CreateMappingResponseV1(mappingIri: IRI) extends KnoraResponseV1 { * Represents a request to get a mapping from XML elements and attributes to standoff entities. * * @param mappingIri the IRI of the mapping. + * @param featureFactoryConfig the feature factory configuration. * @param userProfile the profile of the user making the request. */ -case class GetMappingRequestV1(mappingIri: IRI, userProfile: UserADM) extends StandoffResponderRequestV1 +case class GetMappingRequestV1(mappingIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM) extends StandoffResponderRequestV1 /** * Represents a response to a [[GetMappingRequestV1]]. @@ -76,9 +87,12 @@ case class GetMappingResponseV1(mappingIri: IRI, mapping: MappingXMLtoStandoff, * Represents a request that gets an XSL Transformation represented by a `knora-base:XSLTransformation`. * * @param xsltTextRepresentationIri the IRI of the `knora-base:XSLTransformation`. + * @param featureFactoryConfig the feature factory configuration. * @param userProfile the profile of the user making the request. */ -case class GetXSLTransformationRequestV1(xsltTextRepresentationIri: IRI, userProfile: UserADM) extends StandoffResponderRequestV1 +case class GetXSLTransformationRequestV1(xsltTextRepresentationIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM) extends StandoffResponderRequestV1 /** * Represents a response to a [[GetXSLTransformationRequestV1]]. diff --git a/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/usermessages/UserMessagesV1.scala b/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/usermessages/UserMessagesV1.scala index d11a055602..65ec56d329 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/usermessages/UserMessagesV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/usermessages/UserMessagesV1.scala @@ -24,6 +24,7 @@ import java.util.UUID import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport import org.knora.webapi._ import org.knora.webapi.exceptions.{BadRequestException, InconsistentTriplestoreDataException} +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.admin.responder.permissionsmessages.{PermissionsADMJsonProtocol, PermissionsDataADM} import org.knora.webapi.messages.v1.responder.projectmessages.{ProjectInfoV1, ProjectV1JsonProtocol} import org.knora.webapi.messages.v1.responder.usermessages.UserProfileTypeV1.UserProfileType @@ -73,11 +74,13 @@ case class UserDataByIriGetV1(userIri: IRI, short: Boolean = true) extends Users /** * A message that requests a user's profile. A successful response will be a [[UserProfileResponseV1]]. * - * @param userIri the IRI of the user to be queried. - * @param userProfileType the extent of the information returned. + * @param userIri the IRI of the user to be queried. + * @param userProfileType the extent of the information returned. + * @param featureFactoryConfig the feature factory configuration. */ case class UserProfileByIRIGetRequestV1(userIri: IRI, userProfileType: UserProfileType, + featureFactoryConfig: FeatureFactoryConfig, userProfile: UserProfileV1) extends UsersResponderRequestV1 @@ -88,27 +91,32 @@ case class UserProfileByIRIGetRequestV1(userIri: IRI, * @param userProfileType the extent of the information returned. */ case class UserProfileByIRIGetV1(userIri: IRI, - userProfileType: UserProfileType) extends UsersResponderRequestV1 + userProfileType: UserProfileType, + featureFactoryConfig: FeatureFactoryConfig) extends UsersResponderRequestV1 /** * A message that requests a user's profile. A successful response will be a [[UserProfileResponseV1]]. * - * @param email the email of the user to be queried. - * @param userProfileType the extent of the information returned. - * @param userProfile the requesting user's profile. + * @param email the email of the user to be queried. + * @param userProfileType the extent of the information returned. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the requesting user's profile. */ case class UserProfileByEmailGetRequestV1(email: String, userProfileType: UserProfileType, + featureFactoryConfig: FeatureFactoryConfig, userProfile: UserProfileV1) extends UsersResponderRequestV1 /** * A message that requests a user's profile. A successful response will be a [[UserProfileV1]]. * - * @param email the email of the user to be queried. - * @param userProfileType the extent of the information returned. + * @param email the email of the user to be queried. + * @param userProfileType the extent of the information returned. + * @param featureFactoryConfig the feature factory configuration. */ case class UserProfileByEmailGetV1(email: String, - userProfileType: UserProfileType) extends UsersResponderRequestV1 + userProfileType: UserProfileType, + featureFactoryConfig: FeatureFactoryConfig) extends UsersResponderRequestV1 /** * Requests user's project memberships. diff --git a/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/valuemessages/ValueMessagesV1.scala b/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/valuemessages/ValueMessagesV1.scala index 15df9e08eb..9a5ae139aa 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/valuemessages/ValueMessagesV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/v1/responder/valuemessages/ValueMessagesV1.scala @@ -25,6 +25,7 @@ import java.util.UUID import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport import org.knora.webapi._ import org.knora.webapi.exceptions.{BadRequestException, InconsistentTriplestoreDataException, NotImplementedException} +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectADM import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.traits.Jsonable @@ -221,21 +222,29 @@ sealed trait ValuesResponderRequestV1 extends KnoraRequestV1 /** * Represents a request for a (current) value. A successful response will be a [[ValueGetResponseV1]]. * - * @param valueIri the IRI of the value requested. - * @param userProfile the profile of the user making the request. + * @param valueIri the IRI of the value requested. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. */ -case class ValueGetRequestV1(valueIri: IRI, userProfile: UserADM) extends ValuesResponderRequestV1 +case class ValueGetRequestV1(valueIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM) extends ValuesResponderRequestV1 /** * Represents a request for the details of a reification node describing a direct link between two resources. * A successful response will be a [[ValueGetResponseV1]] containing a [[LinkValueV1]]. * - * @param subjectIri the IRI of the resource that is the source of the link. - * @param predicateIri the IRI of the property that links the two resources. - * @param objectIri the IRI of the resource that is the target of the link. - * @param userProfile the profile of the user making the request. + * @param subjectIri the IRI of the resource that is the source of the link. + * @param predicateIri the IRI of the property that links the two resources. + * @param objectIri the IRI of the resource that is the target of the link. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. */ -case class LinkValueGetRequestV1(subjectIri: IRI, predicateIri: IRI, objectIri: IRI, userProfile: UserADM) extends ValuesResponderRequestV1 +case class LinkValueGetRequestV1(subjectIri: IRI, + predicateIri: IRI, + objectIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM) extends ValuesResponderRequestV1 /** * Provides details of a Knora value. A successful response will be a [[ValueGetResponseV1]]. @@ -284,19 +293,21 @@ case class ValueVersionHistoryGetResponseV1(valueVersions: Seq[ValueVersionV1]) * Represents a request to add a new value of a resource property (as opposed to a new version of an existing value). A * successful response will be an [[CreateValueResponseV1]]. * - * @param resourceIndex the index of the resource - * @param resourceIri the IRI of the resource to which the value should be added. - * @param propertyIri the IRI of the property that should receive the value. - * @param value the value to be added. - * @param comment an optional comment on the value. - * @param userProfile the profile of the user making the request. - * @param apiRequestID the ID of this API request. + * @param resourceIndex the index of the resource + * @param resourceIri the IRI of the resource to which the value should be added. + * @param propertyIri the IRI of the property that should receive the value. + * @param value the value to be added. + * @param comment an optional comment on the value. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. + * @param apiRequestID the ID of this API request. */ case class CreateValueRequestV1(resourceIndex: Int = 0, resourceIri: IRI, propertyIri: IRI, value: UpdateValueV1, comment: Option[String] = None, + featureFactoryConfig: FeatureFactoryConfig, userProfile: UserADM, apiRequestID: UUID) extends ValuesResponderRequestV1 @@ -328,13 +339,15 @@ case class UnverifiedValueV1(newValueIri: IRI, value: UpdateValueV1) /** * Requests verification that new values were created. * - * @param resourceIri the IRI of the resource in which the values should have been created. - * @param unverifiedValues a [[Map]] of property IRIs to [[UnverifiedValueV1]] objects - * describing the values that should have been created for each property. - * @param userProfile the profile of the user making the request. + * @param resourceIri the IRI of the resource in which the values should have been created. + * @param unverifiedValues a [[Map]] of property IRIs to [[UnverifiedValueV1]] objects + * describing the values that should have been created for each property. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. */ case class VerifyMultipleValueCreationRequestV1(resourceIri: IRI, unverifiedValues: Map[IRI, Seq[UnverifiedValueV1]], + featureFactoryConfig: FeatureFactoryConfig, userProfile: UserADM) extends ValuesResponderRequestV1 /** @@ -378,6 +391,7 @@ case class CreateValueV1WithComment(updateValueV1: UpdateValueV1, comment: Optio * @param clientResourceIDsToResourceIris a map of client resource IDs (which may appear in standoff link tags * in values) to the IRIs that will be used for those resources. * @param creationDate an xsd:dateTimeStamp that will be attached to the values. + * @param featureFactoryConfig the feature factory configuration. * @param userProfile the user that is creating the values. */ case class GenerateSparqlToCreateMultipleValuesRequestV1(projectIri: IRI, @@ -387,6 +401,7 @@ case class GenerateSparqlToCreateMultipleValuesRequestV1(projectIri: IRI, values: Map[IRI, Seq[CreateValueV1WithComment]], clientResourceIDsToResourceIris: Map[String, IRI], creationDate: Instant, + featureFactoryConfig: FeatureFactoryConfig, userProfile: UserADM, apiRequestID: UUID) extends ValuesResponderRequestV1 @@ -411,28 +426,32 @@ case class GenerateSparqlToCreateMultipleValuesResponseV1(insertSparql: String, * Represents a request to change the value of a property (by updating its version history). A successful response will * be a [[ChangeValueResponseV1]]. * - * @param valueIri the IRI of the current value. - * @param value the new value, or [[None]] if only the value's comment is being changed. - * @param comment an optional comment on the value. - * @param userProfile the profile of the user making the request. - * @param apiRequestID the ID of this API request. + * @param valueIri the IRI of the current value. + * @param value the new value, or [[None]] if only the value's comment is being changed. + * @param comment an optional comment on the value. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. + * @param apiRequestID the ID of this API request. */ case class ChangeValueRequestV1(valueIri: IRI, value: UpdateValueV1, comment: Option[String] = None, + featureFactoryConfig: FeatureFactoryConfig, userProfile: UserADM, apiRequestID: UUID) extends ValuesResponderRequestV1 /** * Represents a request to change the comment on a value. A successful response will be a [[ChangeValueResponseV1]]. * - * @param valueIri the IRI of the current value. - * @param comment the comment to be added to the new version of the value. - * @param userProfile the profile of the user making the request. - * @param apiRequestID the ID of this API request. + * @param valueIri the IRI of the current value. + * @param comment the comment to be added to the new version of the value. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. + * @param apiRequestID the ID of this API request. */ case class ChangeCommentRequestV1(valueIri: IRI, comment: Option[String], + featureFactoryConfig: FeatureFactoryConfig, userProfile: UserADM, apiRequestID: UUID) extends ValuesResponderRequestV1 @@ -453,13 +472,15 @@ case class ChangeValueResponseV1(value: ApiValueV1, /** * Represents a request to mark a value as deleted. * - * @param valueIri the IRI of the value to be marked as deleted. - * @param deleteComment an optional comment explaining why the value is being deleted. - * @param userProfile the profile of the user making the request. - * @param apiRequestID the ID of this API request. + * @param valueIri the IRI of the value to be marked as deleted. + * @param deleteComment an optional comment explaining why the value is being deleted. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. + * @param apiRequestID the ID of this API request. */ case class DeleteValueRequestV1(valueIri: IRI, deleteComment: Option[String] = None, + featureFactoryConfig: FeatureFactoryConfig, userProfile: UserADM, apiRequestID: UUID) extends ValuesResponderRequestV1 @@ -479,10 +500,15 @@ case class DeleteValueResponseV1(id: IRI) extends KnoraResponseV1 { * Represents a request to change (update) the file value(s) of a given resource. * In case of an image, two file valueshave to be changed: thumbnail and full quality. * - * @param resourceIri the resource whose files value(s) should be changed. - * @param file a file that has been uploaded to Sipi's temporary storage. + * @param resourceIri the resource whose files value(s) should be changed. + * @param file a file that has been uploaded to Sipi's temporary storage. + * @param featureFactoryConfig the feature factory configuration. */ -case class ChangeFileValueRequestV1(resourceIri: IRI, file: FileValueV1, apiRequestID: UUID, userProfile: UserADM) extends ValuesResponderRequestV1 +case class ChangeFileValueRequestV1(resourceIri: IRI, + file: FileValueV1, + apiRequestID: UUID, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM) extends ValuesResponderRequestV1 /** * Represents a response to a [[ChangeFileValueRequestV1]]. @@ -1638,7 +1664,7 @@ object ApiValueV1JsonProtocol extends SprayJsonSupport with DefaultJsonProtocol def write(calendarV1Value: KnoraCalendarV1.Value): JsValue = JsString(calendarV1Value.toString) } - /**å + /** å * Converts between [[KnoraPrecisionV1]] objects and [[JsValue]] objects. */ implicit object KnoraPrecisionV1JsonFormat extends JsonFormat[KnoraPrecisionV1.Value] { diff --git a/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/KnoraRequestV2.scala b/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/KnoraRequestV2.scala index f5d792be82..fd1aa38519 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/KnoraRequestV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/KnoraRequestV2.scala @@ -19,15 +19,14 @@ package org.knora.webapi.messages.v2.responder -import java.io.StringWriter import java.util.UUID import akka.actor.ActorRef import akka.event.LoggingAdapter import akka.util.Timeout -import org.apache.jena +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.admin.responder.usersmessages.UserADM -import org.knora.webapi.messages.util.JsonLDDocument +import org.knora.webapi.messages.util.rdf.{JsonLDDocument, RdfFeatureFactory, RdfModel, Turtle} import org.knora.webapi.settings.KnoraSettingsImpl import scala.concurrent.{ExecutionContext, Future} @@ -38,21 +37,19 @@ import scala.concurrent.{ExecutionContext, Future} trait KnoraRequestV2 /** - * A trait for request messages that are constructed as a [[jena.graph.Graph]]. + * A trait for request messages that are constructed as an [[RdfModel]]. */ -trait KnoraGraphRequestV2 { +trait KnoraRdfModelRequestV2 { /** - * A [[jena.graph.Graph]] representing the request. + * An [[RdfModel]] representing the request. */ - val graph: jena.graph.Graph + val rdfModel: RdfModel /** * Returns a Turtle representation of the graph. */ - def toTurtle: String = { - val stringWriter = new StringWriter - jena.riot.RDFDataMgr.write(stringWriter, graph, jena.riot.Lang.TURTLE) - stringWriter.toString + def toTurtle(featureFactoryConfig: FeatureFactoryConfig): String = { + RdfFeatureFactory.getRdfFormatUtil(featureFactoryConfig).format(rdfModel, Turtle) } } @@ -65,15 +62,14 @@ trait KnoraJsonLDRequestReaderV2[C] { /** * Converts JSON-LD input into a case class instance. * - * @param jsonLDDocument the JSON-LD input. - * @param apiRequestID the UUID of the API request. - * @param requestingUser the user making the request. - * @param responderManager a reference to the responder manager. - * @param storeManager a reference to the store manager. - * @param settings the application settings. - * @param log a logging adapter. - * @param timeout a timeout for `ask` messages. - * @param executionContext an execution context for futures. + * @param jsonLDDocument the JSON-LD input. + * @param apiRequestID the UUID of the API request. + * @param requestingUser the user making the request. + * @param responderManager a reference to the responder manager. + * @param storeManager a reference to the store manager. + * @param featureFactoryConfig the feature factory configuration. + * @param settings the application settings. + * @param log a logging adapter. * @return a case class instance representing the input. */ def fromJsonLD(jsonLDDocument: JsonLDDocument, @@ -81,6 +77,7 @@ trait KnoraJsonLDRequestReaderV2[C] { requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[C] } diff --git a/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/KnoraResponseV2.scala b/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/KnoraResponseV2.scala index 4e0e50020f..add2c7a960 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/KnoraResponseV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/KnoraResponseV2.scala @@ -19,15 +19,12 @@ package org.knora.webapi.messages.v2.responder -import java.io.StringReader - -import akka.http.scaladsl.model.MediaType -import org.eclipse.rdf4j import org.knora.webapi._ import org.knora.webapi.exceptions.AssertionException +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.OntologyConstants import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectADM -import org.knora.webapi.messages.util.{JsonLDDocument, JsonLDObject, JsonLDString, RdfFormatUtil} +import org.knora.webapi.messages.util.rdf._ import org.knora.webapi.settings.KnoraSettingsImpl @@ -38,15 +35,17 @@ trait KnoraResponseV2 { /** * Returns this response message in the requested format. * - * @param mediaType the specific media type selected for the response. - * @param targetSchema the response schema. - * @param schemaOptions the schema options. - * @param settings the application settings. + * @param rdfFormat the RDF format selected for the response. + * @param targetSchema the response schema. + * @param schemaOptions the schema options. + * @param settings the application settings. + * @param featureFactoryConfig the feature factory configuration. * @return a formatted string representing this response message. */ - def format(mediaType: MediaType.NonBinary, + def format(rdfFormat: RdfFormat, targetSchema: OntologySchema, schemaOptions: Set[SchemaOption], + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl): String } @@ -55,9 +54,10 @@ trait KnoraResponseV2 { */ trait KnoraJsonLDResponseV2 extends KnoraResponseV2 { - override def format(mediaType: MediaType.NonBinary, + override def format(rdfFormat: RdfFormat, targetSchema: OntologySchema, schemaOptions: Set[SchemaOption], + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl): String = { val targetApiV2Schema = targetSchema match { case apiV2Schema: ApiV2Schema => apiV2Schema @@ -72,17 +72,20 @@ trait KnoraJsonLDResponseV2 extends KnoraResponseV2 { ) // Which response format was requested? - mediaType match { - case RdfMediaTypes.`application/ld+json` => - // JSON-LD. Convert the document to a string in JSON-LD format. + rdfFormat match { + case JsonLD => + // JSON-LD. Use the JsonLDDocument to generate the formatted text. jsonLDDocument.toPrettyString - case _ => - // Some other format. Convert the document to an RDF4J Model, - // and return the model in the requested format. - RdfFormatUtil.formatRDF4JModel( - model = jsonLDDocument.toRDF4JModel, - mediaType = mediaType + case nonJsonLD: NonJsonLD => + // Some other format. Convert the JSON-LD document to an RDF model. + val rdfFormatUtil: RdfFormatUtil = RdfFeatureFactory.getRdfFormatUtil(featureFactoryConfig) + val rdfModel: RdfModel = jsonLDDocument.toRdfModel(rdfFormatUtil.getRdfModelFactory) + + // Convert the model to the requested format. + rdfFormatUtil.format( + rdfModel = rdfModel, + rdfFormat = nonJsonLD ) } } @@ -106,28 +109,30 @@ trait KnoraTurtleResponseV2 extends KnoraResponseV2 { */ protected val turtle: String - override def format(mediaType: MediaType.NonBinary, + override def format(rdfFormat: RdfFormat, targetSchema: OntologySchema, schemaOptions: Set[SchemaOption], + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl): String = { if (targetSchema != InternalSchema) { throw AssertionException(s"Response can be returned only in the internal schema") } // Which response format was requested? - mediaType match { - case RdfMediaTypes.`text/turtle` => + rdfFormat match { + case Turtle => // Turtle. Return the Turtle string as is. turtle case _ => - // Some other format. Parse the Turtle to an RDF4J Model. - val model = rdf4j.rio.Rio.parse(new StringReader(turtle), "", rdf4j.rio.RDFFormat.TURTLE, null) + // Some other format. Parse the Turtle to an RdfModel. + val rdfFormatUtil: RdfFormatUtil = RdfFeatureFactory.getRdfFormatUtil(featureFactoryConfig) + val rdfModel: RdfModel = rdfFormatUtil.parseToRdfModel(rdfStr = turtle, rdfFormat = Turtle) // Return the model in the requested format. - RdfFormatUtil.formatRDF4JModel( - model = model, - mediaType = mediaType + rdfFormatUtil.format( + rdfModel = rdfModel, + rdfFormat = rdfFormat ) } } diff --git a/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/listsmessages/ListsMessagesV2.scala b/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/listsmessages/ListsMessagesV2.scala index 314e3962a5..b3891ec619 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/listsmessages/ListsMessagesV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/listsmessages/ListsMessagesV2.scala @@ -19,12 +19,14 @@ package org.knora.webapi.messages.v2.responder.listsmessages +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.admin.responder.listsmessages._ import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.store.triplestoremessages.StringLiteralSequenceV2 -import org.knora.webapi.messages.util._ -import org.knora.webapi.messages.v2.responder.{KnoraRequestV2, KnoraJsonLDResponseV2} +import org.knora.webapi.messages.util.{rdf, _} +import org.knora.webapi.messages.util.rdf.{JsonLDArray, JsonLDBoolean, JsonLDDocument, JsonLDInt, JsonLDObject, JsonLDString, JsonLDUtil} +import org.knora.webapi.messages.v2.responder.{KnoraJsonLDResponseV2, KnoraRequestV2} import org.knora.webapi.messages.{OntologyConstants, StringFormatter} import org.knora.webapi.settings.KnoraSettingsImpl import org.knora.webapi.{messages, _} @@ -38,10 +40,12 @@ sealed trait ListsResponderRequestV2 extends KnoraRequestV2 /** * Requests a list. A successful response will be a [[ListGetResponseV2]] * - * @param listIri the IRI of the list (Iri of the list's root node). - * @param requestingUser the user making the request. + * @param listIri the IRI of the list (Iri of the list's root node). + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ case class ListGetRequestV2(listIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends ListsResponderRequestV2 @@ -112,7 +116,7 @@ case class ListGetResponseV2(list: ListADM, userLang: String, fallbackLang: Stri OntologyConstants.KnoraBase.HasRootNode.toSmartIri.toOntologySchema(ApiV2Complex).toString -> JsonLDUtil.iriToJsonLDObject(node.hasRootNode) ) - messages.util.JsonLDObject( + JsonLDObject( Map( "@id" -> JsonLDString(node.id), "@type" -> JsonLDString(OntologyConstants.KnoraBase.ListNode.toSmartIri.toOntologySchema(ApiV2Complex).toString) @@ -139,7 +143,7 @@ case class ListGetResponseV2(list: ListADM, userLang: String, fallbackLang: Stri OntologyConstants.KnoraBase.AttachedToProject.toSmartIri.toOntologySchema(ApiV2Complex).toString -> JsonLDUtil.iriToJsonLDObject(listinfo.projectIri) ) - val body = messages.util.JsonLDObject(Map( + val body = rdf.JsonLDObject(Map( "@id" -> JsonLDString(listinfo.id), "@type" -> JsonLDString(OntologyConstants.KnoraBase.ListNode.toSmartIri.toOntologySchema(ApiV2Complex).toString), OntologyConstants.KnoraBase.IsRootNode.toSmartIri.toOntologySchema(ApiV2Complex).toString -> JsonLDBoolean(true) @@ -160,9 +164,11 @@ case class ListGetResponseV2(list: ListADM, userLang: String, fallbackLang: Stri /** * Requests a list node. A successful response will be a [[NodeGetResponseV2]] * - * @param nodeIri the IRI of the node to retrieve. + * @param nodeIri the IRI of the node to retrieve. + * @param featureFactoryConfig the feature factory configuration. */ case class NodeGetRequestV2(nodeIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends ListsResponderRequestV2 /** diff --git a/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/metadatamessages/MetadataMessagesV2.scala b/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/metadatamessages/MetadataMessagesV2.scala index cda1f59f01..1d7d33f4f1 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/metadatamessages/MetadataMessagesV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/metadatamessages/MetadataMessagesV2.scala @@ -21,12 +21,13 @@ package org.knora.webapi.messages.v2.responder.metadatamessages import java.util.UUID -import org.apache.jena import org.knora.webapi.IRI import org.knora.webapi.exceptions.{BadRequestException, ForbiddenException} +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.OntologyConstants import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectADM import org.knora.webapi.messages.admin.responder.usersmessages.UserADM +import org.knora.webapi.messages.util.rdf.RdfModel import org.knora.webapi.messages.v2.responder._ /** @@ -42,10 +43,12 @@ sealed trait MetadataResponderRequestV2 extends KnoraRequestV2 { /** * Requests metadata about a project. A successful response will be a [[MetadataGetResponseV2]]. * - * @param projectADM the project for which metadata is requested. - * @param requestingUser the user making the request. + * @param projectADM the project for which metadata is requested. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ case class MetadataGetRequestV2(projectADM: ProjectADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends MetadataResponderRequestV2 { val projectIri: IRI = projectADM.id @@ -67,15 +70,17 @@ case class MetadataGetResponseV2(turtle: String) extends KnoraTurtleResponseV2 * for the project, it will be replaced by the metadata in this message. A successful response * will be a [[SuccessResponseV2]]. * - * @param graph the project metadata to be stored. - * @param projectADM the project. - * @param requestingUser the user making the request. - * @param apiRequestID the API request ID. + * @param rdfModel the project metadata to be stored. + * @param projectADM the project. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. + * @param apiRequestID the API request ID. */ -case class MetadataPutRequestV2(graph: jena.graph.Graph, +case class MetadataPutRequestV2(rdfModel: RdfModel, projectADM: ProjectADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, - apiRequestID: UUID) extends KnoraGraphRequestV2 with MetadataResponderRequestV2 { + apiRequestID: UUID) extends KnoraRdfModelRequestV2 with MetadataResponderRequestV2 { /** * The project IRI. */ @@ -91,5 +96,9 @@ case class MetadataPutRequestV2(graph: jena.graph.Graph, if (projectIri == OntologyConstants.KnoraAdmin.SystemProject || projectIri == OntologyConstants.KnoraAdmin.DefaultSharedOntologiesProject) { throw BadRequestException(s"Metadata cannot be created in project <$projectIri>") } -} + // Don't allow named graphs. + if (rdfModel.getContexts.nonEmpty) { + throw BadRequestException("A project metadata request cannot contain named graphs") + } +} 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 49e12765a8..c6ffd72242 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 @@ -19,7 +19,6 @@ package org.knora.webapi.messages.v2.responder.ontologymessages -import java.io import java.time.Instant import java.util.UUID @@ -27,17 +26,18 @@ import akka.actor.ActorRef import akka.event.LoggingAdapter import akka.util.Timeout import org.apache.commons.lang3.builder.HashCodeBuilder +import org.knora.webapi._ import org.knora.webapi.exceptions.{AssertionException, BadRequestException, DataConversionException, InconsistentTriplestoreDataException} +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.store.triplestoremessages._ -import org.knora.webapi.messages.util._ +import org.knora.webapi.messages.util.rdf._ import org.knora.webapi.messages.v2.responder._ import org.knora.webapi.messages.v2.responder.ontologymessages.Cardinality.{KnoraCardinalityInfo, OwlCardinalityInfo} import org.knora.webapi.messages.v2.responder.standoffmessages.StandoffDataTypeClasses import org.knora.webapi.messages.{OntologyConstants, SmartIri, StringFormatter} import org.knora.webapi.settings.KnoraSettingsImpl -import org.knora.webapi.{messages, _} import scala.concurrent.{ExecutionContext, Future} @@ -53,20 +53,23 @@ sealed trait OntologiesResponderRequestV2 extends KnoraRequestV2 { * Requests that all ontologies in the repository are loaded. This message must be sent only once, when the application * starts, before it accepts any API requests. A successful response will be a [[SuccessResponseV2]]. * - * @param requestingUser the user making the request. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ -case class LoadOntologiesRequestV2(requestingUser: UserADM) extends OntologiesResponderRequestV2 +case class LoadOntologiesRequestV2(featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM) extends OntologiesResponderRequestV2 /** * Requests the creation of an empty ontology. A successful response will be a [[ReadOntologyV2]]. * - * @param ontologyName the name of the ontology to be created. - * @param projectIri the IRI of the project that the ontology will belong to. - * @param isShared the flag that shows if an ontology is a shared one. - * @param label the label of the ontology. - * @param comment the optional comment that described the ontology to be created. - * @param apiRequestID the ID of the API request. - * @param requestingUser the user making the request. + * @param ontologyName the name of the ontology to be created. + * @param projectIri the IRI of the project that the ontology will belong to. + * @param isShared the flag that shows if an ontology is a shared one. + * @param label the label of the ontology. + * @param comment the optional comment that described the ontology to be created. + * @param apiRequestID the ID of the API request. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ case class CreateOntologyRequestV2(ontologyName: String, projectIri: SmartIri, @@ -74,6 +77,7 @@ case class CreateOntologyRequestV2(ontologyName: String, label: String, comment: Option[String] = None, apiRequestID: UUID, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends OntologiesResponderRequestV2 /** @@ -83,14 +87,14 @@ object CreateOntologyRequestV2 extends KnoraJsonLDRequestReaderV2[CreateOntology /** * Converts JSON-LD input into a [[CreateOntologyRequestV2]]. * - * @param jsonLDDocument the JSON-LD input. - * @param apiRequestID the UUID of the API request. - * @param requestingUser the user making the request. - * @param responderManager a reference to the responder manager. - * @param storeManager a reference to the store manager. - * @param log a logging adapter. - * @param timeout a timeout for `ask` messages. - * @param executionContext an execution context for futures. + * @param jsonLDDocument the JSON-LD input. + * @param apiRequestID the UUID of the API request. + * @param requestingUser the user making the request. + * @param responderManager a reference to the responder manager. + * @param storeManager a reference to the store manager. + * @param featureFactoryConfig the feature factory configuration. + * @param settings the application settings. + * @param log a logging adapter. * @return a [[CreateOntologyRequestV2]] representing the input. */ override def fromJsonLD(jsonLDDocument: JsonLDDocument, @@ -98,12 +102,14 @@ object CreateOntologyRequestV2 extends KnoraJsonLDRequestReaderV2[CreateOntology requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[CreateOntologyRequestV2] = { Future { fromJsonLDSync( jsonLDDocument = jsonLDDocument, apiRequestID = apiRequestID, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) } @@ -111,6 +117,7 @@ object CreateOntologyRequestV2 extends KnoraJsonLDRequestReaderV2[CreateOntology private def fromJsonLDSync(jsonLDDocument: JsonLDDocument, apiRequestID: UUID, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM): CreateOntologyRequestV2 = { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance @@ -127,6 +134,7 @@ object CreateOntologyRequestV2 extends KnoraJsonLDRequestReaderV2[CreateOntology label = label, comment = comment, apiRequestID = apiRequestID, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) } @@ -143,6 +151,7 @@ object CreateOntologyRequestV2 extends KnoraJsonLDRequestReaderV2[CreateOntology case class DeleteOntologyRequestV2(ontologyIri: SmartIri, lastModificationDate: Instant, apiRequestID: UUID, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends OntologiesResponderRequestV2 /** @@ -348,6 +357,7 @@ object OntologyUpdateHelper { case class CreatePropertyRequestV2(propertyInfoContent: PropertyInfoContentV2, lastModificationDate: Instant, apiRequestID: UUID, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends OntologiesResponderRequestV2 /** @@ -357,14 +367,14 @@ object CreatePropertyRequestV2 extends KnoraJsonLDRequestReaderV2[CreateProperty /** * Converts a JSON-LD request to a [[CreatePropertyRequestV2]]. * - * @param jsonLDDocument the JSON-LD input. - * @param apiRequestID the UUID of the API request. - * @param requestingUser the user making the request. - * @param responderManager a reference to the responder manager. - * @param storeManager a reference to the store manager. - * @param log a logging adapter. - * @param timeout a timeout for `ask` messages. - * @param executionContext an execution context for futures. + * @param jsonLDDocument the JSON-LD input. + * @param apiRequestID the UUID of the API request. + * @param requestingUser the user making the request. + * @param responderManager a reference to the responder manager. + * @param storeManager a reference to the store manager. + * @param featureFactoryConfig the feature factory configuration. + * @param settings the application settings. + * @param log a logging adapter. * @return a [[CreatePropertyRequestV2]] representing the input. */ override def fromJsonLD(jsonLDDocument: JsonLDDocument, @@ -372,12 +382,14 @@ object CreatePropertyRequestV2 extends KnoraJsonLDRequestReaderV2[CreateProperty requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[CreatePropertyRequestV2] = { Future { fromJsonLDSync( jsonLDDocument = jsonLDDocument, apiRequestID = apiRequestID, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) } @@ -385,6 +397,7 @@ object CreatePropertyRequestV2 extends KnoraJsonLDRequestReaderV2[CreateProperty private def fromJsonLDSync(jsonLDDocument: JsonLDDocument, apiRequestID: UUID, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM): CreatePropertyRequestV2 = { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance @@ -426,6 +439,7 @@ object CreatePropertyRequestV2 extends KnoraJsonLDRequestReaderV2[CreateProperty propertyInfoContent = propertyInfoContent, lastModificationDate = lastModificationDate, apiRequestID = apiRequestID, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) } @@ -442,6 +456,7 @@ object CreatePropertyRequestV2 extends KnoraJsonLDRequestReaderV2[CreateProperty case class CreateClassRequestV2(classInfoContent: ClassInfoContentV2, lastModificationDate: Instant, apiRequestID: UUID, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends OntologiesResponderRequestV2 /** @@ -451,33 +466,36 @@ object CreateClassRequestV2 extends KnoraJsonLDRequestReaderV2[CreateClassReques /** * Converts a JSON-LD request to a [[CreateClassRequestV2]]. * - * @param jsonLDDocument the JSON-LD input. - * @param apiRequestID the UUID of the API request. - * @param requestingUser the user making the request. - * @param responderManager a reference to the responder manager. - * @param storeManager a reference to the store manager. - * @param log a logging adapter. - * @param timeout a timeout for `ask` messages. - * @param executionContext an execution context for futures. + * @param jsonLDDocument the JSON-LD input. + * @param apiRequestID the UUID of the API request. + * @param requestingUser the user making the request. + * @param responderManager a reference to the responder manager. + * @param storeManager a reference to the store manager. + * @param featureFactoryConfig the feature factory configuration. + * @param settings the application settings. + * @param log a logging adapter. * @return a [[CreateClassRequestV2]] representing the input. */ override def fromJsonLD(jsonLDDocument: JsonLDDocument, apiRequestID: UUID, requestingUser: UserADM, - storeManager: ActorRef, responderManager: ActorRef, + storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[CreateClassRequestV2] = { Future { fromJsonLDSync( jsonLDDocument = jsonLDDocument, apiRequestID = apiRequestID, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) } } - private def fromJsonLDSync(jsonLDDocument: JsonLDDocument, apiRequestID: UUID, requestingUser: UserADM): CreateClassRequestV2 = { + private def fromJsonLDSync(jsonLDDocument: JsonLDDocument, apiRequestID: UUID, featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): CreateClassRequestV2 = { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance // Get the class definition and the ontology's last modification date from the JSON-LD. @@ -501,6 +519,7 @@ object CreateClassRequestV2 extends KnoraJsonLDRequestReaderV2[CreateClassReques classInfoContent = classInfoContent, lastModificationDate = lastModificationDate, apiRequestID = apiRequestID, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) } @@ -517,6 +536,7 @@ object CreateClassRequestV2 extends KnoraJsonLDRequestReaderV2[CreateClassReques case class AddCardinalitiesToClassRequestV2(classInfoContent: ClassInfoContentV2, lastModificationDate: Instant, apiRequestID: UUID, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends OntologiesResponderRequestV2 /** @@ -526,14 +546,14 @@ object AddCardinalitiesToClassRequestV2 extends KnoraJsonLDRequestReaderV2[AddCa /** * Converts JSON-LD input into an [[AddCardinalitiesToClassRequestV2]]. * - * @param jsonLDDocument the JSON-LD input. - * @param apiRequestID the UUID of the API request. - * @param requestingUser the user making the request. - * @param responderManager a reference to the responder manager. - * @param storeManager a reference to the store manager. - * @param log a logging adapter. - * @param timeout a timeout for `ask` messages. - * @param executionContext an execution context for futures. + * @param jsonLDDocument the JSON-LD input. + * @param apiRequestID the UUID of the API request. + * @param requestingUser the user making the request. + * @param responderManager a reference to the responder manager. + * @param storeManager a reference to the store manager. + * @param featureFactoryConfig the feature factory configuration. + * @param settings the application settings. + * @param log a logging adapter. * @return an [[AddCardinalitiesToClassRequestV2]] representing the input. */ override def fromJsonLD(jsonLDDocument: JsonLDDocument, @@ -541,18 +561,21 @@ object AddCardinalitiesToClassRequestV2 extends KnoraJsonLDRequestReaderV2[AddCa requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[AddCardinalitiesToClassRequestV2] = { Future { fromJsonLDSync( jsonLDDocument = jsonLDDocument, apiRequestID = apiRequestID, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) } } - private def fromJsonLDSync(jsonLDDocument: JsonLDDocument, apiRequestID: UUID, requestingUser: UserADM): AddCardinalitiesToClassRequestV2 = { + private def fromJsonLDSync(jsonLDDocument: JsonLDDocument, apiRequestID: UUID, featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): AddCardinalitiesToClassRequestV2 = { // Get the class definition and the ontology's last modification date from the JSON-LD. val inputOntologiesV2 = InputOntologyV2.fromJsonLD(jsonLDDocument) @@ -570,6 +593,7 @@ object AddCardinalitiesToClassRequestV2 extends KnoraJsonLDRequestReaderV2[AddCa classInfoContent = classInfoContent, lastModificationDate = lastModificationDate, apiRequestID = apiRequestID, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) } @@ -586,6 +610,7 @@ object AddCardinalitiesToClassRequestV2 extends KnoraJsonLDRequestReaderV2[AddCa case class ChangeCardinalitiesRequestV2(classInfoContent: ClassInfoContentV2, lastModificationDate: Instant, apiRequestID: UUID, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends OntologiesResponderRequestV2 /** @@ -595,14 +620,14 @@ object ChangeCardinalitiesRequestV2 extends KnoraJsonLDRequestReaderV2[ChangeCar /** * Converts JSON-LD input into a [[ChangeCardinalitiesRequestV2]]. * - * @param jsonLDDocument the JSON-LD input. - * @param apiRequestID the UUID of the API request. - * @param requestingUser the user making the request. - * @param responderManager a reference to the responder manager. - * @param storeManager a reference to the store manager. - * @param log a logging adapter. - * @param timeout a timeout for `ask` messages. - * @param executionContext an execution context for futures. + * @param jsonLDDocument the JSON-LD input. + * @param apiRequestID the UUID of the API request. + * @param requestingUser the user making the request. + * @param responderManager a reference to the responder manager. + * @param storeManager a reference to the store manager. + * @param featureFactoryConfig the feature factory configuration. + * @param settings the application settings. + * @param log a logging adapter. * @return a [[ChangeCardinalitiesRequestV2]] representing the input. */ override def fromJsonLD(jsonLDDocument: JsonLDDocument, @@ -610,18 +635,21 @@ object ChangeCardinalitiesRequestV2 extends KnoraJsonLDRequestReaderV2[ChangeCar requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[ChangeCardinalitiesRequestV2] = { Future { fromJsonLDSync( jsonLDDocument = jsonLDDocument, apiRequestID = apiRequestID, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) } } - private def fromJsonLDSync(jsonLDDocument: JsonLDDocument, apiRequestID: UUID, requestingUser: UserADM): ChangeCardinalitiesRequestV2 = { + private def fromJsonLDSync(jsonLDDocument: JsonLDDocument, apiRequestID: UUID, featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): ChangeCardinalitiesRequestV2 = { val inputOntologiesV2 = InputOntologyV2.fromJsonLD(jsonLDDocument) val classUpdateInfo = OntologyUpdateHelper.getClassDef(inputOntologiesV2) val classInfoContent = classUpdateInfo.classInfoContent @@ -631,6 +659,7 @@ object ChangeCardinalitiesRequestV2 extends KnoraJsonLDRequestReaderV2[ChangeCar classInfoContent = classInfoContent, lastModificationDate = lastModificationDate, apiRequestID = apiRequestID, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) } @@ -647,6 +676,7 @@ object ChangeCardinalitiesRequestV2 extends KnoraJsonLDRequestReaderV2[ChangeCar case class DeleteClassRequestV2(classIri: SmartIri, lastModificationDate: Instant, apiRequestID: UUID, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends OntologiesResponderRequestV2 /** @@ -660,6 +690,7 @@ case class DeleteClassRequestV2(classIri: SmartIri, case class DeletePropertyRequestV2(propertyIri: SmartIri, lastModificationDate: Instant, apiRequestID: UUID, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends OntologiesResponderRequestV2 /** @@ -692,6 +723,7 @@ case class ChangePropertyLabelsOrCommentsRequestV2(propertyIri: SmartIri, newObjects: Seq[StringLiteralV2], lastModificationDate: Instant, apiRequestID: UUID, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends OntologiesResponderRequestV2 with ChangeLabelsOrCommentsRequest /** @@ -703,14 +735,14 @@ object ChangePropertyLabelsOrCommentsRequestV2 extends KnoraJsonLDRequestReaderV /** * Converts a JSON-LD request to a [[ChangePropertyLabelsOrCommentsRequestV2]]. * - * @param jsonLDDocument the JSON-LD input. - * @param apiRequestID the UUID of the API request. - * @param requestingUser the user making the request. - * @param responderManager a reference to the responder manager. - * @param storeManager a reference to the store manager. - * @param log a logging adapter. - * @param timeout a timeout for `ask` messages. - * @param executionContext an execution context for futures. + * @param jsonLDDocument the JSON-LD input. + * @param apiRequestID the UUID of the API request. + * @param requestingUser the user making the request. + * @param responderManager a reference to the responder manager. + * @param storeManager a reference to the store manager. + * @param featureFactoryConfig the feature factory configuration. + * @param settings the application settings. + * @param log a logging adapter. * @return a [[ChangePropertyLabelsOrCommentsRequestV2]] representing the input. */ override def fromJsonLD(jsonLDDocument: JsonLDDocument, @@ -718,12 +750,14 @@ object ChangePropertyLabelsOrCommentsRequestV2 extends KnoraJsonLDRequestReaderV requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[ChangePropertyLabelsOrCommentsRequestV2] = { Future { fromJsonLDSync( jsonLDDocument = jsonLDDocument, apiRequestID = apiRequestID, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) } @@ -731,6 +765,7 @@ object ChangePropertyLabelsOrCommentsRequestV2 extends KnoraJsonLDRequestReaderV private def fromJsonLDSync(jsonLDDocument: JsonLDDocument, apiRequestID: UUID, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM): ChangePropertyLabelsOrCommentsRequestV2 = { val inputOntologiesV2 = InputOntologyV2.fromJsonLD(jsonLDDocument) val propertyUpdateInfo = OntologyUpdateHelper.getPropertyDef(inputOntologiesV2) @@ -746,6 +781,7 @@ object ChangePropertyLabelsOrCommentsRequestV2 extends KnoraJsonLDRequestReaderV }, lastModificationDate = lastModificationDate, apiRequestID = apiRequestID, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) } @@ -766,6 +802,7 @@ case class ChangeClassLabelsOrCommentsRequestV2(classIri: SmartIri, newObjects: Seq[StringLiteralV2], lastModificationDate: Instant, apiRequestID: UUID, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends OntologiesResponderRequestV2 with ChangeLabelsOrCommentsRequest /** @@ -775,14 +812,14 @@ object ChangeClassLabelsOrCommentsRequestV2 extends KnoraJsonLDRequestReaderV2[C /** * Converts a JSON-LD request to a [[ChangeClassLabelsOrCommentsRequestV2]]. * - * @param jsonLDDocument the JSON-LD input. - * @param apiRequestID the UUID of the API request. - * @param requestingUser the user making the request. - * @param responderManager a reference to the responder manager. - * @param storeManager a reference to the store manager. - * @param log a logging adapter. - * @param timeout a timeout for `ask` messages. - * @param executionContext an execution context for futures. + * @param jsonLDDocument the JSON-LD input. + * @param apiRequestID the UUID of the API request. + * @param requestingUser the user making the request. + * @param responderManager a reference to the responder manager. + * @param storeManager a reference to the store manager. + * @param featureFactoryConfig the feature factory configuration. + * @param settings the application settings. + * @param log a logging adapter. * @return a [[ChangeClassLabelsOrCommentsRequestV2]] representing the input. */ override def fromJsonLD(jsonLDDocument: JsonLDDocument, @@ -790,12 +827,14 @@ object ChangeClassLabelsOrCommentsRequestV2 extends KnoraJsonLDRequestReaderV2[C requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[ChangeClassLabelsOrCommentsRequestV2] = { Future { fromJsonLDSync( jsonLDDocument = jsonLDDocument, apiRequestID = apiRequestID, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) } @@ -803,6 +842,7 @@ object ChangeClassLabelsOrCommentsRequestV2 extends KnoraJsonLDRequestReaderV2[C private def fromJsonLDSync(jsonLDDocument: JsonLDDocument, apiRequestID: UUID, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM): ChangeClassLabelsOrCommentsRequestV2 = { val inputOntologiesV2 = InputOntologyV2.fromJsonLD(jsonLDDocument) val classUpdateInfo = OntologyUpdateHelper.getClassDef(inputOntologiesV2) @@ -818,6 +858,7 @@ object ChangeClassLabelsOrCommentsRequestV2 extends KnoraJsonLDRequestReaderV2[C }, lastModificationDate = lastModificationDate, apiRequestID = apiRequestID, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) } @@ -838,6 +879,7 @@ case class ChangeOntologyMetadataRequestV2(ontologyIri: SmartIri, comment: Option[String] = None, lastModificationDate: Instant, apiRequestID: UUID, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends OntologiesResponderRequestV2 /** @@ -847,14 +889,14 @@ object ChangeOntologyMetadataRequestV2 extends KnoraJsonLDRequestReaderV2[Change /** * Converts a JSON-LD request to a [[ChangeOntologyMetadataRequestV2]]. * - * @param jsonLDDocument the JSON-LD input. - * @param apiRequestID the UUID of the API request. - * @param requestingUser the user making the request. - * @param responderManager a reference to the responder manager. - * @param storeManager a reference to the store manager. - * @param log a logging adapter. - * @param timeout a timeout for `ask` messages. - * @param executionContext an execution context for futures. + * @param jsonLDDocument the JSON-LD input. + * @param apiRequestID the UUID of the API request. + * @param requestingUser the user making the request. + * @param responderManager a reference to the responder manager. + * @param storeManager a reference to the store manager. + * @param featureFactoryConfig the feature factory configuration. + * @param settings the application settings. + * @param log a logging adapter. * @return a [[ChangeClassLabelsOrCommentsRequestV2]] representing the input. */ override def fromJsonLD(jsonLDDocument: JsonLDDocument, @@ -862,12 +904,14 @@ object ChangeOntologyMetadataRequestV2 extends KnoraJsonLDRequestReaderV2[Change requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[ChangeOntologyMetadataRequestV2] = { Future { fromJsonLDSync( jsonLDDocument = jsonLDDocument, apiRequestID = apiRequestID, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) } @@ -875,6 +919,7 @@ object ChangeOntologyMetadataRequestV2 extends KnoraJsonLDRequestReaderV2[Change private def fromJsonLDSync(jsonLDDocument: JsonLDDocument, apiRequestID: UUID, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM): ChangeOntologyMetadataRequestV2 = { val inputOntologyV2 = InputOntologyV2.fromJsonLD(jsonLDDocument) val inputMetadata = inputOntologyV2.ontologyMetadata @@ -889,6 +934,7 @@ object ChangeOntologyMetadataRequestV2 extends KnoraJsonLDRequestReaderV2[Change comment = comment, lastModificationDate = lastModificationDate, apiRequestID = apiRequestID, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) } @@ -898,11 +944,13 @@ object ChangeOntologyMetadataRequestV2 extends KnoraJsonLDRequestReaderV2[Change * Requests all available information about a list of ontology entities (classes and/or properties). A successful response will be an * [[EntityInfoGetResponseV2]]. * - * @param classIris the IRIs of the class entities to be queried. - * @param propertyIris the IRIs of the property entities to be queried. - * @param requestingUser the user making the request. + * @param classIris the IRIs of the class entities to be queried. + * @param propertyIris the IRIs of the property entities to be queried. + * @param requestingUser the user making the request. */ -case class EntityInfoGetRequestV2(classIris: Set[SmartIri] = Set.empty[SmartIri], propertyIris: Set[SmartIri] = Set.empty[SmartIri], requestingUser: UserADM) extends OntologiesResponderRequestV2 +case class EntityInfoGetRequestV2(classIris: Set[SmartIri] = Set.empty[SmartIri], + propertyIris: Set[SmartIri] = Set.empty[SmartIri], + requestingUser: UserADM) extends OntologiesResponderRequestV2 /** * Represents assertions about one or more ontology entities (resource classes and/or properties). @@ -921,7 +969,9 @@ case class EntityInfoGetResponseV2(classInfoMap: Map[SmartIri, ReadClassInfoV2], * @param standoffPropertyIris the IRIs of the property entities to be queried. * @param requestingUser the user making the request. */ -case class StandoffEntityInfoGetRequestV2(standoffClassIris: Set[SmartIri] = Set.empty[SmartIri], standoffPropertyIris: Set[SmartIri] = Set.empty[SmartIri], requestingUser: UserADM) extends OntologiesResponderRequestV2 +case class StandoffEntityInfoGetRequestV2(standoffClassIris: Set[SmartIri] = Set.empty[SmartIri], + standoffPropertyIris: Set[SmartIri] = Set.empty[SmartIri], + requestingUser: UserADM) extends OntologiesResponderRequestV2 /** * Represents assertions about one or more ontology entities (resource classes and/or properties). @@ -936,7 +986,7 @@ case class StandoffEntityInfoGetResponseV2(standoffClassInfoMap: Map[SmartIri, R * Requests information about all standoff classes that are a subclass of a data type standoff class. A successful response will be an * [[StandoffClassesWithDataTypeGetResponseV2]]. * - * @param requestingUser the user making the request. + * @param requestingUser the user making the request. */ case class StandoffClassesWithDataTypeGetRequestV2(requestingUser: UserADM) extends OntologiesResponderRequestV2 @@ -951,7 +1001,7 @@ case class StandoffClassesWithDataTypeGetResponseV2(standoffClassInfoMap: Map[Sm * Requests information about all standoff property entities. A successful response will be an * [[StandoffAllPropertyEntitiesGetResponseV2]]. * - * @param requestingUser the user making the request. + * @param requestingUser the user making the request. */ case class StandoffAllPropertyEntitiesGetRequestV2(requestingUser: UserADM) extends OntologiesResponderRequestV2 @@ -969,7 +1019,9 @@ case class StandoffAllPropertyEntitiesGetResponseV2(standoffAllPropertiesEntityI * @param subClassIri the IRI of the subclass. * @param superClassIri the IRI of the superclass. */ -case class CheckSubClassRequestV2(subClassIri: SmartIri, superClassIri: SmartIri, requestingUser: UserADM) extends OntologiesResponderRequestV2 +case class CheckSubClassRequestV2(subClassIri: SmartIri, + superClassIri: SmartIri, + requestingUser: UserADM) extends OntologiesResponderRequestV2 /** * Represents a response to a [[CheckSubClassRequestV2]]. @@ -985,7 +1037,8 @@ case class CheckSubClassResponseV2(isSubClass: Boolean) * @param resourceClassIri the IRI of the given resource class. * @param requestingUser the user making the request. */ -case class SubClassesGetRequestV2(resourceClassIri: SmartIri, requestingUser: UserADM) extends OntologiesResponderRequestV2 +case class SubClassesGetRequestV2(resourceClassIri: SmartIri, + requestingUser: UserADM) extends OntologiesResponderRequestV2 /** * Provides information about the subclasses of a Knora resource class. @@ -999,55 +1052,61 @@ case class SubClassesGetResponseV2(subClasses: Seq[SubClassInfoV2]) * Request information about the Knora entities (Knora resource classes, standoff class, resource properties, and standoff properties) of a named graph. * A successful response will be a [[OntologyKnoraEntitiesIriInfoV2]]. * - * @param ontologyIri the IRI of the named graph. - * @param requestingUser the user making the request. + * @param ontologyIri the IRI of the named graph. + * @param requestingUser the user making the request. */ -case class OntologyKnoraEntityIrisGetRequestV2(ontologyIri: SmartIri, requestingUser: UserADM) extends OntologiesResponderRequestV2 +case class OntologyKnoraEntityIrisGetRequestV2(ontologyIri: SmartIri, + requestingUser: UserADM) extends OntologiesResponderRequestV2 /** * Requests metadata about ontologies by project. * - * @param projectIris the IRIs of the projects for which ontologies should be returned. If this set is empty, information - * about all ontologies is returned. - * @param requestingUser the user making the request. + * @param projectIris the IRIs of the projects for which ontologies should be returned. If this set is empty, information + * about all ontologies is returned. + * @param requestingUser the user making the request. */ -case class OntologyMetadataGetByProjectRequestV2(projectIris: Set[SmartIri] = Set.empty[SmartIri], requestingUser: UserADM) extends OntologiesResponderRequestV2 +case class OntologyMetadataGetByProjectRequestV2(projectIris: Set[SmartIri] = Set.empty[SmartIri], + requestingUser: UserADM) extends OntologiesResponderRequestV2 /** * Requests metadata about ontologies by ontology IRI. * - * @param ontologyIris the IRIs of the ontologies to be queried. If this set is empty, information - * about all ontologies is returned. - * @param requestingUser the user making the request. + * @param ontologyIris the IRIs of the ontologies to be queried. If this set is empty, information + * about all ontologies is returned. + * @param requestingUser the user making the request. */ -case class OntologyMetadataGetByIriRequestV2(ontologyIris: Set[SmartIri] = Set.empty[SmartIri], requestingUser: UserADM) extends OntologiesResponderRequestV2 +case class OntologyMetadataGetByIriRequestV2(ontologyIris: Set[SmartIri] = Set.empty[SmartIri], + requestingUser: UserADM) extends OntologiesResponderRequestV2 /** * Requests entity definitions for the given ontology. * - * @param ontologyIri the ontology to query for. - * @param allLanguages true if information in all available languages should be returned. - * @param requestingUser the user making the request. + * @param ontologyIri the ontology to query for. + * @param allLanguages true if information in all available languages should be returned. + * @param requestingUser the user making the request. */ -case class OntologyEntitiesGetRequestV2(ontologyIri: SmartIri, allLanguages: Boolean, requestingUser: UserADM) extends OntologiesResponderRequestV2 +case class OntologyEntitiesGetRequestV2(ontologyIri: SmartIri, allLanguages: Boolean, + requestingUser: UserADM) extends OntologiesResponderRequestV2 /** * Requests the entity definitions for the given class IRIs. A successful response will be a [[ReadOntologyV2]]. * - * @param classIris the IRIs of the classes to be queried. - * @param allLanguages true if information in all available languages should be returned. - * @param requestingUser the user making the request. + * @param classIris the IRIs of the classes to be queried. + * @param allLanguages true if information in all available languages should be returned. + * @param requestingUser the user making the request. */ -case class ClassesGetRequestV2(classIris: Set[SmartIri], allLanguages: Boolean, requestingUser: UserADM) extends OntologiesResponderRequestV2 +case class ClassesGetRequestV2(classIris: Set[SmartIri], allLanguages: Boolean, + requestingUser: UserADM) extends OntologiesResponderRequestV2 /** * Requests the definitions of the specified properties. A successful response will be a [[ReadOntologyV2]]. * - * @param propertyIris the IRIs of the properties to be queried. - * @param allLanguages true if information in all available languages should be returned. - * @param requestingUser the user making the request. + * @param propertyIris the IRIs of the properties to be queried. + * @param allLanguages true if information in all available languages should be returned. + * @param requestingUser the user making the request. */ -case class PropertiesGetRequestV2(propertyIris: Set[SmartIri], allLanguages: Boolean, requestingUser: UserADM) extends OntologiesResponderRequestV2 +case class PropertiesGetRequestV2(propertyIris: Set[SmartIri], allLanguages: Boolean, + requestingUser: UserADM) extends OntologiesResponderRequestV2 /** * Represents the contents of an ontology to be returned in an API response. @@ -1246,12 +1305,12 @@ case class ReadOntologyV2(ontologyMetadata: OntologyMetadataV2, }.toVector val allEntities = jsonClasses ++ jsonProperties ++ jsonIndividuals - val allEntitiesSorted = allEntities.sortBy(_.value(JsonLDConstants.ID)) + val allEntitiesSorted = allEntities.sortBy(_.value(JsonLDKeywords.ID)) // Assemble the JSON-LD document. val body = JsonLDObject( - ontologyMetadata.toJsonLD(targetSchema) + (JsonLDConstants.GRAPH -> JsonLDArray(allEntitiesSorted)) + ontologyMetadata.toJsonLD(targetSchema) + (JsonLDKeywords.GRAPH -> JsonLDArray(allEntitiesSorted)) ) JsonLDDocument(body = body, context = context) @@ -1359,7 +1418,7 @@ object InputOntologyV2 { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance val ontologyObj: JsonLDObject = jsonLDDocument.body - val externalOntologyIri: SmartIri = ontologyObj.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.toSmartIriWithErr) + val externalOntologyIri: SmartIri = ontologyObj.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.toSmartIriWithErr) if (!(externalOntologyIri.isKnoraApiV2DefinitionIri && externalOntologyIri.isKnoraOntologyIri)) { throw BadRequestException(s"Invalid ontology IRI: $externalOntologyIri") @@ -1385,14 +1444,14 @@ object InputOntologyV2 { lastModificationDate = lastModificationDate ) - val maybeGraph: Option[JsonLDArray] = ontologyObj.maybeArray(JsonLDConstants.GRAPH) + val maybeGraph: Option[JsonLDArray] = ontologyObj.maybeArray(JsonLDKeywords.GRAPH) maybeGraph match { case Some(graph) => // Make a list of (entity definition, entity type IRI) val entitiesWithTypes: Seq[(JsonLDObject, SmartIri)] = graph.value.map { case jsonLDObj: JsonLDObject => - val entityType = jsonLDObj.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val entityType = jsonLDObj.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) (jsonLDObj, entityType) case _ => throw BadRequestException("@graph must contain only JSON-LD objects") @@ -1480,7 +1539,7 @@ case class ReadOntologyMetadataV2(ontologies: Set[OntologyMetadataV2]) extends K val ontologiesJson: Vector[JsonLDObject] = ontologies.toVector.sortBy(_.ontologyIri).map(ontology => JsonLDObject(ontology.toJsonLD(targetSchema))) val body = JsonLDObject(Map( - JsonLDConstants.GRAPH -> JsonLDArray(ontologiesJson) + JsonLDKeywords.GRAPH -> JsonLDArray(ontologiesJson) )) JsonLDDocument(body = body, context = context) @@ -1925,14 +1984,14 @@ object EntityInfoContentV2 { def predicatesFromJsonLDObject(jsonLDObject: JsonLDObject): Map[SmartIri, PredicateInfoV2] = { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance - val entityType: SmartIri = jsonLDObject.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val entityType: SmartIri = jsonLDObject.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) val rdfType: (SmartIri, PredicateInfoV2) = OntologyConstants.Rdf.Type.toSmartIri -> PredicateInfoV2( predicateIri = OntologyConstants.Rdf.Type.toSmartIri, objects = Seq(SmartIriLiteralV2(entityType)) ) - val predicates = jsonLDObject.value - JsonLDConstants.ID - JsonLDConstants.TYPE - OntologyConstants.Rdfs.SubClassOf - OntologyConstants.Rdfs.SubPropertyOf - OntologyConstants.Owl.WithRestrictions + val predicates = jsonLDObject.value - JsonLDKeywords.ID - JsonLDKeywords.TYPE - OntologyConstants.Rdfs.SubClassOf - OntologyConstants.Rdfs.SubPropertyOf - OntologyConstants.Owl.WithRestrictions predicates.map { case (predicateIriStr: IRI, predicateValue: JsonLDValue) => @@ -2079,7 +2138,7 @@ sealed trait ReadEntityInfoV2 { None } - messages.util.JsonLDObject(getNonLanguageSpecific(targetSchema) ++ labels ++ comments) + JsonLDObject(getNonLanguageSpecific(targetSchema) ++ labels ++ comments) } } @@ -2244,7 +2303,7 @@ case class ReadClassInfoV2(entityInfoContent: ClassInfoContentV2, } JsonLDObject(Map( - JsonLDConstants.TYPE -> JsonLDString(OntologyConstants.Owl.Restriction), + JsonLDKeywords.TYPE -> JsonLDString(OntologyConstants.Owl.Restriction), OntologyConstants.Owl.OnProperty -> JsonLDUtil.iriToJsonLDObject(propertyIri.toString), prop2card ) ++ isInheritedStatement ++ guiOrderStatement) @@ -2310,8 +2369,8 @@ case class ReadClassInfoV2(entityInfoContent: ClassInfoContentV2, } Map( - JsonLDConstants.ID -> JsonLDString(entityInfoContent.classIri.toString), - JsonLDConstants.TYPE -> JsonLDArray(entityInfoContent.getRdfTypes.map(typeIri => JsonLDString(typeIri.toString))) + JsonLDKeywords.ID -> JsonLDString(entityInfoContent.classIri.toString), + JsonLDKeywords.TYPE -> JsonLDArray(entityInfoContent.getRdfTypes.map(typeIri => JsonLDString(typeIri.toString))) ) ++ jsonSubClassOfStatement ++ resourceIconStatement ++ isKnoraResourceClassStatement ++ isStandoffClassStatement ++ canBeInstantiatedStatement ++ isValueClassStatement ++ jsonRestriction } @@ -2422,8 +2481,8 @@ case class ReadPropertyInfoV2(entityInfoContent: PropertyInfoContentV2, } Map( - JsonLDConstants.ID -> JsonLDString(entityInfoContent.propertyIri.toString), - JsonLDConstants.TYPE -> JsonLDArray(entityInfoContent.getRdfTypes.map(typeIri => JsonLDString(typeIri.toString))) + JsonLDKeywords.ID -> JsonLDString(entityInfoContent.propertyIri.toString), + JsonLDKeywords.TYPE -> JsonLDArray(entityInfoContent.getRdfTypes.map(typeIri => JsonLDString(typeIri.toString))) ) ++ jsonSubPropertyOfStatement ++ subjectTypeStatement ++ objectTypeStatement ++ isResourcePropStatement ++ isEditableStatement ++ isLinkValuePropertyStatement ++ isLinkPropertyStatement ++ guiElementStatement ++ guiAttributeStatement @@ -2458,7 +2517,7 @@ case class ReadIndividualInfoV2(entityInfoContent: IndividualInfoContentV2) exte } Map( - JsonLDConstants.ID -> JsonLDString(entityInfoContent.individualIri.toString) + JsonLDKeywords.ID -> JsonLDString(entityInfoContent.individualIri.toString) ) ++ jsonLDPredicates } } @@ -2585,8 +2644,8 @@ object ClassInfoContentV2 { // The predicates that are allowed in a class definition that is read from JSON-LD representing client input. private val AllowedJsonLDClassPredicatesInClientInput = Set( - JsonLDConstants.ID, - JsonLDConstants.TYPE, + JsonLDKeywords.ID, + JsonLDKeywords.TYPE, OntologyConstants.Rdfs.SubClassOf, OntologyConstants.Rdfs.Label, OntologyConstants.Rdfs.Comment @@ -2594,7 +2653,7 @@ object ClassInfoContentV2 { // The predicates that are allowed in an owl:Restriction that is read from JSON-LD representing client input. private val AllowedJsonLDRestrictionPredicatesInClientInput = Set( - JsonLDConstants.TYPE, + JsonLDKeywords.TYPE, OntologyConstants.Owl.Cardinality, OntologyConstants.Owl.MinCardinality, OntologyConstants.Owl.MaxCardinality, @@ -2612,7 +2671,7 @@ object ClassInfoContentV2 { def fromJsonLDObject(jsonLDClassDef: JsonLDObject, parsingMode: InputOntologyParsingModeV2): ClassInfoContentV2 = { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance - val classIri: SmartIri = jsonLDClassDef.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.toSmartIriWithErr) + val classIri: SmartIri = jsonLDClassDef.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.toSmartIriWithErr) val ontologySchema: OntologySchema = classIri.getOntologySchema.getOrElse(throw BadRequestException(s"Invalid class IRI: $classIri")) // Parse differently depending on parsing mode. @@ -2656,7 +2715,7 @@ object ClassInfoContentV2 { if (jsonLDObj.isIri) { false } else { - jsonLDObj.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr).toString == OntologyConstants.Owl.Restriction + jsonLDObj.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr).toString == OntologyConstants.Owl.Restriction } } @@ -2868,8 +2927,8 @@ case class PropertyInfoContentV2(propertyIri: SmartIri, object PropertyInfoContentV2 { // The predicates allowed in a property definition that is read from JSON-LD representing client input. private val AllowedJsonLDPropertyPredicatesInClientInput = Set( - JsonLDConstants.ID, - JsonLDConstants.TYPE, + JsonLDKeywords.ID, + JsonLDKeywords.TYPE, OntologyConstants.KnoraApiV2Simple.SubjectType, OntologyConstants.KnoraApiV2Simple.ObjectType, OntologyConstants.KnoraApiV2Complex.SubjectType, @@ -2891,7 +2950,7 @@ object PropertyInfoContentV2 { def fromJsonLDObject(jsonLDPropertyDef: JsonLDObject, parsingMode: InputOntologyParsingModeV2): PropertyInfoContentV2 = { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance - val propertyIri: SmartIri = jsonLDPropertyDef.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.toSmartIriWithErr) + val propertyIri: SmartIri = jsonLDPropertyDef.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.toSmartIriWithErr) val ontologySchema: OntologySchema = propertyIri.getOntologySchema.getOrElse(throw BadRequestException(s"Invalid property IRI: $propertyIri")) // Parse differently depending on the parsing mode. @@ -2981,7 +3040,7 @@ object IndividualInfoContentV2 { def fromJsonLDObject(jsonLDIndividualDef: JsonLDObject): IndividualInfoContentV2 = { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance - val individualIri: SmartIri = jsonLDIndividualDef.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.toSmartIriWithErr) + val individualIri: SmartIri = jsonLDIndividualDef.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.toSmartIriWithErr) val ontologySchema: OntologySchema = individualIri.getOntologySchema.getOrElse(throw BadRequestException(s"Invalid named individual IRI: $individualIri")) IndividualInfoContentV2( @@ -3103,8 +3162,8 @@ case class OntologyMetadataV2(ontologyIri: SmartIri, None } - Map(JsonLDConstants.ID -> JsonLDString(ontologyIri.toString), - JsonLDConstants.TYPE -> JsonLDString(OntologyConstants.Owl.Ontology) + Map(JsonLDKeywords.ID -> JsonLDString(ontologyIri.toString), + JsonLDKeywords.TYPE -> JsonLDString(OntologyConstants.Owl.Ontology) ) ++ projectIriStatement ++ labelStatement ++ commentStatement ++ lastModDateStatement ++ isSharedStatement ++ isBuiltInStatement } } diff --git a/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/resourcemessages/ResourceMessagesV2.scala b/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/resourcemessages/ResourceMessagesV2.scala index f999a39e91..46ed6e8543 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/resourcemessages/ResourceMessagesV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/resourcemessages/ResourceMessagesV2.scala @@ -30,12 +30,14 @@ import akka.util.Timeout import org.eclipse.rdf4j.rio.rdfxml.util.RDFXMLPrettyWriter import org.eclipse.rdf4j.rio.{RDFFormat, RDFParser, RDFWriter, Rio} import org.knora.webapi.exceptions._ +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.admin.responder.projectsmessages.{ProjectADM, ProjectGetRequestADM, ProjectGetResponseADM, ProjectIdentifierADM} import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.util.PermissionUtilADM.EntityPermission -import org.knora.webapi.messages.util.standoff.{StandoffTagUtilV2, XMLUtil} import org.knora.webapi.messages.util._ +import org.knora.webapi.messages.util.rdf._ +import org.knora.webapi.messages.util.standoff.{StandoffTagUtilV2, XMLUtil} import org.knora.webapi.messages.v2.responder._ import org.knora.webapi.messages.v2.responder.standoffmessages.MappingXMLtoStandoff import org.knora.webapi.messages.v2.responder.valuemessages._ @@ -59,13 +61,14 @@ sealed trait ResourcesResponderRequestV2 extends KnoraRequestV2 { /** * Requests a description of a resource. A successful response will be a [[ReadResourcesSequenceV2]]. * - * @param resourceIris the IRIs of the resources to be queried. - * @param propertyIri if defined, requests only the values of the specified explicit property. - * @param valueUuid if defined, requests only the value with the specified UUID. - * @param versionDate if defined, requests the state of the resources at the specified time in the past. - * @param targetSchema the target API schema. - * @param schemaOptions the schema options submitted with the request. - * @param requestingUser the user making the request. + * @param resourceIris the IRIs of the resources to be queried. + * @param propertyIri if defined, requests only the values of the specified explicit property. + * @param valueUuid if defined, requests only the value with the specified UUID. + * @param versionDate if defined, requests the state of the resources at the specified time in the past. + * @param targetSchema the target API schema. + * @param schemaOptions the schema options submitted with the request. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ case class ResourcesGetRequestV2(resourceIris: Seq[IRI], propertyIri: Option[SmartIri] = None, @@ -73,26 +76,36 @@ case class ResourcesGetRequestV2(resourceIris: Seq[IRI], versionDate: Option[Instant] = None, targetSchema: ApiV2Schema, schemaOptions: Set[SchemaOption] = Set.empty, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends ResourcesResponderRequestV2 /** * Requests a preview of one or more resources. A successful response will be a [[ReadResourcesSequenceV2]]. * - * @param resourceIris the IRIs of the resources to obtain a preview for. - * @param targetSchema the schema of the response. - * @param requestingUser the user making the request. + * @param resourceIris the IRIs of the resources to obtain a preview for. + * @param targetSchema the schema of the response. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ -case class ResourcesPreviewGetRequestV2(resourceIris: Seq[IRI], targetSchema: ApiV2Schema, requestingUser: UserADM) extends ResourcesResponderRequestV2 +case class ResourcesPreviewGetRequestV2(resourceIris: Seq[IRI], + targetSchema: ApiV2Schema, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM) extends ResourcesResponderRequestV2 /** * Requests the version history of the values of a resource. * - * @param resourceIri the IRI of the resource. - * @param startDate the start of the time period to return, inclusive. - * @param endDate the end of the time period to return, exclusive. - * @param requestingUser the user making the request. + * @param resourceIri the IRI of the resource. + * @param startDate the start of the time period to return, inclusive. + * @param endDate the end of the time period to return, exclusive. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ -case class ResourceVersionHistoryGetRequestV2(resourceIri: IRI, startDate: Option[Instant], endDate: Option[Instant], requestingUser: UserADM) extends ResourcesResponderRequestV2 +case class ResourceVersionHistoryGetRequestV2(resourceIri: IRI, + startDate: Option[Instant], + endDate: Option[Instant], + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM) extends ResourcesResponderRequestV2 /** * Represents an item in the version history of a resource. @@ -147,7 +160,7 @@ case class ResourceVersionHistoryResponseV2(history: Seq[ResourceHistoryEntry]) // Make the JSON-LD document. - val body = JsonLDObject(Map(JsonLDConstants.GRAPH -> JsonLDArray(historyAsJsonLD))) + val body = JsonLDObject(Map(JsonLDKeywords.GRAPH -> JsonLDArray(historyAsJsonLD))) JsonLDDocument(body = body, context = context) } @@ -161,9 +174,16 @@ case class ResourceVersionHistoryResponseV2(history: Seq[ResourceHistoryEntry]) * @param mappingIri the IRI of the mapping to be used to convert from standoff to TEI/XML, if any. Otherwise the standard mapping is assumed. * @param gravsearchTemplateIri the gravsearch template to query the metadata for the TEI header, if provided. * @param headerXSLTIri the IRI of the XSL transformation to convert the resource's metadata to the TEI header. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the user making the request. */ -case class ResourceTEIGetRequestV2(resourceIri: IRI, textProperty: SmartIri, mappingIri: Option[IRI], gravsearchTemplateIri: Option[IRI], headerXSLTIri: Option[IRI], requestingUser: UserADM) extends ResourcesResponderRequestV2 +case class ResourceTEIGetRequestV2(resourceIri: IRI, + textProperty: SmartIri, + mappingIri: Option[IRI], + gravsearchTemplateIri: Option[IRI], + headerXSLTIri: Option[IRI], + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM) extends ResourcesResponderRequestV2 /** * Represents a Knora resource as TEI/XML. @@ -196,7 +216,10 @@ case class TEIHeader(headerInfo: ReadResourceV2, headerXSLT: Option[String], set if (headerXSLT.nonEmpty) { - val headerJSONLD = ReadResourcesSequenceV2(Vector(headerInfo)).toJsonLDDocument(ApiV2Complex, settings) + val headerJSONLD: JsonLDDocument = ReadResourcesSequenceV2(Vector(headerInfo)).toJsonLDDocument(ApiV2Complex, settings) + + // TODO: Change the XSLT transformation used here to handle rdf:Description, so we can use RdfFormatUtil + // here instead of RDF4J. val rdfParser: RDFParser = Rio.createParser(RDFFormat.JSONLD) val stringReader = new StringReader(headerJSONLD.toCompactString) @@ -208,10 +231,8 @@ case class TEIHeader(headerInfo: ReadResourceV2, headerXSLT: Option[String], set rdfParser.parse(stringReader, "") val teiHeaderInfos = stringWriter.toString - XMLUtil.applyXSLTransformation(teiHeaderInfos, headerXSLT.get) - } else { s""" | @@ -430,10 +451,10 @@ case class ReadResourceV2(resourceIri: IRI, datatype = OntologyConstants.Xsd.Uri.toSmartIri ) - messages.util.JsonLDObject( + JsonLDObject( Map( - JsonLDConstants.ID -> JsonLDString(resourceIri), - JsonLDConstants.TYPE -> JsonLDString(resourceClassIri.toString), + JsonLDKeywords.ID -> JsonLDString(resourceIri), + JsonLDKeywords.TYPE -> JsonLDString(resourceClassIri.toString), OntologyConstants.Rdfs.Label -> JsonLDString(label) ) ++ propertiesAndValuesAsJsonLD ++ metadataForComplexSchema + arkUrlAsJsonLD + versionArkUrlAsJsonLD ) @@ -500,11 +521,13 @@ case class CreateResourceV2(resourceIri: Option[SmartIri], /** * Represents a request to create a resource. * - * @param createResource the resource to be created. - * @param requestingUser the user making the request. - * @param apiRequestID the API request ID. + * @param createResource the resource to be created. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. + * @param apiRequestID the API request ID. */ case class CreateResourceRequestV2(createResource: CreateResourceV2, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends ResourcesResponderRequestV2 @@ -512,14 +535,14 @@ object CreateResourceRequestV2 extends KnoraJsonLDRequestReaderV2[CreateResource /** * Converts JSON-LD input to a [[CreateResourceRequestV2]]. * - * @param jsonLDDocument the JSON-LD input. - * @param apiRequestID the UUID of the API request. - * @param requestingUser the user making the request. - * @param responderManager a reference to the responder manager. - * @param storeManager a reference to the store manager. - * @param log a logging adapter. - * @param timeout a timeout for `ask` messages. - * @param executionContext an execution context for futures. + * @param jsonLDDocument the JSON-LD input. + * @param apiRequestID the UUID of the API request. + * @param requestingUser the user making the request. + * @param responderManager a reference to the responder manager. + * @param storeManager a reference to the store manager. + * @param featureFactoryConfig the feature factory configuration. + * @param settings the application settings. + * @param log a logging adapter. * @return a case class instance representing the input. */ override def fromJsonLD(jsonLDDocument: JsonLDDocument, @@ -527,6 +550,7 @@ object CreateResourceRequestV2 extends KnoraJsonLDRequestReaderV2[CreateResource requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[CreateResourceRequestV2] = { @@ -546,7 +570,8 @@ object CreateResourceRequestV2 extends KnoraJsonLDRequestReaderV2[CreateResource projectIri: SmartIri = jsonLDDocument.requireIriInObject(OntologyConstants.KnoraApiV2Complex.AttachedToProject, stringFormatter.toSmartIriWithErr) projectInfoResponse: ProjectGetResponseADM <- (responderManager ? ProjectGetRequestADM( - ProjectIdentifierADM(maybeIri = Some(projectIri.toString)), + identifier = ProjectIdentifierADM(maybeIri = Some(projectIri.toString)), + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser )).mapTo[ProjectGetResponseADM] @@ -574,6 +599,7 @@ object CreateResourceRequestV2 extends KnoraJsonLDRequestReaderV2[CreateResource requestingUser = requestingUser, requestedUserIri = attachedToUserIri.toString, projectIri = projectIri.toString, + featureFactoryConfig = featureFactoryConfig, responderManager = responderManager ) } @@ -591,8 +617,8 @@ object CreateResourceRequestV2 extends KnoraJsonLDRequestReaderV2[CreateResource propertyIriStrs: Set[IRI] = jsonLDDocument.body.value.keySet -- Set( - JsonLDConstants.ID, - JsonLDConstants.TYPE, + JsonLDKeywords.ID, + JsonLDKeywords.TYPE, OntologyConstants.Rdfs.Label, OntologyConstants.KnoraApiV2Complex.AttachedToProject, OntologyConstants.KnoraApiV2Complex.AttachedToUser, @@ -618,6 +644,7 @@ object CreateResourceRequestV2 extends KnoraJsonLDRequestReaderV2[CreateResource requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, + featureFactoryConfig = featureFactoryConfig, settings = settings, log = log ) @@ -661,6 +688,7 @@ object CreateResourceRequestV2 extends KnoraJsonLDRequestReaderV2[CreateResource permissions = permissions, creationDate = creationDate ), + featureFactoryConfig = featureFactoryConfig, requestingUser = maybeAttachedToUser.getOrElse(requestingUser), apiRequestID = apiRequestID ) @@ -676,6 +704,7 @@ object CreateResourceRequestV2 extends KnoraJsonLDRequestReaderV2[CreateResource * @param maybeLabel the resource's new `rdfs:label`, if any. * @param maybePermissions the resource's new permissions, if any. * @param maybeNewModificationDate the resource's new last modification date, if any. + * @param featureFactoryConfig the feature factory configuration. */ case class UpdateResourceMetadataRequestV2(resourceIri: IRI, resourceClassIri: SmartIri, @@ -683,6 +712,7 @@ case class UpdateResourceMetadataRequestV2(resourceIri: IRI, maybeLabel: Option[String] = None, maybePermissions: Option[String] = None, maybeNewModificationDate: Option[Instant] = None, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends ResourcesResponderRequestV2 @@ -690,15 +720,14 @@ object UpdateResourceMetadataRequestV2 extends KnoraJsonLDRequestReaderV2[Update /** * Converts JSON-LD input into an instance of [[UpdateResourceMetadataRequestV2]]. * - * @param jsonLDDocument the JSON-LD input. - * @param apiRequestID the UUID of the API request. - * @param requestingUser the user making the request. - * @param responderManager a reference to the responder manager. - * @param storeManager a reference to the store manager. - * @param settings the application settings. - * @param log a logging adapter. - * @param timeout a timeout for `ask` messages. - * @param executionContext an execution context for futures. + * @param jsonLDDocument the JSON-LD input. + * @param apiRequestID the UUID of the API request. + * @param requestingUser the user making the request. + * @param responderManager a reference to the responder manager. + * @param storeManager a reference to the store manager. + * @param featureFactoryConfig the feature factory configuration. + * @param settings the application settings. + * @param log a logging adapter. * @return a case class instance representing the input. */ override def fromJsonLD(jsonLDDocument: JsonLDDocument, @@ -706,18 +735,23 @@ object UpdateResourceMetadataRequestV2 extends KnoraJsonLDRequestReaderV2[Update requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[UpdateResourceMetadataRequestV2] = { Future { fromJsonLDSync( jsonLDDocument = jsonLDDocument, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = apiRequestID ) } } - def fromJsonLDSync(jsonLDDocument: JsonLDDocument, requestingUser: UserADM, apiRequestID: UUID): UpdateResourceMetadataRequestV2 = { + def fromJsonLDSync(jsonLDDocument: JsonLDDocument, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): UpdateResourceMetadataRequestV2 = { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance val resourceIri: SmartIri = jsonLDDocument.requireIDAsKnoraDataIri @@ -754,6 +788,7 @@ object UpdateResourceMetadataRequestV2 extends KnoraJsonLDRequestReaderV2[Update maybeLabel = maybeLabel, maybePermissions = maybePermissions, maybeNewModificationDate = maybeNewModificationDate, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = apiRequestID ) @@ -770,6 +805,7 @@ object UpdateResourceMetadataRequestV2 extends KnoraJsonLDRequestReaderV2[Update * the current time will be used. * @param maybeLastModificationDate the resource's last modification date, if any. * @param erase if `true`, the resource will be erased from the triplestore, otherwise it will be marked as deleted. + * @param featureFactoryConfig the feature factory configuration. */ case class DeleteOrEraseResourceRequestV2(resourceIri: IRI, resourceClassIri: SmartIri, @@ -777,6 +813,7 @@ case class DeleteOrEraseResourceRequestV2(resourceIri: IRI, maybeDeleteDate: Option[Instant] = None, maybeLastModificationDate: Option[Instant] = None, erase: Boolean = false, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends ResourcesResponderRequestV2 @@ -784,15 +821,14 @@ object DeleteOrEraseResourceRequestV2 extends KnoraJsonLDRequestReaderV2[DeleteO /** * Converts JSON-LD input into an instance of [[DeleteOrEraseResourceRequestV2]]. * - * @param jsonLDDocument the JSON-LD input. - * @param apiRequestID the UUID of the API request. - * @param requestingUser the user making the request. - * @param responderManager a reference to the responder manager. - * @param storeManager a reference to the store manager. - * @param settings the application settings. - * @param log a logging adapter. - * @param timeout a timeout for `ask` messages. - * @param executionContext an execution context for futures. + * @param jsonLDDocument the JSON-LD input. + * @param apiRequestID the UUID of the API request. + * @param requestingUser the user making the request. + * @param responderManager a reference to the responder manager. + * @param storeManager a reference to the store manager. + * @param featureFactoryConfig the feature factory configuration. + * @param settings the application settings. + * @param log a logging adapter. * @return a case class instance representing the input. */ override def fromJsonLD(jsonLDDocument: JsonLDDocument, @@ -800,18 +836,23 @@ object DeleteOrEraseResourceRequestV2 extends KnoraJsonLDRequestReaderV2[DeleteO requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[DeleteOrEraseResourceRequestV2] = { Future { fromJsonLDSync( jsonLDDocument = jsonLDDocument, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = apiRequestID ) } } - def fromJsonLDSync(jsonLDDocument: JsonLDDocument, requestingUser: UserADM, apiRequestID: UUID): DeleteOrEraseResourceRequestV2 = { + def fromJsonLDSync(jsonLDDocument: JsonLDDocument, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): DeleteOrEraseResourceRequestV2 = { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance val resourceIri: SmartIri = jsonLDDocument.requireIDAsKnoraDataIri @@ -842,6 +883,7 @@ object DeleteOrEraseResourceRequestV2 extends KnoraJsonLDRequestReaderV2[DeleteO maybeDeleteComment = maybeDeleteComment, maybeDeleteDate = maybeDeleteDate, maybeLastModificationDate = maybeLastModificationDate, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = apiRequestID ) @@ -928,7 +970,7 @@ case class ReadResourcesSequenceV2(resources: Seq[ReadResourceV2], val body = JsonLDObject( Map( - JsonLDConstants.GRAPH -> JsonLDArray(resourcesJsonObjects) + JsonLDKeywords.GRAPH -> JsonLDArray(resourcesJsonObjects) ) ++ mayHaveMoreResultsStatement ) @@ -1111,8 +1153,8 @@ case class GraphDataGetResponseV2(nodes: Seq[GraphNodeV2], edges: Seq[GraphEdgeV node: GraphNodeV2 => // Convert the node to JSON-LD. val jsonLDNodeMap = Map( - JsonLDConstants.ID -> JsonLDString(node.resourceIri), - JsonLDConstants.TYPE -> JsonLDString(node.resourceClassIri.toString), + JsonLDKeywords.ID -> JsonLDString(node.resourceIri), + JsonLDKeywords.TYPE -> JsonLDString(node.resourceClassIri.toString), OntologyConstants.Rdfs.Label -> JsonLDString(node.resourceLabel) ) @@ -1129,7 +1171,7 @@ case class GraphDataGetResponseV2(nodes: Seq[GraphNodeV2], edges: Seq[GraphEdgeV propertyIri.toString -> JsonLDArray(sortedPropertyEdges.map(propertyEdge => JsonLDUtil.iriToJsonLDObject(propertyEdge.target))) }.toMap - messages.util.JsonLDObject(jsonLDNodeMap ++ jsonLDNodeEdges) + messages.util.rdf.JsonLDObject(jsonLDNodeMap ++ jsonLDNodeEdges) case None => // This node isn't the source of any edges. @@ -1139,7 +1181,7 @@ case class GraphDataGetResponseV2(nodes: Seq[GraphNodeV2], edges: Seq[GraphEdgeV // Make the JSON-LD document. - val body = JsonLDObject(Map(JsonLDConstants.GRAPH -> JsonLDArray(nodesWithEdges))) + val body = JsonLDObject(Map(JsonLDKeywords.GRAPH -> JsonLDArray(nodesWithEdges))) JsonLDDocument(body = body, context = context) } diff --git a/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/searchmessages/SearchMessagesV2.scala b/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/searchmessages/SearchMessagesV2.scala index e76ef9142b..2d4e712d18 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/searchmessages/SearchMessagesV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/searchmessages/SearchMessagesV2.scala @@ -19,9 +19,10 @@ package org.knora.webapi.messages.v2.responder.searchmessages +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.admin.responder.usersmessages.UserADM +import org.knora.webapi.messages.util.rdf.{JsonLDDocument, JsonLDInt, JsonLDObject, JsonLDString} import org.knora.webapi.messages.util.search.ConstructQuery -import org.knora.webapi.messages.util.{JsonLDDocument, JsonLDInt, JsonLDObject, JsonLDString} import org.knora.webapi.messages.v2.responder._ import org.knora.webapi.messages.{OntologyConstants, SmartIri} import org.knora.webapi.settings.KnoraSettingsImpl @@ -41,12 +42,14 @@ sealed trait SearchResponderRequestV2 extends KnoraRequestV2 { * @param searchValue the values to search for. * @param limitToProject limit search to given project. * @param limitToResourceClass limit search to given resource class. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the user making the request. */ case class FullTextSearchCountRequestV2(searchValue: String, limitToProject: Option[IRI], limitToResourceClass: Option[SmartIri], limitToStandoffClass: Option[SmartIri], + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends SearchResponderRequestV2 /** @@ -58,6 +61,7 @@ case class FullTextSearchCountRequestV2(searchValue: String, * @param limitToResourceClass limit search to given resource class. * @param targetSchema the target API schema. * @param schemaOptions the schema options submitted with the request. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the user making the request. */ case class FulltextSearchRequestV2(searchValue: String, @@ -67,6 +71,7 @@ case class FulltextSearchRequestV2(searchValue: String, limitToStandoffClass: Option[SmartIri], targetSchema: ApiV2Schema, schemaOptions: Set[SchemaOption], + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends SearchResponderRequestV2 @@ -74,25 +79,29 @@ case class FulltextSearchRequestV2(searchValue: String, * * Requests the amount of results (resources count) of a given Gravsearch query. A successful response will be a [[ResourceCountV2]]. * - * @param constructQuery a Sparql construct query provided by the client. - * @param requestingUser the user making the request. + * @param constructQuery a Sparql construct query provided by the client. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ case class GravsearchCountRequestV2(constructQuery: ConstructQuery, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends SearchResponderRequestV2 /** * * Performs a Gravsearch query. A successful response will be a [[org.knora.webapi.messages.v2.responder.resourcemessages.ReadResourcesSequenceV2]]. * - * @param constructQuery a Sparql construct query provided by the client. - * @param targetSchema the target API schema. - * @param schemaOptions the schema options submitted with the request. - * @param requestingUser the user making the request. + * @param constructQuery a Sparql construct query provided by the client. + * @param targetSchema the target API schema. + * @param schemaOptions the schema options submitted with the request. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ case class GravsearchRequestV2(constructQuery: ConstructQuery, targetSchema: ApiV2Schema, schemaOptions: Set[SchemaOption] = Set.empty[SchemaOption], + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends SearchResponderRequestV2 @@ -102,11 +111,13 @@ case class GravsearchRequestV2(constructQuery: ConstructQuery, * @param searchValue the values to search for. * @param limitToProject limit search to given project. * @param limitToResourceClass limit search to given resource class. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the user making the request. */ case class SearchResourceByLabelCountRequestV2(searchValue: String, limitToProject: Option[IRI], limitToResourceClass: Option[SmartIri], + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends SearchResponderRequestV2 /** @@ -117,6 +128,7 @@ case class SearchResourceByLabelCountRequestV2(searchValue: String, * @param limitToProject limit search to given project. * @param limitToResourceClass limit search to given resource class. * @param targetSchema the schema of the response. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the user making the request. */ case class SearchResourceByLabelRequestV2(searchValue: String, @@ -124,6 +136,7 @@ case class SearchResourceByLabelRequestV2(searchValue: String, limitToProject: Option[IRI], limitToResourceClass: Option[SmartIri], targetSchema: ApiV2Schema, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends SearchResponderRequestV2 /** @@ -145,13 +158,14 @@ case class ResourceCountV2(numberOfResources: Int) extends KnoraJsonLDResponseV2 /** * Requests resources of the specified class from the specified project. * - * @param projectIri the IRI of the project. - * @param resourceClass the IRI of the resource class, in the complex schema. - * @param orderByProperty the IRI of the property that the resources are to be ordered by, in the complex schema. - * @param page the page number of the results page to be returned. - * @param targetSchema the schema of the response. - * @param schemaOptions the schema options submitted with the request. - * @param requestingUser the user making the request. + * @param projectIri the IRI of the project. + * @param resourceClass the IRI of the resource class, in the complex schema. + * @param orderByProperty the IRI of the property that the resources are to be ordered by, in the complex schema. + * @param page the page number of the results page to be returned. + * @param targetSchema the schema of the response. + * @param schemaOptions the schema options submitted with the request. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ case class SearchResourcesByProjectAndClassRequestV2(projectIri: SmartIri, resourceClass: SmartIri, @@ -159,4 +173,5 @@ case class SearchResourcesByProjectAndClassRequestV2(projectIri: SmartIri, page: Int, targetSchema: ApiV2Schema, schemaOptions: Set[SchemaOption], + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends SearchResponderRequestV2 \ No newline at end of file diff --git a/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/standoffmessages/StandoffMessagesV2.scala b/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/standoffmessages/StandoffMessagesV2.scala index 9933519926..8f143714ae 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/standoffmessages/StandoffMessagesV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/v2/responder/standoffmessages/StandoffMessagesV2.scala @@ -27,11 +27,13 @@ import akka.event.LoggingAdapter import akka.util.Timeout import org.knora.webapi._ import org.knora.webapi.exceptions.AssertionException +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.util._ +import org.knora.webapi.messages.util.rdf.{JsonLDArray, JsonLDBoolean, JsonLDDocument, JsonLDInt, JsonLDKeywords, JsonLDObject, JsonLDString, JsonLDUtil, JsonLDValue} import org.knora.webapi.messages.v2.responder.ontologymessages.StandoffEntityInfoGetResponseV2 -import org.knora.webapi.messages.v2.responder.{KnoraContentV2, KnoraJsonLDRequestReaderV2, KnoraRequestV2, KnoraJsonLDResponseV2} +import org.knora.webapi.messages.v2.responder.{KnoraContentV2, KnoraJsonLDRequestReaderV2, KnoraJsonLDResponseV2, KnoraRequestV2} import org.knora.webapi.messages.{OntologyConstants, SmartIri, StringFormatter} import org.knora.webapi.settings.KnoraSettingsImpl @@ -47,22 +49,32 @@ sealed trait StandoffResponderRequestV2 extends KnoraRequestV2 /** * Requests a page of standoff markup from a text value. A successful response will be a [[GetStandoffResponseV2]]. * - * @param resourceIri the IRI of the resource containing the value. - * @param valueIri the IRI of the value. - * @param offset the start index of the first standoff tag to be returned. - * @param targetSchema the schema of the response. - * @param requestingUser the user making the request. + * @param resourceIri the IRI of the resource containing the value. + * @param valueIri the IRI of the value. + * @param offset the start index of the first standoff tag to be returned. + * @param targetSchema the schema of the response. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ -case class GetStandoffPageRequestV2(resourceIri: IRI, valueIri: IRI, offset: Int, targetSchema: ApiV2Schema, requestingUser: UserADM) extends StandoffResponderRequestV2 +case class GetStandoffPageRequestV2(resourceIri: IRI, + valueIri: IRI, + offset: Int, + targetSchema: ApiV2Schema, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM) extends StandoffResponderRequestV2 /** * Requests all the standoff markup from a text value, except for the first page. A successful response will be a [[GetStandoffResponseV2]]. * - * @param resourceIri the IRI of the resource containing the text value. - * @param valueIri the IRI of the text value. - * @param requestingUser the user making the request. + * @param resourceIri the IRI of the resource containing the text value. + * @param valueIri the IRI of the text value. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ -case class GetRemainingStandoffFromTextValueRequestV2(resourceIri: IRI, valueIri: IRI, requestingUser: UserADM) extends StandoffResponderRequestV2 +case class GetRemainingStandoffFromTextValueRequestV2(resourceIri: IRI, + valueIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM) extends StandoffResponderRequestV2 /** * A response to a [[GetStandoffPageRequestV2]] or a [[GetRemainingStandoffFromTextValueRequestV2]], representing standoff @@ -75,8 +87,6 @@ case class GetRemainingStandoffFromTextValueRequestV2(resourceIri: IRI, valueIri case class GetStandoffResponseV2(valueIri: IRI, standoff: Seq[StandoffTagV2], nextOffset: Option[Int]) extends KnoraJsonLDResponseV2 { - private val stringFormatter = StringFormatter.getGeneralInstance - /** * Converts the response to a data structure that can be used to generate JSON-LD. * @@ -94,7 +104,7 @@ case class GetStandoffResponseV2(valueIri: IRI, val contentMap: Map[IRI, JsonLDValue] = Map( - JsonLDConstants.GRAPH -> JsonLDArray(standoffAsJsonLD) + JsonLDKeywords.GRAPH -> JsonLDArray(standoffAsJsonLD) ) val nextOffsetStatement: Option[(IRI, JsonLDInt)] = nextOffset.map { @@ -121,12 +131,17 @@ case class GetStandoffResponseV2(valueIri: IRI, * Represents a request to create a mapping between XML elements and attributes and standoff classes and properties. * A successful response will be a [[CreateMappingResponseV2]]. * - * @param metadata the metadata describing the mapping. - * @param xml the mapping in XML syntax. - * @param requestingUser the the user making the request. - * @param apiRequestID the ID of the API request. + * @param metadata the metadata describing the mapping. + * @param xml the mapping in XML syntax. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the the user making the request. + * @param apiRequestID the ID of the API request. */ -case class CreateMappingRequestV2(metadata: CreateMappingRequestMetadataV2, xml: CreateMappingRequestXMLV2, requestingUser: UserADM, apiRequestID: UUID) extends StandoffResponderRequestV2 +case class CreateMappingRequestV2(metadata: CreateMappingRequestMetadataV2, + xml: CreateMappingRequestXMLV2, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID) extends StandoffResponderRequestV2 /** * Represents the metadata describing the mapping that is to be created. @@ -144,6 +159,7 @@ object CreateMappingRequestMetadataV2 extends KnoraJsonLDRequestReaderV2[CreateM requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[CreateMappingRequestMetadataV2] = { Future { @@ -197,8 +213,8 @@ case class CreateMappingResponseV2(mappingIri: IRI, label: String, projectIri: S implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance val body = JsonLDObject(Map( - JsonLDConstants.ID -> JsonLDString(mappingIri), - JsonLDConstants.TYPE -> JsonLDString(OntologyConstants.KnoraBase.XMLToStandoffMapping.toSmartIri.toOntologySchema(targetSchema).toString), + JsonLDKeywords.ID -> JsonLDString(mappingIri), + JsonLDKeywords.TYPE -> JsonLDString(OntologyConstants.KnoraBase.XMLToStandoffMapping.toSmartIri.toOntologySchema(targetSchema).toString), OntologyConstants.Rdfs.Label -> JsonLDString(label), OntologyConstants.KnoraApiV2Complex.AttachedToProject.toSmartIri.toOntologySchema(targetSchema).toString -> JsonLDUtil.iriToJsonLDObject(projectIri.toString) )) @@ -217,10 +233,13 @@ case class CreateMappingResponseV2(mappingIri: IRI, label: String, projectIri: S /** * Represents a request to get a mapping from XML elements and attributes to standoff entities. * - * @param mappingIri the IRI of the mapping. - * @param requestingUser the the user making the request. + * @param mappingIri the IRI of the mapping. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the the user making the request. */ -case class GetMappingRequestV2(mappingIri: IRI, requestingUser: UserADM) extends StandoffResponderRequestV2 +case class GetMappingRequestV2(mappingIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM) extends StandoffResponderRequestV2 /** * Represents a response to a [[GetMappingRequestV2]]. @@ -235,9 +254,12 @@ case class GetMappingResponseV2(mappingIri: IRI, mapping: MappingXMLtoStandoff, * Represents a request that gets an XSL Transformation represented by a `knora-base:XSLTransformation`. * * @param xsltTextRepresentationIri the IRI of the `knora-base:XSLTransformation`. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the the user making the request. */ -case class GetXSLTransformationRequestV2(xsltTextRepresentationIri: IRI, requestingUser: UserADM) extends StandoffResponderRequestV2 +case class GetXSLTransformationRequestV2(xsltTextRepresentationIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM) extends StandoffResponderRequestV2 /** * Represents a response to a [[GetXSLTransformationRequestV2]]. @@ -645,7 +667,7 @@ case class StandoffTagV2(standoffTagClassIri: SmartIri, val attributesAsJsonLD: Map[IRI, JsonLDValue] = attributes.map(_.toJsonLD).toMap val contentMap: Map[IRI, JsonLDValue] = Map( - JsonLDConstants.TYPE -> JsonLDString(standoffTagClassIri.toString), + JsonLDKeywords.TYPE -> JsonLDString(standoffTagClassIri.toString), OntologyConstants.KnoraApiV2Complex.StandoffTagHasUUID -> JsonLDString(stringFormatter.base64EncodeUuid(uuid)), OntologyConstants.KnoraApiV2Complex.StandoffTagHasStart -> JsonLDInt(startPosition), OntologyConstants.KnoraApiV2Complex.StandoffTagHasEnd -> JsonLDInt(endPosition), 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 99200c6df6..b356cbc6a3 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 @@ -29,14 +29,16 @@ import akka.pattern._ import akka.util.Timeout import org.knora.webapi._ import org.knora.webapi.exceptions.{AssertionException, BadRequestException, NotImplementedException, SipiException} +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectADM import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.store.sipimessages.{GetFileMetadataRequest, GetFileMetadataResponse} import org.knora.webapi.messages.util.PermissionUtilADM.EntityPermission +import org.knora.webapi.messages.util._ +import org.knora.webapi.messages.util.rdf._ import org.knora.webapi.messages.util.standoff.StandoffTagUtilV2.TextWithStandoffTagsV2 import org.knora.webapi.messages.util.standoff.{StandoffTagUtilV2, XMLUtil} -import org.knora.webapi.messages.util._ import org.knora.webapi.messages.v2.responder._ import org.knora.webapi.messages.v2.responder.resourcemessages.ReadResourceV2 import org.knora.webapi.messages.v2.responder.standoffmessages._ @@ -54,12 +56,14 @@ sealed trait ValuesResponderRequestV2 extends KnoraRequestV2 /** * Requests the creation of a value. * - * @param createValue a [[CreateValueV2]] representing the value to be created. A successful response will be - * a [[CreateValueResponseV2]]. - * @param requestingUser the user making the request. - * @param apiRequestID the API request ID. + * @param createValue a [[CreateValueV2]] representing the value to be created. A successful response will be + * a [[CreateValueResponseV2]]. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. + * @param apiRequestID the API request ID. */ case class CreateValueRequestV2(createValue: CreateValueV2, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends ValuesResponderRequestV2 @@ -71,14 +75,14 @@ object CreateValueRequestV2 extends KnoraJsonLDRequestReaderV2[CreateValueReques /** * Converts JSON-LD input to a [[CreateValueRequestV2]]. * - * @param jsonLDDocument the JSON-LD input. - * @param apiRequestID the UUID of the API request. - * @param requestingUser the user making the request. - * @param responderManager a reference to the responder manager. - * @param storeManager a reference to the store manager. - * @param log a logging adapter. - * @param timeout a timeout for `ask` messages. - * @param executionContext an execution context for futures. + * @param jsonLDDocument the JSON-LD input. + * @param apiRequestID the UUID of the API request. + * @param requestingUser the user making the request. + * @param responderManager a reference to the responder manager. + * @param storeManager a reference to the store manager. + * @param featureFactoryConfig the feature factory configuration. + * @param settings the application settings. + * @param log a logging adapter. * @return a case class instance representing the input. */ override def fromJsonLD(jsonLDDocument: JsonLDDocument, @@ -86,6 +90,7 @@ object CreateValueRequestV2 extends KnoraJsonLDRequestReaderV2[CreateValueReques requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[CreateValueRequestV2] = { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance @@ -112,6 +117,7 @@ object CreateValueRequestV2 extends KnoraJsonLDRequestReaderV2[CreateValueReques requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, + featureFactoryConfig = featureFactoryConfig, settings = settings, log = log ) @@ -155,6 +161,7 @@ object CreateValueRequestV2 extends KnoraJsonLDRequestReaderV2[CreateValueReques } } yield CreateValueRequestV2( createValue = createValue, + featureFactoryConfig = featureFactoryConfig, apiRequestID = apiRequestID, requestingUser = requestingUser ) @@ -185,8 +192,8 @@ case class CreateValueResponseV2(valueIri: IRI, JsonLDDocument( body = JsonLDObject( Map( - JsonLDConstants.ID -> JsonLDString(valueIri), - JsonLDConstants.TYPE -> JsonLDString(valueType.toOntologySchema(ApiV2Complex).toString), + JsonLDKeywords.ID -> JsonLDString(valueIri), + JsonLDKeywords.TYPE -> JsonLDString(valueType.toOntologySchema(ApiV2Complex).toString), OntologyConstants.KnoraApiV2Complex.ValueHasUUID -> JsonLDString(stringFormatter.base64EncodeUuid(valueUUID)), OntologyConstants.KnoraApiV2Complex.ValueCreationDate -> JsonLDUtil.datatypeValueToJsonLDObject( value = valueCreationDate.toString, @@ -206,12 +213,14 @@ case class CreateValueResponseV2(valueIri: IRI, /** * Requests an update to a value, i.e. the creation of a new version of an existing value. * - * @param updateValue an [[UpdateValueV2]] representing the new version of the value. A successful response will be - * an [[UpdateValueResponseV2]]. - * @param requestingUser the user making the request. - * @param apiRequestID the API request ID. + * @param updateValue an [[UpdateValueV2]] representing the new version of the value. A successful response will be + * an [[UpdateValueResponseV2]]. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. + * @param apiRequestID the API request ID. */ case class UpdateValueRequestV2(updateValue: UpdateValueV2, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends ValuesResponderRequestV2 @@ -222,14 +231,14 @@ object UpdateValueRequestV2 extends KnoraJsonLDRequestReaderV2[UpdateValueReques /** * Converts JSON-LD input to a [[CreateValueRequestV2]]. * - * @param jsonLDDocument the JSON-LD input. - * @param apiRequestID the UUID of the API request. - * @param requestingUser the user making the request. - * @param responderManager a reference to the responder manager. - * @param storeManager a reference to the store manager. - * @param log a logging adapter. - * @param timeout a timeout for `ask` messages. - * @param executionContext an execution context for futures. + * @param jsonLDDocument the JSON-LD input. + * @param apiRequestID the UUID of the API request. + * @param requestingUser the user making the request. + * @param responderManager a reference to the responder manager. + * @param storeManager a reference to the store manager. + * @param featureFactoryConfig the feature factory configuration. + * @param settings the application settings. + * @param log a logging adapter. * @return a case class instance representing the input. */ override def fromJsonLD(jsonLDDocument: JsonLDDocument, @@ -237,6 +246,7 @@ object UpdateValueRequestV2 extends KnoraJsonLDRequestReaderV2[UpdateValueReques requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[UpdateValueRequestV2] = { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance @@ -286,8 +296,8 @@ object UpdateValueRequestV2 extends KnoraJsonLDRequestReaderV2[UpdateValueReques // contain knora-api:hasPermissions? val otherValuePredicates: Set[IRI] = jsonLDObject.value.keySet -- Set( - JsonLDConstants.ID, - JsonLDConstants.TYPE, + JsonLDKeywords.ID, + JsonLDKeywords.TYPE, OntologyConstants.KnoraApiV2Complex.ValueCreationDate, OntologyConstants.KnoraApiV2Complex.NewValueVersionIri ) @@ -295,7 +305,7 @@ object UpdateValueRequestV2 extends KnoraJsonLDRequestReaderV2[UpdateValueReques if (otherValuePredicates == Set(OntologyConstants.KnoraApiV2Complex.HasPermissions)) { // Yes. This is a request to change the value's permissions. - val valueType: SmartIri = jsonLDObject.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = jsonLDObject.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) val permissions = jsonLDObject.requireStringWithValidation(OntologyConstants.KnoraApiV2Complex.HasPermissions, stringFormatter.toSparqlEncodedString) FastFuture.successful( @@ -319,6 +329,7 @@ object UpdateValueRequestV2 extends KnoraJsonLDRequestReaderV2[UpdateValueReques requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, + featureFactoryConfig: FeatureFactoryConfig, settings = settings, log = log ) @@ -338,6 +349,7 @@ object UpdateValueRequestV2 extends KnoraJsonLDRequestReaderV2[UpdateValueReques } } yield UpdateValueRequestV2( updateValue = updateValue, + featureFactoryConfig = featureFactoryConfig, apiRequestID = apiRequestID, requestingUser = requestingUser ) @@ -366,8 +378,8 @@ case class UpdateValueResponseV2(valueIri: IRI, JsonLDDocument( body = JsonLDObject( Map( - JsonLDConstants.ID -> JsonLDString(valueIri), - JsonLDConstants.TYPE -> JsonLDString(valueType.toOntologySchema(ApiV2Complex).toString), + JsonLDKeywords.ID -> JsonLDString(valueIri), + JsonLDKeywords.TYPE -> JsonLDString(valueType.toOntologySchema(ApiV2Complex).toString), OntologyConstants.KnoraApiV2Complex.ValueHasUUID -> JsonLDString(stringFormatter.base64EncodeUuid(valueUUID)) ) ), @@ -383,16 +395,17 @@ case class UpdateValueResponseV2(valueIri: IRI, /** * Requests that a value is marked as deleted. A successful response will be a [[SuccessResponseV2]]. * - * @param resourceIri the IRI of the containing resource. - * @param resourceClassIri the IRI of the resource class. - * @param propertyIri the IRI of the property pointing to the value to be marked as deleted. - * @param valueIri the IRI of the value to be marked as deleted. - * @param valueTypeIri the IRI of the value class. - * @param deleteComment an optional comment explaining why the value is being marked as deleted. - * @param deleteDate an optional timestamp indicating when the value was deleted. If not supplied, - * the current time will be used. - * @param requestingUser the user making the request. - * @param apiRequestID the API request ID. + * @param resourceIri the IRI of the containing resource. + * @param resourceClassIri the IRI of the resource class. + * @param propertyIri the IRI of the property pointing to the value to be marked as deleted. + * @param valueIri the IRI of the value to be marked as deleted. + * @param valueTypeIri the IRI of the value class. + * @param deleteComment an optional comment explaining why the value is being marked as deleted. + * @param deleteDate an optional timestamp indicating when the value was deleted. If not supplied, + * the current time will be used. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. + * @param apiRequestID the API request ID. */ case class DeleteValueRequestV2(resourceIri: IRI, resourceClassIri: SmartIri, @@ -401,6 +414,7 @@ case class DeleteValueRequestV2(resourceIri: IRI, valueTypeIri: SmartIri, deleteComment: Option[String] = None, deleteDate: Option[Instant] = None, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID) extends ValuesResponderRequestV2 @@ -408,15 +422,14 @@ object DeleteValueRequestV2 extends KnoraJsonLDRequestReaderV2[DeleteValueReques /** * Converts JSON-LD input into a case class instance. * - * @param jsonLDDocument the JSON-LD input. - * @param apiRequestID the UUID of the API request. - * @param requestingUser the user making the request. - * @param responderManager a reference to the responder manager. - * @param storeManager a reference to the store manager. - * @param settings the application settings. - * @param log a logging adapter. - * @param timeout a timeout for `ask` messages. - * @param executionContext an execution context for futures. + * @param jsonLDDocument the JSON-LD input. + * @param apiRequestID the UUID of the API request. + * @param requestingUser the user making the request. + * @param responderManager a reference to the responder manager. + * @param storeManager a reference to the store manager. + * @param featureFactoryConfig the feature factory configuration. + * @param settings the application settings. + * @param log a logging adapter. * @return a case class instance representing the input. */ override def fromJsonLD(jsonLDDocument: JsonLDDocument, @@ -424,12 +437,14 @@ object DeleteValueRequestV2 extends KnoraJsonLDRequestReaderV2[DeleteValueReques requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[DeleteValueRequestV2] = { Future { fromJsonLDSync( jsonLDDocument = jsonLDDocument, apiRequestID = apiRequestID, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) } @@ -437,6 +452,7 @@ object DeleteValueRequestV2 extends KnoraJsonLDRequestReaderV2[DeleteValueReques private def fromJsonLDSync(jsonLDDocument: JsonLDDocument, apiRequestID: UUID, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM): DeleteValueRequestV2 = { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance @@ -477,6 +493,7 @@ object DeleteValueRequestV2 extends KnoraJsonLDRequestReaderV2[DeleteValueReques valueTypeIri = valueTypeIri, deleteComment = deleteComment, deleteDate = deleteDate, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = apiRequestID ) @@ -563,8 +580,8 @@ case class DeletionInfo(deleteDate: Instant, OntologyConstants.KnoraApiV2Complex.IsDeleted -> JsonLDBoolean(true), OntologyConstants.KnoraApiV2Complex.DeleteDate -> JsonLDObject( Map( - JsonLDConstants.TYPE -> JsonLDString(OntologyConstants.Xsd.DateTimeStamp), - JsonLDConstants.VALUE -> JsonLDString(deleteDate.toString) + JsonLDKeywords.TYPE -> JsonLDString(OntologyConstants.Xsd.DateTimeStamp), + JsonLDKeywords.VALUE -> JsonLDString(deleteDate.toString) ) ) ) ++ maybeDeleteCommentStatement @@ -656,8 +673,8 @@ sealed trait ReadValueV2 extends IOValueV2 { val valueSmartIri = valueIri.toSmartIri val requiredMetadata = Map( - JsonLDConstants.ID -> JsonLDString(valueIri), - JsonLDConstants.TYPE -> JsonLDString(valueContent.valueType.toString), + JsonLDKeywords.ID -> JsonLDString(valueIri), + JsonLDKeywords.TYPE -> JsonLDString(valueContent.valueType.toString), OntologyConstants.KnoraApiV2Complex.AttachedToUser -> JsonLDUtil.iriToJsonLDObject(attachedToUser), OntologyConstants.KnoraApiV2Complex.HasPermissions -> JsonLDString(permissions), OntologyConstants.KnoraApiV2Complex.UserHasPermission -> JsonLDString(userPermission.toString), @@ -1031,18 +1048,20 @@ trait ValueContentReaderV2[C <: ValueContentV2] { /** * Converts a JSON-LD object to a subclass of [[ValueContentV2]]. * - * @param jsonLDObject the JSON-LD object. - * @param requestingUser the user making the request. - * @param responderManager a reference to the responder manager. - * @param log a logging adapter. - * @param timeout a timeout for `ask` messages. - * @param executionContext an execution context for futures. + * @param jsonLDObject the JSON-LD object. + * @param requestingUser the user making the request. + * @param responderManager a reference to the responder manager. + * @param storeManager a reference to the store manager. + * @param featureFactoryConfig the feature factory configuration. + * @param settings the application settings. + * @param log a logging adapter. * @return a subclass of [[ValueContentV2]]. */ def fromJsonLDObject(jsonLDObject: JsonLDObject, requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[C] @@ -1058,73 +1077,75 @@ object ValueContentV2 extends ValueContentReaderV2[ValueContentV2] { /** * Converts a JSON-LD object to a [[ValueContentV2]]. * - * @param jsonLDObject a JSON-LD object representing a value. - * @param requestingUser the user making the request. - * @param responderManager a reference to the responder manager. - * @param log a logging adapter. - * @param timeout a timeout for `ask` messages. - * @param executionContext an execution context for futures. + * @param jsonLDObject the JSON-LD object. + * @param requestingUser the user making the request. + * @param responderManager a reference to the responder manager. + * @param storeManager a reference to the store manager. + * @param featureFactoryConfig the feature factory configuration. + * @param settings the application settings. + * @param log a logging adapter. * @return a [[ValueContentV2]]. */ override def fromJsonLDObject(jsonLDObject: JsonLDObject, requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[ValueContentV2] = { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance for { - valueType: SmartIri <- Future(jsonLDObject.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr)) + valueType: SmartIri <- Future(jsonLDObject.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr)) valueContent: ValueContentV2 <- valueType.toString match { case OntologyConstants.KnoraApiV2Complex.TextValue => - TextValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, settings = settings, log = log) + TextValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, featureFactoryConfig = featureFactoryConfig, settings = settings, log = log) case OntologyConstants.KnoraApiV2Complex.IntValue => - IntegerValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, settings = settings, log = log) + IntegerValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, featureFactoryConfig = featureFactoryConfig, settings = settings, log = log) case OntologyConstants.KnoraApiV2Complex.DecimalValue => - DecimalValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, settings = settings, log = log) + DecimalValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, featureFactoryConfig = featureFactoryConfig, settings = settings, log = log) case OntologyConstants.KnoraApiV2Complex.BooleanValue => - BooleanValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, settings = settings, log = log) + BooleanValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, featureFactoryConfig = featureFactoryConfig, settings = settings, log = log) case OntologyConstants.KnoraApiV2Complex.DateValue => - DateValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, settings = settings, log = log) + DateValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, featureFactoryConfig = featureFactoryConfig, settings = settings, log = log) case OntologyConstants.KnoraApiV2Complex.GeomValue => - GeomValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, settings = settings, log = log) + GeomValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, featureFactoryConfig = featureFactoryConfig, settings = settings, log = log) case OntologyConstants.KnoraApiV2Complex.IntervalValue => - IntervalValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, settings = settings, log = log) + IntervalValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, featureFactoryConfig = featureFactoryConfig, settings = settings, log = log) case OntologyConstants.KnoraApiV2Complex.TimeValue => - TimeValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, settings = settings, log = log) + TimeValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, featureFactoryConfig = featureFactoryConfig, settings = settings, log = log) case OntologyConstants.KnoraApiV2Complex.LinkValue => - LinkValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, settings = settings, log = log) + LinkValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, featureFactoryConfig = featureFactoryConfig, settings = settings, log = log) case OntologyConstants.KnoraApiV2Complex.ListValue => - HierarchicalListValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, settings = settings, log = log) + HierarchicalListValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, featureFactoryConfig = featureFactoryConfig, settings = settings, log = log) case OntologyConstants.KnoraApiV2Complex.UriValue => - UriValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, settings = settings, log = log) + UriValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, featureFactoryConfig = featureFactoryConfig, settings = settings, log = log) case OntologyConstants.KnoraApiV2Complex.GeonameValue => - GeonameValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, settings = settings, log = log) + GeonameValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, featureFactoryConfig = featureFactoryConfig, settings = settings, log = log) case OntologyConstants.KnoraApiV2Complex.ColorValue => - ColorValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, settings = settings, log = log) + ColorValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, featureFactoryConfig = featureFactoryConfig, settings = settings, log = log) case OntologyConstants.KnoraApiV2Complex.StillImageFileValue => - StillImageFileValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, settings = settings, log = log) + StillImageFileValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, featureFactoryConfig = featureFactoryConfig, settings = settings, log = log) case OntologyConstants.KnoraApiV2Complex.DocumentFileValue => - DocumentFileValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, settings = settings, log = log) + DocumentFileValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, featureFactoryConfig = featureFactoryConfig, settings = settings, log = log) case OntologyConstants.KnoraApiV2Complex.TextFileValue => - TextFileValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, settings = settings, log = log) + TextFileValueContentV2.fromJsonLDObject(jsonLDObject = jsonLDObject, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, featureFactoryConfig = featureFactoryConfig, settings = settings, log = log) case other => throw NotImplementedException(s"Parsing of JSON-LD value type not implemented: $other") } @@ -1268,18 +1289,20 @@ object DateValueContentV2 extends ValueContentReaderV2[DateValueContentV2] { /** * Converts a JSON-LD object to a [[DateValueContentV2]]. * - * @param jsonLDObject the JSON-LD object. - * @param responderManager a reference to the responder manager. - * @param storeManager a reference to the store manager. - * @param log a logging adapter. - * @param timeout a timeout for `ask` messages. - * @param executionContext an execution context for futures. + * @param jsonLDObject the JSON-LD object. + * @param requestingUser the user making the request. + * @param responderManager a reference to the responder manager. + * @param storeManager a reference to the store manager. + * @param featureFactoryConfig the feature factory configuration. + * @param settings the application settings. + * @param log a logging adapter. * @return a [[DateValueContentV2]]. */ override def fromJsonLDObject(jsonLDObject: JsonLDObject, requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[DateValueContentV2] = { Future(fromJsonLDObjectSync(jsonLDObject)) @@ -1637,19 +1660,20 @@ object TextValueContentV2 extends ValueContentReaderV2[TextValueContentV2] { /** * Converts a JSON-LD object to a [[TextValueContentV2]]. * - * @param jsonLDObject the JSON-LD object. - * @param requestingUser the user making the request. - * @param responderManager a reference to the responder manager. - * @param storeManager a reference to the store manager. - * @param log a logging adapter. - * @param timeout a timeout for `ask` messages. - * @param executionContext an execution context for futures. + * @param jsonLDObject the JSON-LD object. + * @param requestingUser the user making the request. + * @param responderManager a reference to the responder manager. + * @param storeManager a reference to the store manager. + * @param featureFactoryConfig the feature factory configuration. + * @param settings the application settings. + * @param log a logging adapter. * @return a [[TextValueContentV2]]. */ override def fromJsonLDObject(jsonLDObject: JsonLDObject, requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[TextValueContentV2] = { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance @@ -1665,7 +1689,11 @@ object TextValueContentV2 extends ValueContentReaderV2[TextValueContentV2] { maybeMappingFuture: Option[Future[GetMappingResponseV2]] = maybeMappingIri.map { mappingIri => for { - mappingResponse: GetMappingResponseV2 <- (responderManager ? GetMappingRequestV2(mappingIri = mappingIri, requestingUser = requestingUser)).mapTo[GetMappingResponseV2] + mappingResponse: GetMappingResponseV2 <- (responderManager ? GetMappingRequestV2( + mappingIri = mappingIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + )).mapTo[GetMappingResponseV2] } yield mappingResponse } @@ -1778,6 +1806,7 @@ object IntegerValueContentV2 extends ValueContentReaderV2[IntegerValueContentV2] requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[IntegerValueContentV2] = { Future(fromJsonLDObjectSync(jsonLDObject)) @@ -1870,6 +1899,7 @@ object DecimalValueContentV2 extends ValueContentReaderV2[DecimalValueContentV2] requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[DecimalValueContentV2] = { Future(fromJsonLDObjectSync(jsonLDObject)) @@ -1959,6 +1989,7 @@ object BooleanValueContentV2 extends ValueContentReaderV2[BooleanValueContentV2] requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[BooleanValueContentV2] = { Future(fromJsonLDObjectSync(jsonLDObject)) @@ -2053,6 +2084,7 @@ object GeomValueContentV2 extends ValueContentReaderV2[GeomValueContentV2] { requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[GeomValueContentV2] = { Future(fromJsonLDObjectSync(jsonLDObject)) @@ -2162,6 +2194,7 @@ object IntervalValueContentV2 extends ValueContentReaderV2[IntervalValueContentV requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[IntervalValueContentV2] = { Future(fromJsonLDObjectSync(jsonLDObject)) @@ -2273,6 +2306,7 @@ object TimeValueContentV2 extends ValueContentReaderV2[TimeValueContentV2] { requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[TimeValueContentV2] = { Future(fromJsonLDObjectSync(jsonLDObject)) @@ -2381,6 +2415,7 @@ object HierarchicalListValueContentV2 extends ValueContentReaderV2[HierarchicalL requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[HierarchicalListValueContentV2] = { Future(fromJsonLDObjectSync(jsonLDObject)) @@ -2480,6 +2515,7 @@ object ColorValueContentV2 extends ValueContentReaderV2[ColorValueContentV2] { requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[ColorValueContentV2] = { Future(fromJsonLDObjectSync(jsonLDObject)) @@ -2575,6 +2611,7 @@ object UriValueContentV2 extends ValueContentReaderV2[UriValueContentV2] { requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[UriValueContentV2] = { Future(fromJsonLDObjectSync(jsonLDObject)) @@ -2674,6 +2711,7 @@ object GeonameValueContentV2 extends ValueContentReaderV2[GeonameValueContentV2] requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[GeonameValueContentV2] = { Future(fromJsonLDObjectSync(jsonLDObject)) @@ -2839,6 +2877,7 @@ object StillImageFileValueContentV2 extends ValueContentReaderV2[StillImageFileV requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[StillImageFileValueContentV2] = { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance @@ -2944,6 +2983,7 @@ object DocumentFileValueContentV2 extends ValueContentReaderV2[DocumentFileValue requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[DocumentFileValueContentV2] = { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance @@ -3033,6 +3073,7 @@ object TextFileValueContentV2 extends ValueContentReaderV2[TextFileValueContentV requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[TextFileValueContentV2] = { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance @@ -3167,6 +3208,7 @@ object LinkValueContentV2 extends ValueContentReaderV2[LinkValueContentV2] { requestingUser: UserADM, responderManager: ActorRef, storeManager: ActorRef, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[LinkValueContentV2] = { Future(fromJsonLDObjectSync(jsonLDObject)) diff --git a/webapi/src/main/scala/org/knora/webapi/responders/BUILD.bazel b/webapi/src/main/scala/org/knora/webapi/responders/BUILD.bazel index e2189c1b88..806ebf214d 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/BUILD.bazel +++ b/webapi/src/main/scala/org/knora/webapi/responders/BUILD.bazel @@ -14,6 +14,7 @@ scala_library( "//webapi/src/main/scala/org/knora/webapi/instrumentation", "//webapi/src/main/scala/org/knora/webapi/messages", "//webapi/src/main/scala/org/knora/webapi/settings", + "//webapi/src/main/scala/org/knora/webapi/feature", "//webapi/src/main/scala/org/knora/webapi/util", "//webapi/src/main/scala/org/knora/webapi/util/cache", "@maven//:com_typesafe_akka_akka_actor_2_12", diff --git a/webapi/src/main/scala/org/knora/webapi/responders/admin/GroupsResponderADM.scala b/webapi/src/main/scala/org/knora/webapi/responders/admin/GroupsResponderADM.scala index 387fb10153..e382b7d665 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/admin/GroupsResponderADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/admin/GroupsResponderADM.scala @@ -25,6 +25,7 @@ import akka.http.scaladsl.util.FastFuture import akka.pattern._ import org.knora.webapi._ import org.knora.webapi.exceptions._ +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.admin.responder.groupsmessages._ import org.knora.webapi.messages.admin.responder.projectsmessages.{ProjectADM, ProjectGetADM, ProjectIdentifierADM} @@ -51,25 +52,26 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond * Receives a message extending [[ProjectsResponderRequestV1]], and returns an appropriate response message */ def receive(msg: GroupsResponderRequestADM) = msg match { - case GroupsGetADM(requestingUser) => groupsGetADM(requestingUser) - case GroupsGetRequestADM(requestingUser) => groupsGetRequestADM(requestingUser) - case GroupGetADM(groupIri, requestingUser) => groupGetADM(groupIri, requestingUser) - case MultipleGroupsGetRequestADM(groupIris, requestingUser) => multipleGroupsGetRequestADM(groupIris, requestingUser) - case GroupGetRequestADM(groupIri, requestingUser) => groupGetRequestADM(groupIri, requestingUser) - case GroupMembersGetRequestADM(groupIri, requestingUser) => groupMembersGetRequestADM(groupIri, requestingUser) - case GroupCreateRequestADM(newGroupInfo, requestingUser, apiRequestID) => createGroupADM(newGroupInfo, requestingUser, apiRequestID) - case GroupChangeRequestADM(groupIri, changeGroupRequest, requestingUser, apiRequestID) => changeGroupBasicInformationRequestADM(groupIri, changeGroupRequest, requestingUser, apiRequestID) - case GroupChangeStatusRequestADM(groupIri, changeGroupRequest, requestingUser, apiRequestID) => changeGroupStatusRequestADM(groupIri, changeGroupRequest, requestingUser, apiRequestID) + case GroupsGetADM(featureFactoryConfig, requestingUser) => groupsGetADM(featureFactoryConfig, requestingUser) + case GroupsGetRequestADM(featureFactoryConfig, requestingUser) => groupsGetRequestADM(featureFactoryConfig, requestingUser) + case GroupGetADM(groupIri, featureFactoryConfig, requestingUser) => groupGetADM(groupIri, featureFactoryConfig, requestingUser) + case MultipleGroupsGetRequestADM(groupIris, featureFactoryConfig, requestingUser) => multipleGroupsGetRequestADM(groupIris, featureFactoryConfig, requestingUser) + case GroupGetRequestADM(groupIri, featureFactoryConfig, requestingUser) => groupGetRequestADM(groupIri, featureFactoryConfig, requestingUser) + case GroupMembersGetRequestADM(groupIri, featureFactoryConfig, requestingUser) => groupMembersGetRequestADM(groupIri, featureFactoryConfig, requestingUser) + case GroupCreateRequestADM(newGroupInfo, featureFactoryConfig, requestingUser, apiRequestID) => createGroupADM(newGroupInfo, featureFactoryConfig, requestingUser, apiRequestID) + case GroupChangeRequestADM(groupIri, changeGroupRequest, featureFactoryConfig, requestingUser, apiRequestID) => changeGroupBasicInformationRequestADM(groupIri, changeGroupRequest, featureFactoryConfig, requestingUser, apiRequestID) + case GroupChangeStatusRequestADM(groupIri, changeGroupRequest, featureFactoryConfig, requestingUser, apiRequestID) => changeGroupStatusRequestADM(groupIri, changeGroupRequest, featureFactoryConfig, requestingUser, apiRequestID) case other => handleUnexpectedMessage(other, log, this.getClass.getName) } /** * Gets all the groups (without built-in groups) and returns them as a sequence of [[GroupADM]]. * - * @param requestingUser the user making the request. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return all the groups as a sequence of [[GroupADM]]. */ - private def groupsGetADM(requestingUser: UserADM): Future[Seq[GroupADM]] = { + private def groupsGetADM(featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM): Future[Seq[GroupADM]] = { log.debug("groupsGetADM") @@ -78,7 +80,11 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond triplestore = settings.triplestoreType, maybeIri = None ).toString()) - groupsResponse <- (storeManager ? SparqlExtendedConstructRequest(sparqlQuery)).mapTo[SparqlExtendedConstructResponse] + + groupsResponse <- (storeManager ? SparqlExtendedConstructRequest( + sparql = sparqlQuery, + featureFactoryConfig = featureFactoryConfig + )).mapTo[SparqlExtendedConstructResponse] statements = groupsResponse.statements @@ -88,7 +94,12 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond val projectIri: IRI = propsMap.getOrElse(OntologyConstants.KnoraAdmin.BelongsToProject.toSmartIri, throw InconsistentTriplestoreDataException(s"Group $groupIri has no project attached")).head.asInstanceOf[IriLiteralV2].value for { - maybeProjectADM: Option[ProjectADM] <- (responderManager ? ProjectGetADM(ProjectIdentifierADM(maybeIri = Some(projectIri)), requestingUser = KnoraSystemInstances.Users.SystemUser)).mapTo[Option[ProjectADM]] + maybeProjectADM: Option[ProjectADM] <- (responderManager ? ProjectGetADM( + identifier = ProjectIdentifierADM(maybeIri = Some(projectIri)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + )).mapTo[Option[ProjectADM]] + projectADM: ProjectADM = maybeProjectADM match { case Some(project) => project case None => throw InconsistentTriplestoreDataException(s"Project $projectIri was referenced by $groupIri but was not found in the triplestore.") @@ -115,9 +126,13 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond * @param requestingUser the user initiating the request. * @return all the groups as a [[GroupsGetResponseADM]]. */ - private def groupsGetRequestADM(requestingUser: UserADM): Future[GroupsGetResponseADM] = { + private def groupsGetRequestADM(featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM): Future[GroupsGetResponseADM] = { for { - maybeGroupsListToReturn <- groupsGetADM(requestingUser) + maybeGroupsListToReturn <- groupsGetADM( + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) + result = maybeGroupsListToReturn match { case groups: Seq[GroupADM] if groups.nonEmpty => GroupsGetResponseADM(groups = groups) case _ => throw NotFoundException(s"No groups found") @@ -133,7 +148,7 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond * @param requestingUser the user initiating the request. * @return information about the group as a [[GroupADM]] */ - private def groupGetADM(groupIri: IRI, requestingUser: UserADM): Future[Option[GroupADM]] = { + private def groupGetADM(groupIri: IRI, featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM): Future[Option[GroupADM]] = { for { sparqlQuery <- Future(org.knora.webapi.messages.twirl.queries.sparql.admin.txt.getGroups( @@ -141,16 +156,20 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond maybeIri = Some(groupIri) ).toString()) - groupResponse <- (storeManager ? SparqlExtendedConstructRequest(sparqlQuery)).mapTo[SparqlExtendedConstructResponse] - - _ = if (groupResponse.statements.isEmpty) { - } + groupResponse <- (storeManager ? SparqlExtendedConstructRequest( + sparql = sparqlQuery, + featureFactoryConfig = featureFactoryConfig + )).mapTo[SparqlExtendedConstructResponse] maybeGroup: Option[GroupADM] <- if (groupResponse.statements.isEmpty) { FastFuture.successful(None) } else { - statements2GroupADM(statements = groupResponse.statements.head, requestingUser = requestingUser) + statements2GroupADM( + statements = groupResponse.statements.head, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) } _ = log.debug("groupGetADM - result: {}", maybeGroup) @@ -161,14 +180,20 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond /** * Gets the group with the given group IRI and returns the information as a [[GroupGetResponseADM]]. * - * @param groupIri the IRI of the group requested. - * @param requestingUser the user initiating the request. + * @param groupIri the IRI of the group requested. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. * @return information about the group as a [[GroupGetResponseADM]]. */ - private def groupGetRequestADM(groupIri: IRI, requestingUser: UserADM): Future[GroupGetResponseADM] = { + private def groupGetRequestADM(groupIri: IRI, featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM): Future[GroupGetResponseADM] = { for { - maybeGroupADM: Option[GroupADM] <- groupGetADM(groupIri, requestingUser) + maybeGroupADM: Option[GroupADM] <- groupGetADM( + groupIri = groupIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) + result = maybeGroupADM match { case Some(group) => GroupGetResponseADM(group = group) case None => throw NotFoundException(s"Group <$groupIri> not found") @@ -183,9 +208,16 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond * @param requestingUser the user initiating the request. * @return information about the group as a set of [[GroupGetResponseADM]] objects. */ - private def multipleGroupsGetRequestADM(groupIris: Set[IRI], requestingUser: UserADM): Future[Set[GroupGetResponseADM]] = { + private def multipleGroupsGetRequestADM(groupIris: Set[IRI], + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[Set[GroupGetResponseADM]] = { val groupResponseFutures: Set[Future[GroupGetResponseADM]] = groupIris.map { - groupIri => groupGetRequestADM(groupIri = groupIri, requestingUser = requestingUser) + groupIri => + groupGetRequestADM( + groupIri = groupIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) } Future.sequence(groupResponseFutures) @@ -194,16 +226,23 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond /** * Gets the members with the given group IRI and returns the information as a sequence of [[UserADM]]. * - * @param groupIri the IRI of the group. - * @param requestingUser the user initiating the request. + * @param groupIri the IRI of the group. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. * @return A sequence of [[UserADM]] */ - private def groupMembersGetADM(groupIri: IRI, requestingUser: UserADM): Future[Seq[UserADM]] = { + private def groupMembersGetADM(groupIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[Seq[UserADM]] = { log.debug("groupMembersGetADM - groupIri: {}", groupIri) for { - maybeGroupADM: Option[GroupADM] <- groupGetADM(groupIri, KnoraSystemInstances.Users.SystemUser) + maybeGroupADM: Option[GroupADM] <- groupGetADM( + groupIri = groupIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) _ = maybeGroupADM match { case Some(group) => @@ -235,7 +274,12 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond _ = log.debug("groupMembersGetRequestADM - groupMemberIris: {}", groupMemberIris) maybeUsersFutures: Seq[Future[Option[UserADM]]] = groupMemberIris.map { - userIri => (responderManager ? UserGetADM(UserIdentifierADM(maybeIri = Some(userIri)), userInformationTypeADM = UserInformationTypeADM.RESTRICTED, requestingUser = KnoraSystemInstances.Users.SystemUser)).mapTo[Option[UserADM]] + userIri => (responderManager ? UserGetADM( + UserIdentifierADM(maybeIri = Some(userIri)), + userInformationTypeADM = UserInformationTypeADM.RESTRICTED, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + )).mapTo[Option[UserADM]] } maybeUsers: Seq[Option[UserADM]] <- Future.sequence(maybeUsersFutures) users: Seq[UserADM] = maybeUsers.flatten @@ -249,16 +293,24 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond * Gets the group members with the given group IRI and returns the information as a [[GroupMembersGetResponseADM]]. * Only project and system admins are allowed to access this information. * - * @param groupIri the IRI of the group. - * @param requestingUser the user initiating the request. + * @param groupIri the IRI of the group. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. * @return A [[GroupMembersGetResponseADM]] */ - private def groupMembersGetRequestADM(groupIri: IRI, requestingUser: UserADM): Future[GroupMembersGetResponseADM] = { + private def groupMembersGetRequestADM(groupIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[GroupMembersGetResponseADM] = { log.debug("groupMembersGetRequestADM - groupIri: {}", groupIri) for { - maybeMembersListToReturn <- groupMembersGetADM(groupIri, requestingUser) + maybeMembersListToReturn <- groupMembersGetADM( + groupIri = groupIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) + result = maybeMembersListToReturn match { case members: Seq[UserADM] if members.nonEmpty => GroupMembersGetResponseADM(members = members) case _ => throw NotFoundException(s"No members found.") @@ -269,12 +321,16 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond /** * Create a new group. * - * @param createRequest the create request information. - * @param requestingUser the user making the request. - * @param apiRequestID the unique request ID. + * @param createRequest the create request information. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. + * @param apiRequestID the unique request ID. * @return a [[GroupOperationResponseADM]] */ - private def createGroupADM(createRequest: CreateGroupApiRequestADM, requestingUser: UserADM, apiRequestID: UUID): Future[GroupOperationResponseADM] = { + private def createGroupADM(createRequest: CreateGroupApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): Future[GroupOperationResponseADM] = { log.debug("createGroupADM - createRequest: {}", createRequest) @@ -294,7 +350,11 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond throw DuplicateValueException(s"Group with the name '${createRequest.name}' already exists") } - maybeProjectADM: Option[ProjectADM] <- (responderManager ? ProjectGetADM(ProjectIdentifierADM(maybeIri = Some(createRequest.project)), requestingUser = KnoraSystemInstances.Users.SystemUser)).mapTo[Option[ProjectADM]] + maybeProjectADM: Option[ProjectADM] <- (responderManager ? ProjectGetADM( + identifier = ProjectIdentifierADM(maybeIri = Some(createRequest.project)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + )).mapTo[Option[ProjectADM]] projectADM: ProjectADM = maybeProjectADM match { case Some(p) => p @@ -323,7 +383,12 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond /* Verify that the group was created */ /* Verify that the project was updated. */ - maybeCreatedGroup <- groupGetADM(groupIri = groupIri, requestingUser = KnoraSystemInstances.Users.SystemUser) + maybeCreatedGroup <- groupGetADM( + groupIri = groupIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) + createdGroup: GroupADM = maybeCreatedGroup.getOrElse(throw UpdateNotPerformedException(s"Group was not created. Please report this as a possible bug.")) } yield GroupOperationResponseADM(group = createdGroup) @@ -342,13 +407,18 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond /** * Change group's basic information. * - * @param groupIri the IRI of the group we want to change. - * @param changeGroupRequest the change request. - * @param requestingUser the user making the request. - * @param apiRequestID the unique request ID. + * @param groupIri the IRI of the group we want to change. + * @param changeGroupRequest the change request. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. + * @param apiRequestID the unique request ID. * @return a [[GroupOperationResponseADM]]. */ - private def changeGroupBasicInformationRequestADM(groupIri: IRI, changeGroupRequest: ChangeGroupApiRequestADM, requestingUser: UserADM, apiRequestID: UUID): Future[GroupOperationResponseADM] = { + private def changeGroupBasicInformationRequestADM(groupIri: IRI, + changeGroupRequest: ChangeGroupApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): Future[GroupOperationResponseADM] = { /** * The actual change group task run with an IRI lock. @@ -361,7 +431,12 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond ) /* Get the project IRI which also verifies that the group exists. */ - maybeGroupADM <- groupGetADM(groupIri, KnoraSystemInstances.Users.SystemUser) + maybeGroupADM <- groupGetADM( + groupIri = groupIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) + groupADM: GroupADM = maybeGroupADM.getOrElse(throw NotFoundException(s"Group <$groupIri> not found. Aborting update request.")) /* check if the requesting user is allowed to perform updates */ @@ -378,7 +453,12 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond selfjoin = changeGroupRequest.selfjoin ) - result <- updateGroupADM(groupIri, groupUpdatePayload, KnoraSystemInstances.Users.SystemUser) + result <- updateGroupADM( + groupIri = groupIri, + groupUpdatePayload = groupUpdatePayload, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) } yield result @@ -396,13 +476,18 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond /** * Change group's basic information. * - * @param groupIri the IRI of the group we want to change. - * @param changeGroupRequest the change request. - * @param requestingUser the user making the request. - * @param apiRequestID the unique request ID. + * @param groupIri the IRI of the group we want to change. + * @param changeGroupRequest the change request. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. + * @param apiRequestID the unique request ID. * @return a [[GroupOperationResponseADM]]. */ - private def changeGroupStatusRequestADM(groupIri: IRI, changeGroupRequest: ChangeGroupApiRequestADM, requestingUser: UserADM, apiRequestID: UUID): Future[GroupOperationResponseADM] = { + private def changeGroupStatusRequestADM(groupIri: IRI, + changeGroupRequest: ChangeGroupApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): Future[GroupOperationResponseADM] = { /** * The actual change group task run with an IRI lock. @@ -415,7 +500,12 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond ) /* Get the project IRI which also verifies that the group exists. */ - maybeGroupADM <- groupGetADM(groupIri, KnoraSystemInstances.Users.SystemUser) + maybeGroupADM <- groupGetADM( + groupIri = groupIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) + groupADM: GroupADM = maybeGroupADM.getOrElse(throw NotFoundException(s"Group <$groupIri> not found. Aborting update request.")) /* check if the requesting user is allowed to perform updates */ @@ -430,10 +520,19 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond ) // update group status - updateGroupResult: GroupOperationResponseADM <- updateGroupADM(groupIri, groupUpdatePayload, KnoraSystemInstances.Users.SystemUser) + updateGroupResult: GroupOperationResponseADM <- updateGroupADM( + groupIri = groupIri, + groupUpdatePayload = groupUpdatePayload, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) // remove all members from group if status is false - operationResponse <- removeGroupMembersIfNecessary(updateGroupResult.group, apiRequestID) + operationResponse <- removeGroupMembersIfNecessary( + changedGroup = updateGroupResult.group, + featureFactoryConfig = featureFactoryConfig, + apiRequestID = apiRequestID + ) } yield operationResponse @@ -451,12 +550,16 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond /** * Main group update method. * - * @param groupIri the IRI of the group we are updating. - * @param groupUpdatePayload the payload holding the information which we want to update. - * @param requestingUser the profile of the user making the request. + * @param groupIri the IRI of the group we are updating. + * @param groupUpdatePayload the payload holding the information which we want to update. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the profile of the user making the request. * @return a [[GroupOperationResponseADM]] */ - private def updateGroupADM(groupIri: IRI, groupUpdatePayload: GroupUpdatePayloadADM, requestingUser: UserADM): Future[GroupOperationResponseADM] = { + private def updateGroupADM(groupIri: IRI, + groupUpdatePayload: GroupUpdatePayloadADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[GroupOperationResponseADM] = { log.debug("updateGroupADM - groupIri: {}, groupUpdatePayload: {}", groupIri, groupUpdatePayload) @@ -471,7 +574,12 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond for { /* Verify that the group exists. */ - maybeGroupADM <- groupGetADM(groupIri = groupIri, requestingUser = KnoraSystemInstances.Users.SystemUser) + maybeGroupADM <- groupGetADM( + groupIri = groupIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) + groupADM: GroupADM = maybeGroupADM.getOrElse(throw NotFoundException(s"Group <$groupIri> not found. Aborting update request.")) /* Verify that the potentially new name is unique */ @@ -504,7 +612,12 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond updateGroupResponse <- (storeManager ? SparqlUpdateRequest(updateProjectSparqlString)).mapTo[SparqlUpdateResponse] /* Verify that the project was updated. */ - maybeUpdatedGroup <- groupGetADM(groupIri = groupIri, requestingUser = KnoraSystemInstances.Users.SystemUser) + maybeUpdatedGroup <- groupGetADM( + groupIri = groupIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) + updatedGroup: GroupADM = maybeUpdatedGroup.getOrElse(throw UpdateNotPerformedException("Group was not updated. Please report this as a possible bug.")) //_ = log.debug("updateProjectV1 - projectUpdatePayload: {} / updatedProject: {}", projectUpdatePayload, updatedProject) @@ -542,11 +655,14 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond /** * Helper method that turns SPARQL result rows into a [[GroupADM]]. * - * @param statements results from the SPARQL query representing information about the group. - * @param requestingUser the user that is making the request. + * @param statements results from the SPARQL query representing information about the group. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user that is making the request. * @return a [[GroupADM]] representing information about the group. */ - private def statements2GroupADM(statements: (SubjectV2, Map[SmartIri, Seq[LiteralV2]]), requestingUser: UserADM): Future[Option[GroupADM]] = { + private def statements2GroupADM(statements: (SubjectV2, Map[SmartIri, Seq[LiteralV2]]), + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[Option[GroupADM]] = { log.debug("statements2GroupADM - statements: {}", statements) @@ -564,7 +680,12 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond if (propsMap.nonEmpty) { for { projectIri <- projectIriFuture - maybeProject: Option[ProjectADM] <- (responderManager ? ProjectGetADM(ProjectIdentifierADM(maybeIri = Some(projectIri)), requestingUser = KnoraSystemInstances.Users.SystemUser)).mapTo[Option[ProjectADM]] + maybeProject: Option[ProjectADM] <- (responderManager ? ProjectGetADM( + identifier = ProjectIdentifierADM(maybeIri = Some(projectIri)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + )).mapTo[Option[ProjectADM]] + project: ProjectADM = maybeProject.getOrElse(throw InconsistentTriplestoreDataException(s"Group $groupIri has no project attached.")) groupADM: GroupADM = GroupADM( @@ -623,11 +744,14 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond * In the case that the group was deactivated (status = false), the * group members need to be removed from the group. * - * @param changedGroup the group with the new status. - * @param apiRequestID the unique request ID. + * @param changedGroup the group with the new status. + * @param featureFactoryConfig the feature factory configuration. + * @param apiRequestID the unique request ID. * @return a [[GroupOperationResponseADM]] */ - private def removeGroupMembersIfNecessary(changedGroup: GroupADM, apiRequestID: UUID): Future[GroupOperationResponseADM] = { + private def removeGroupMembersIfNecessary(changedGroup: GroupADM, + featureFactoryConfig: FeatureFactoryConfig, + apiRequestID: UUID): Future[GroupOperationResponseADM] = { if (changedGroup.status) { // group active. no need to remove members. @@ -637,10 +761,20 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond // group deactivated. need to remove members. log.debug("removeGroupMembersIfNecessary - group deactivated. need to remove members.") for { - members: Seq[UserADM] <- groupMembersGetADM(changedGroup.id, KnoraSystemInstances.Users.SystemUser) + members: Seq[UserADM] <- groupMembersGetADM( + groupIri = changedGroup.id, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) seqOfFutures: Seq[Future[UserOperationResponseADM]] = members.map { user: UserADM => - (responderManager ? UserGroupMembershipRemoveRequestADM(userIri = user.id, groupIri = changedGroup.id, requestingUser = KnoraSystemInstances.Users.SystemUser, apiRequestID = apiRequestID)).mapTo[UserOperationResponseADM] + (responderManager ? UserGroupMembershipRemoveRequestADM( + userIri = user.id, + groupIri = changedGroup.id, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser, + apiRequestID = apiRequestID + )).mapTo[UserOperationResponseADM] } userOperationResults: Seq[UserOperationResponseADM] <- Future.sequence(seqOfFutures) diff --git a/webapi/src/main/scala/org/knora/webapi/responders/admin/ListsResponderADM.scala b/webapi/src/main/scala/org/knora/webapi/responders/admin/ListsResponderADM.scala index 4208be486f..d41b77edc4 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/admin/ListsResponderADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/admin/ListsResponderADM.scala @@ -25,6 +25,7 @@ import akka.http.scaladsl.util.FastFuture import akka.pattern._ import org.knora.webapi._ import org.knora.webapi.exceptions._ +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.admin.responder.listsmessages.ListsMessagesUtilADM._ import org.knora.webapi.messages.admin.responder.listsmessages._ @@ -53,14 +54,14 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde * Receives a message of type [[ListsResponderRequestADM]], and returns an appropriate response message. */ def receive(msg: ListsResponderRequestADM) = msg match { - case ListsGetRequestADM(projectIri, requestingUser) => listsGetRequestADM(projectIri, requestingUser) - case ListGetRequestADM(listIri, requestingUser) => listGetRequestADM(listIri, requestingUser) - case ListInfoGetRequestADM(listIri, requestingUser) => listInfoGetRequestADM(listIri, requestingUser) - case ListNodeInfoGetRequestADM(listIri, requestingUser) => listNodeInfoGetRequestADM(listIri, requestingUser) + case ListsGetRequestADM(projectIri, featureFactoryConfig, requestingUser) => listsGetRequestADM(projectIri, featureFactoryConfig, requestingUser) + case ListGetRequestADM(listIri, featureFactoryConfig, requestingUser) => listGetRequestADM(listIri, featureFactoryConfig, requestingUser) + case ListInfoGetRequestADM(listIri, featureFactoryConfig, requestingUser) => listInfoGetRequestADM(listIri, featureFactoryConfig, requestingUser) + case ListNodeInfoGetRequestADM(listIri, featureFactoryConfig, requestingUser) => listNodeInfoGetRequestADM(listIri, featureFactoryConfig, requestingUser) case NodePathGetRequestADM(iri, requestingUser) => nodePathGetAdminRequest(iri, requestingUser) - case ListCreateRequestADM(createListRequest, requestingUser, apiRequestID) => listCreateRequestADM(createListRequest, requestingUser, apiRequestID) - case ListInfoChangeRequestADM(listIri, changeListRequest, requestingUser, apiRequestID) => listInfoChangeRequest(listIri, changeListRequest, requestingUser, apiRequestID) - case ListChildNodeCreateRequestADM(parentNodeIri, createListNodeRequest, requestingUser, apiRequestID) => listChildNodeCreateRequestADM(parentNodeIri, createListNodeRequest, requestingUser, apiRequestID) + case ListCreateRequestADM(createListRequest, featureFactoryConfig, requestingUser, apiRequestID) => listCreateRequestADM(createListRequest, featureFactoryConfig, requestingUser, apiRequestID) + case ListInfoChangeRequestADM(listIri, changeListRequest, featureFactoryConfig, requestingUser, apiRequestID) => listInfoChangeRequest(listIri, changeListRequest, featureFactoryConfig, requestingUser, apiRequestID) + case ListChildNodeCreateRequestADM(parentNodeIri, createListNodeRequest, featureFactoryConfig, requestingUser, apiRequestID) => listChildNodeCreateRequestADM(parentNodeIri, createListNodeRequest, featureFactoryConfig, requestingUser, apiRequestID) case other => handleUnexpectedMessage(other, log, this.getClass.getName) } @@ -70,11 +71,14 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde * (as lists can be very large), we only return the head of the list, i.e. the root node without * any children. * - * @param projectIri the IRI of the project the list belongs to. - * @param requestingUser the user making the request. + * @param projectIri the IRI of the project the list belongs to. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return a [[ListsGetResponseADM]]. */ - private def listsGetRequestADM(projectIri: Option[IRI], requestingUser: UserADM): Future[ListsGetResponseADM] = { + private def listsGetRequestADM(projectIri: Option[IRI], + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[ListsGetResponseADM] = { // log.debug("listsGetRequestV2") @@ -84,7 +88,10 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde maybeProjectIri = projectIri ).toString()) - listsResponse <- (storeManager ? SparqlExtendedConstructRequest(sparqlQuery)).mapTo[SparqlExtendedConstructResponse] + listsResponse <- (storeManager ? SparqlExtendedConstructRequest( + sparql = sparqlQuery, + featureFactoryConfig = featureFactoryConfig + )).mapTo[SparqlExtendedConstructResponse] // _ = log.debug("listsGetAdminRequest - listsResponse: {}", listsResponse ) @@ -115,11 +122,14 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde /** * Retrieves a complete list (root and all children) from the triplestore and returns it as a optional [[ListADM]]. * - * @param rootNodeIri the Iri if the root node of the list to be queried. - * @param requestingUser the user making the request. + * @param rootNodeIri the Iri if the root node of the list to be queried. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return a optional [[ListADM]]. */ - private def listGetADM(rootNodeIri: IRI, requestingUser: UserADM): Future[Option[ListADM]] = { + private def listGetADM(rootNodeIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[Option[ListADM]] = { for { // this query will give us only the information about the root node. @@ -130,9 +140,18 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde maybeList: Option[ListADM] <- if (exists) { for { // here we know that the list exists and it is fine if children is an empty list - children: Seq[ListChildNodeADM] <- getChildren(rootNodeIri, shallow = false, KnoraSystemInstances.Users.SystemUser) + children: Seq[ListChildNodeADM] <- getChildren( + ofNodeIri = rootNodeIri, + shallow = false, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) - maybeRootNodeInfo <- listNodeInfoGetADM(rootNodeIri, KnoraSystemInstances.Users.SystemUser) + maybeRootNodeInfo <- listNodeInfoGetADM( + nodeIri = rootNodeIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) // _ = log.debug(s"listGetADM - maybeRootNodeInfo: {}", maybeRootNodeInfo) @@ -154,14 +173,22 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde /** * Retrieves a complete list (root and all children) from the triplestore and returns it as a [[ListGetResponseADM]]. * - * @param rootNodeIri the Iri if the root node of the list to be queried. - * @param requestingUser the user making the request. + * @param rootNodeIri the Iri if the root node of the list to be queried. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return a [[ListGetResponseADM]]. */ - private def listGetRequestADM(rootNodeIri: IRI, requestingUser: UserADM): Future[ListGetResponseADM] = { + private def listGetRequestADM(rootNodeIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[ListGetResponseADM] = { for { - maybeListADM <- listGetADM(rootNodeIri, requestingUser) + maybeListADM <- listGetADM( + rootNodeIri = rootNodeIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) + result = maybeListADM match { case Some(list) => ListGetResponseADM(list = list) case None => throw NotFoundException(s"List '$rootNodeIri' not found") @@ -172,13 +199,20 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde /** * Retrieves information about a list (root) node. * - * @param listIri the Iri if the list (root node) to be queried. - * @param requestingUser the user making the request. + * @param listIri the Iri if the list (root node) to be queried. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return a [[ListInfoGetResponseADM]]. */ - private def listInfoGetRequestADM(listIri: IRI, requestingUser: UserADM): Future[ListInfoGetResponseADM] = { + private def listInfoGetRequestADM(listIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[ListInfoGetResponseADM] = { for { - listNodeInfo <- listNodeInfoGetADM(nodeIri = listIri, requestingUser = requestingUser) + listNodeInfo <- listNodeInfoGetADM( + nodeIri = listIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) // _ = log.debug(s"listInfoGetRequestADM - listNodeInfo: {}", listNodeInfo) @@ -197,11 +231,14 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde * Retrieves information about a single node (without information about children). The single node can be the * lists root node or child node * - * @param nodeIri the Iri if the list node to be queried. - * @param requestingUser the user making the request. + * @param nodeIri the Iri if the list node to be queried. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return a optional [[ListNodeInfoADM]]. */ - private def listNodeInfoGetADM(nodeIri: IRI, requestingUser: UserADM): Future[Option[ListNodeInfoADM]] = { + private def listNodeInfoGetADM(nodeIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[Option[ListNodeInfoADM]] = { for { sparqlQuery <- Future(org.knora.webapi.messages.twirl.queries.sparql.admin.txt.getListNode( triplestore = settings.triplestoreType, @@ -210,7 +247,10 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde // _ = log.debug("listNodeInfoGetADM - sparqlQuery: {}", sparqlQuery) - listNodeResponse <- (storeManager ? SparqlExtendedConstructRequest(sparqlQuery)).mapTo[SparqlExtendedConstructResponse] + listNodeResponse <- (storeManager ? SparqlExtendedConstructRequest( + sparql = sparqlQuery, + featureFactoryConfig = featureFactoryConfig + )).mapTo[SparqlExtendedConstructResponse] statements: Map[SubjectV2, Map[SmartIri, Seq[LiteralV2]]] = listNodeResponse.statements @@ -290,13 +330,21 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde * Retrieves information about a single node (without information about children). The single node can be the * lists root node or child node * - * @param nodeIri the IRI of the list node to be queried. - * @param requestingUser the user making the request. + * @param nodeIri the IRI of the list node to be queried. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return a [[ListNodeInfoGetResponseADM]]. */ - private def listNodeInfoGetRequestADM(nodeIri: IRI, requestingUser: UserADM): Future[ListNodeInfoGetResponseADM] = { + private def listNodeInfoGetRequestADM(nodeIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[ListNodeInfoGetResponseADM] = { for { - maybeListNodeInfoADM: Option[ListNodeInfoADM] <- listNodeInfoGetADM(nodeIri, requestingUser) + maybeListNodeInfoADM: Option[ListNodeInfoADM] <- listNodeInfoGetADM( + nodeIri = nodeIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) + result = maybeListNodeInfoADM match { case Some(nodeInfo) => ListNodeInfoGetResponseADM(nodeinfo = nodeInfo) case None => throw NotFoundException(s"List node '$nodeIri' not found") @@ -308,12 +356,16 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde /** * Retrieves a complete node including children. The node can be the lists root node or child node. * - * @param nodeIri the IRI of the list node to be queried. - * @param shallow denotes if all children or only the immediate children will be returned. - * @param requestingUser the user making the request. + * @param nodeIri the IRI of the list node to be queried. + * @param shallow denotes if all children or only the immediate children will be returned. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return a optional [[ListNodeADM]] */ - private def listNodeGetADM(nodeIri: IRI, shallow: Boolean, requestingUser: UserADM): Future[Option[ListNodeADM]] = { + private def listNodeGetADM(nodeIri: IRI, + shallow: Boolean, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[Option[ListNodeADM]] = { for { // this query will give us only the information about the root node. sparqlQuery <- Future(org.knora.webapi.messages.twirl.queries.sparql.admin.txt.getListNode( @@ -321,14 +373,22 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde nodeIri = nodeIri ).toString()) - listInfoResponse <- (storeManager ? SparqlExtendedConstructRequest(sparqlQuery)).mapTo[SparqlExtendedConstructResponse] + listInfoResponse <- (storeManager ? SparqlExtendedConstructRequest( + sparql = sparqlQuery, + featureFactoryConfig = featureFactoryConfig + )).mapTo[SparqlExtendedConstructResponse] // _ = log.debug(s"listGetADM - statements: {}", MessageUtil.toSource(listInfoResponse.statements)) maybeListNode: Option[ListNodeADM] <- if (listInfoResponse.statements.nonEmpty) { for { // here we know that the list exists and it is fine if children is an empty list - children: Seq[ListChildNodeADM] <- getChildren(nodeIri, shallow, requestingUser) + children: Seq[ListChildNodeADM] <- getChildren( + ofNodeIri = nodeIri, + shallow = shallow, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) // _ = log.debug(s"listGetADM - children count: {}", children.size) @@ -407,12 +467,16 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde * Retrieves the child nodes from the triplestore. If shallow is true, then only the immediate children will be * returned, otherwise all children and their children's children will be returned. * - * @param ofNodeIri the IRI of the node for which children are to be returned. - * @param shallow denotes if all children or only the immediate children will be returned. - * @param requestingUser the user making the request. + * @param ofNodeIri the IRI of the node for which children are to be returned. + * @param shallow denotes if all children or only the immediate children will be returned. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return a sequence of [[ListChildNodeADM]]. */ - private def getChildren(ofNodeIri: IRI, shallow: Boolean, requestingUser: UserADM): Future[Seq[ListChildNodeADM]] = { + private def getChildren(ofNodeIri: IRI, + shallow: Boolean, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[Seq[ListChildNodeADM]] = { /** * This function recursively transforms SPARQL query results representing a hierarchical list into a [[ListChildNodeADM]]. @@ -463,13 +527,16 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde } for { - nodeChildrenQuery <- Future { + nodeChildrenQuery: String <- Future { org.knora.webapi.messages.twirl.queries.sparql.admin.txt.getListNodeWithChildren( triplestore = settings.triplestoreType, startNodeIri = ofNodeIri ).toString() } - nodeWithChildrenResponse <- (storeManager ? SparqlExtendedConstructRequest(nodeChildrenQuery)).mapTo[SparqlExtendedConstructResponse] + nodeWithChildrenResponse <- (storeManager ? SparqlExtendedConstructRequest( + sparql = nodeChildrenQuery, + featureFactoryConfig = featureFactoryConfig + )).mapTo[SparqlExtendedConstructResponse] statements: Seq[(SubjectV2, Map[SmartIri, Seq[LiteralV2]])] = nodeWithChildrenResponse.statements.toList @@ -581,19 +648,24 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde /** * Creates a list. * - * @param createListRequest the new list's information. - * @param requestingUser the user that is making the request. - * @param apiRequestID the unique api request ID. + * @param createListRequest the new list's information. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user that is making the request. + * @param apiRequestID the unique api request ID. * @return a [[ListInfoGetResponseADM]] * @throws ForbiddenException in the case that the user is not allowed to perform the operation. * @throws BadRequestException in the case when the project IRI or label is missing or invalid. */ - private def listCreateRequestADM(createListRequest: CreateListApiRequestADM, requestingUser: UserADM, apiRequestID: UUID): Future[ListGetResponseADM] = { + private def listCreateRequestADM(createListRequest: CreateListApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): Future[ListGetResponseADM] = { /** * The actual task run with an IRI lock. */ - def listCreateTask(createListRequest: CreateListApiRequestADM, requestingUser: UserADM, apiRequestID: UUID) = for { + def listCreateTask(createListRequest: CreateListApiRequestADM, + requestingUser: UserADM, apiRequestID: UUID) = for { // check if the requesting user is allowed to perform operation _ <- Future( @@ -605,7 +677,12 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde ) /* Verify that the project exists. */ - maybeProject <- (responderManager ? ProjectGetADM(ProjectIdentifierADM(maybeIri = Some(createListRequest.projectIri)), KnoraSystemInstances.Users.SystemUser)).mapTo[Option[ProjectADM]] + maybeProject <- (responderManager ? ProjectGetADM( + identifier = ProjectIdentifierADM(maybeIri = Some(createListRequest.projectIri)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + )).mapTo[Option[ProjectADM]] + project: ProjectADM = maybeProject match { case Some(project: ProjectADM) => project case None => throw BadRequestException(s"Project '${createListRequest.projectIri}' not found.") @@ -639,7 +716,12 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde // Verify that the list was created. - maybeNewListADM <- listGetADM(listIri, KnoraSystemInstances.Users.SystemUser) + maybeNewListADM <- listGetADM( + rootNodeIri = listIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) + newListADM = maybeNewListADM.getOrElse(throw UpdateNotPerformedException(s"List $listIri was not created. Please report this as a possible bug.")) // _ = log.debug(s"listCreateRequestADM - newListADM: $newListADM") @@ -659,21 +741,27 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde /** * Changes basic list information stored in the list's root node. * - * @param listIri the list's IRI. - * @param changeListRequest the new list information. - * @param requestingUser the user that is making the request. - * @param apiRequestID the unique api request ID. + * @param listIri the list's IRI. + * @param changeListRequest the new list information. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user that is making the request. + * @param apiRequestID the unique api request ID. * @return a [[ListInfoGetResponseADM]] * @throws ForbiddenException in the case that the user is not allowed to perform the operation. * @throws BadRequestException in the case when the project IRI is missing or invalid. * @throws UpdateNotPerformedException in the case something else went wrong, and the change could not be performed. */ - private def listInfoChangeRequest(listIri: IRI, changeListRequest: ChangeListInfoApiRequestADM, requestingUser: UserADM, apiRequestID: UUID): Future[ListInfoGetResponseADM] = { + private def listInfoChangeRequest(listIri: IRI, + changeListRequest: ChangeListInfoApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): Future[ListInfoGetResponseADM] = { /** * The actual task run with an IRI lock. */ - def listInfoChangeTask(listIri: IRI, changeListRequest: ChangeListInfoApiRequestADM, requestingUser: UserADM, apiRequestID: UUID): Future[ListInfoGetResponseADM] = for { + def listInfoChangeTask(listIri: IRI, changeListRequest: ChangeListInfoApiRequestADM, + requestingUser: UserADM, apiRequestID: UUID): Future[ListInfoGetResponseADM] = for { // check if listIRI in path and payload match _ <- Future( if (!listIri.equals(changeListRequest.listIri)) throw BadRequestException("List IRI in path and payload don't match.") @@ -681,20 +769,30 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde // check if the requesting user is allowed to perform operation _ = if (!requestingUser.permissions.isProjectAdmin(changeListRequest.projectIri) && !requestingUser.permissions.isSystemAdmin) { - // not project or a system admin - // log.debug("same user: {}, system admin: {}", userProfile.userData.user_id.contains(userIri), userProfile.permissionData.isSystemAdmin) - throw ForbiddenException(LIST_CHANGE_PERMISSION_ERROR) - } + // not project or a system admin + // log.debug("same user: {}, system admin: {}", userProfile.userData.user_id.contains(userIri), userProfile.permissionData.isSystemAdmin) + throw ForbiddenException(LIST_CHANGE_PERMISSION_ERROR) + } /* Verify that the list exists. */ - maybeList <- listGetADM(rootNodeIri = listIri, requestingUser = KnoraSystemInstances.Users.SystemUser) + maybeList <- listGetADM( + rootNodeIri = listIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) + list: ListADM = maybeList match { case Some(list: ListADM) => list case None => throw BadRequestException(s"List '$listIri' not found.") } /* Get the project information */ - maybeProject <- (responderManager ? ProjectGetADM(ProjectIdentifierADM(maybeIri = Some(list.listinfo.projectIri)), KnoraSystemInstances.Users.SystemUser)).mapTo[Option[ProjectADM]] + maybeProject <- (responderManager ? ProjectGetADM( + identifier = ProjectIdentifierADM(maybeIri = Some(list.listinfo.projectIri)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + )).mapTo[Option[ProjectADM]] + project: ProjectADM = maybeProject match { case Some(project: ProjectADM) => project case None => throw BadRequestException(s"Project '${list.listinfo.projectIri}' not found.") @@ -728,7 +826,12 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde /* Verify that the list was updated */ - maybeListADM <- listGetADM(listIri, KnoraSystemInstances.Users.SystemUser) + maybeListADM <- listGetADM( + rootNodeIri = listIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) + updatedList = maybeListADM.getOrElse(throw UpdateNotPerformedException(s"List $listIri was not updated. Please report this as a possible bug.")) @@ -766,11 +869,16 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde * * @param parentNodeIri the existing list node to which we want to append. * @param createChildNodeRequest the new list node's information. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the user making the request. * @param apiRequestID the unique api request ID. * @return a [[ListNodeInfoGetResponseADM]] */ - private def listChildNodeCreateRequestADM(parentNodeIri: IRI, createChildNodeRequest: CreateChildNodeApiRequestADM, requestingUser: UserADM, apiRequestID: UUID): Future[ListNodeInfoGetResponseADM] = { + private def listChildNodeCreateRequestADM(parentNodeIri: IRI, + createChildNodeRequest: CreateChildNodeApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): Future[ListNodeInfoGetResponseADM] = { /** * The actual task run with an IRI lock. @@ -789,7 +897,13 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde _ = if (!parentNodeIri.equals(createChildNodeRequest.parentNodeIri)) throw BadRequestException("List node IRI in path and payload don't match.") /* Verify that the list node exists by retrieving the whole node including children one level deep (need for position calculation) */ - maybeParentListNode <- listNodeGetADM(parentNodeIri, shallow = true, requestingUser = KnoraSystemInstances.Users.SystemUser) + maybeParentListNode <- listNodeGetADM( + nodeIri = parentNodeIri, + shallow = true, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) + (parentListNode, children) = maybeParentListNode match { case Some(node: ListRootNodeADM) => (node.asInstanceOf[ListRootNodeADM], node.children) case Some(node: ListChildNodeADM) => (node.asInstanceOf[ListChildNodeADM], node.children) @@ -810,7 +924,12 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde } /* Verify that the project exists by retrieving it. We need the project information so that we can calculate the data graph and IRI for the new node. */ - maybeProject <- (responderManager ? ProjectGetADM(ProjectIdentifierADM(maybeIri = Some(createChildNodeRequest.projectIri)), KnoraSystemInstances.Users.SystemUser)).mapTo[Option[ProjectADM]] + maybeProject <- (responderManager ? ProjectGetADM( + identifier = ProjectIdentifierADM(maybeIri = Some(createChildNodeRequest.projectIri)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + )).mapTo[Option[ProjectADM]] + project: ProjectADM = maybeProject match { case Some(project: ProjectADM) => project case None => throw BadRequestException(s"Project '${createChildNodeRequest.projectIri}' not found.") @@ -848,7 +967,12 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde // Verify that the list node was created. - maybeNewListNode <- listNodeInfoGetADM(newListNodeIri, KnoraSystemInstances.Users.SystemUser) + maybeNewListNode <- listNodeInfoGetADM( + nodeIri = newListNodeIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) + newListNode = maybeNewListNode.getOrElse(throw UpdateNotPerformedException(s"List node $newListNodeIri was not created. Please report this as a possible bug.")) // _ = log.debug(s"listCreateRequestADM - newListADM: $newListADM") diff --git a/webapi/src/main/scala/org/knora/webapi/responders/admin/PermissionsResponderADM.scala b/webapi/src/main/scala/org/knora/webapi/responders/admin/PermissionsResponderADM.scala index 822dba3cd8..bb802a1bdc 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/admin/PermissionsResponderADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/admin/PermissionsResponderADM.scala @@ -25,6 +25,7 @@ import akka.http.scaladsl.util.FastFuture import akka.pattern._ import org.knora.webapi._ import org.knora.webapi.exceptions._ +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.{OntologyConstants, SmartIri} import org.knora.webapi.messages.admin.responder.groupsmessages.{GroupADM, GroupGetADM} import org.knora.webapi.messages.admin.responder.projectsmessages.{ProjectADM, ProjectGetADM, ProjectIdentifierADM} @@ -57,12 +58,12 @@ class PermissionsResponderADM(responderData: ResponderData) extends Responder(re * Receives a message extending [[PermissionsResponderRequestADM]], and returns an appropriate response message. */ def receive(msg: PermissionsResponderRequestADM) = msg match { - case PermissionDataGetADM(projectIris, groupIris, isInProjectAdminGroup, isInSystemAdminGroup, requestingUser) => permissionsDataGetADM(projectIris, groupIris, isInProjectAdminGroup, isInSystemAdminGroup, requestingUser) + case PermissionDataGetADM(projectIris, groupIris, isInProjectAdminGroup, isInSystemAdminGroup, featureFactoryConfig, requestingUser) => permissionsDataGetADM(projectIris, groupIris, isInProjectAdminGroup, isInSystemAdminGroup, featureFactoryConfig, requestingUser) case AdministrativePermissionsForProjectGetRequestADM(projectIri, requestingUser, apiRequestID) => administrativePermissionsForProjectGetRequestADM(projectIri, requestingUser, apiRequestID) case AdministrativePermissionForIriGetRequestADM(administrativePermissionIri, requestingUser, apiRequestID) => administrativePermissionForIriGetRequestADM(administrativePermissionIri, requestingUser, apiRequestID) case AdministrativePermissionForProjectGroupGetADM(projectIri, groupIri, requestingUser) => administrativePermissionForProjectGroupGetADM(projectIri, groupIri, requestingUser) case AdministrativePermissionForProjectGroupGetRequestADM(projectIri, groupIri, requestingUser) => administrativePermissionForProjectGroupGetRequestADM(projectIri, groupIri, requestingUser) - case AdministrativePermissionCreateRequestADM(newAdministrativePermission, requestingUser, apiRequestID) => administrativePermissionCreateRequestADM(newAdministrativePermission, requestingUser, apiRequestID) + case AdministrativePermissionCreateRequestADM(newAdministrativePermission, featureFactoryConfig, requestingUser, apiRequestID) => administrativePermissionCreateRequestADM(newAdministrativePermission, featureFactoryConfig, requestingUser, apiRequestID) case ObjectAccessPermissionsForResourceGetADM(resourceIri, requestingUser) => objectAccessPermissionsForResourceGetADM(resourceIri, requestingUser) case ObjectAccessPermissionsForValueGetADM(valueIri, requestingUser) => objectAccessPermissionsForValueGetADM(valueIri, requestingUser) case DefaultObjectAccessPermissionsForProjectGetRequestADM(projectIri, requestingUser, apiRequestID) => defaultObjectAccessPermissionsForProjectGetRequestADM(projectIri, requestingUser, apiRequestID) @@ -70,8 +71,8 @@ class PermissionsResponderADM(responderData: ResponderData) extends Responder(re case DefaultObjectAccessPermissionGetRequestADM(projectIri, groupIri, resourceClassIri, propertyIri, requestingUser) => defaultObjectAccessPermissionGetRequestADM(projectIri, groupIri, resourceClassIri, propertyIri, requestingUser) case DefaultObjectAccessPermissionsStringForResourceClassGetADM(projectIri, resourceClassIri, targetUser, requestingUser) => defaultObjectAccessPermissionsStringForEntityGetADM(projectIri, resourceClassIri, None, ResourceEntityType, targetUser, requestingUser) case DefaultObjectAccessPermissionsStringForPropertyGetADM(projectIri, resourceClassIri, propertyTypeIri, targetUser, requestingUser) => defaultObjectAccessPermissionsStringForEntityGetADM(projectIri, resourceClassIri, Some(propertyTypeIri), PropertyEntityType, targetUser, requestingUser) - case DefaultObjectAccessPermissionCreateRequestADM(createRequest, requestingUser, apiRequestID) => defaultObjectAccessPermissionCreateRequestADM(createRequest, requestingUser, apiRequestID) - case PermissionsForProjectGetRequestADM(projectIri, groupIri, requestingUser) => permissionsForProjectGetRequestADM(projectIri, groupIri, requestingUser) + case DefaultObjectAccessPermissionCreateRequestADM(createRequest, featureFactoryConfig, requestingUser, apiRequestID) => defaultObjectAccessPermissionCreateRequestADM(createRequest, featureFactoryConfig, requestingUser, apiRequestID) + case PermissionsForProjectGetRequestADM(projectIri, groupIri, featureFactoryConfig, requestingUser) => permissionsForProjectGetRequestADM(projectIri, groupIri, featureFactoryConfig, requestingUser) case other => handleUnexpectedMessage(other, log, this.getClass.getName) } @@ -87,12 +88,14 @@ class PermissionsResponderADM(responderData: ResponderData) extends Responder(re * @param groupIris the groups the user is member of (without ProjectMember, ProjectAdmin, SystemAdmin) * @param isInProjectAdminGroups the projects in which the user is member of the ProjectAdmin group. * @param isInSystemAdminGroup the flag denoting membership in the SystemAdmin group. + * @param featureFactoryConfig the feature factory configuration. * @return */ private def permissionsDataGetADM(projectIris: Seq[IRI], groupIris: Seq[IRI], isInProjectAdminGroups: Seq[IRI], isInSystemAdminGroup: Boolean, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM): Future[PermissionsDataADM] = { // find out which project each group belongs to //_ = log.debug("getPermissionsProfileV1 - find out to which project each group belongs to") @@ -101,7 +104,12 @@ class PermissionsResponderADM(responderData: ResponderData) extends Responder(re groupIris.map { groupIri => for { - maybeGroup <- (responderManager ? GroupGetADM(groupIri, KnoraSystemInstances.Users.SystemUser)).mapTo[Option[GroupADM]] + maybeGroup <- (responderManager ? GroupGetADM( + groupIri = groupIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + )).mapTo[Option[GroupADM]] + group = maybeGroup.getOrElse(throw InconsistentTriplestoreDataException(s"Cannot find information for group: '$groupIri'. Please report as possible bug.")) res = (group.project.id, groupIri) } yield res @@ -194,7 +202,7 @@ class PermissionsResponderADM(responderData: ResponderData) extends Responder(re for { /* Get administrative permissions for the knora-base:ProjectAdmin group */ - administrativePermissionsOnProjectAdminGroup: Set[PermissionADM] <- administrativePermissionForGroupsGeADM(projectIri, List(OntologyConstants.KnoraAdmin.ProjectAdmin)) + administrativePermissionsOnProjectAdminGroup: Set[PermissionADM] <- administrativePermissionForGroupsGetADM(projectIri, List(OntologyConstants.KnoraAdmin.ProjectAdmin)) _ = if (administrativePermissionsOnProjectAdminGroup.nonEmpty) { if (extendedUserGroups.contains(OntologyConstants.KnoraAdmin.ProjectAdmin)) { permissionsListBuffer += (("ProjectAdmin", administrativePermissionsOnProjectAdminGroup)) @@ -207,7 +215,7 @@ class PermissionsResponderADM(responderData: ResponderData) extends Responder(re administrativePermissionsOnCustomGroups: Set[PermissionADM] <- { val customGroups = extendedUserGroups diff List(OntologyConstants.KnoraAdmin.KnownUser, OntologyConstants.KnoraAdmin.ProjectMember, OntologyConstants.KnoraAdmin.ProjectAdmin) if (customGroups.nonEmpty) { - administrativePermissionForGroupsGeADM(projectIri, customGroups) + administrativePermissionForGroupsGetADM(projectIri, customGroups) } else { Future(Set.empty[PermissionADM]) } @@ -221,7 +229,7 @@ class PermissionsResponderADM(responderData: ResponderData) extends Responder(re /* Get administrative permissions for the knora-base:ProjectMember group */ - administrativePermissionsOnProjectMemberGroup: Set[PermissionADM] <- administrativePermissionForGroupsGeADM(projectIri, List(OntologyConstants.KnoraAdmin.ProjectMember)) + administrativePermissionsOnProjectMemberGroup: Set[PermissionADM] <- administrativePermissionForGroupsGetADM(projectIri, List(OntologyConstants.KnoraAdmin.ProjectMember)) _ = if (administrativePermissionsOnProjectMemberGroup.nonEmpty) { if (permissionsListBuffer.isEmpty) { if (extendedUserGroups.contains(OntologyConstants.KnoraAdmin.ProjectMember)) { @@ -233,7 +241,7 @@ class PermissionsResponderADM(responderData: ResponderData) extends Responder(re /* Get administrative permissions for the knora-base:KnownUser group */ - administrativePermissionsOnKnownUserGroup: Set[PermissionADM] <- administrativePermissionForGroupsGeADM(projectIri, List(OntologyConstants.KnoraAdmin.KnownUser)) + administrativePermissionsOnKnownUserGroup: Set[PermissionADM] <- administrativePermissionForGroupsGetADM(projectIri, List(OntologyConstants.KnoraAdmin.KnownUser)) _ = if (administrativePermissionsOnKnownUserGroup.nonEmpty) { if (permissionsListBuffer.isEmpty) { if (extendedUserGroups.contains(OntologyConstants.KnoraAdmin.KnownUser)) { @@ -284,9 +292,8 @@ class PermissionsResponderADM(responderData: ResponderData) extends Responder(re * @param groups the list of groups for which administrative permissions are retrieved and combined. * @return a set of [[PermissionADM]]. */ - private def administrativePermissionForGroupsGeADM(projectIri: IRI, - groups: Seq[IRI] - ): Future[Set[PermissionADM]] = { + private def administrativePermissionForGroupsGetADM(projectIri: IRI, + groups: Seq[IRI]): Future[Set[PermissionADM]] = { /* Get administrative permissions for each group and combine them */ val gpf: Seq[Future[Seq[PermissionADM]]] = for { @@ -326,7 +333,7 @@ class PermissionsResponderADM(responderData: ResponderData) extends Responder(re * * @param projectIRI the IRI of the project. * @param requestingUser the [[UserADM]] of the requesting user. - * @param apiRequestID the API request ID. + * @param apiRequestID the API request ID. * @return a list of IRIs of [[AdministrativePermissionADM]] objects. */ private def administrativePermissionsForProjectGetRequestADM(projectIRI: IRI, @@ -418,9 +425,9 @@ class PermissionsResponderADM(responderData: ResponderData) extends Responder(re /** * Gets a single administrative permission identified by project and group. * - * @param projectIri the project. - * @param groupIri the group. - * @param requestingUser the requesting user. + * @param projectIri the project. + * @param groupIri the group. + * @param requestingUser the requesting user. * @return an option containing an [[AdministrativePermissionADM]] */ private def administrativePermissionForProjectGroupGetADM(projectIri: IRI, @@ -466,9 +473,9 @@ class PermissionsResponderADM(responderData: ResponderData) extends Responder(re /** * Gets a single administrative permission identified by project and group. * - * @param projectIri the project. - * @param groupIri the group. - * @param requestingUser the requesting user. + * @param projectIri the project. + * @param groupIri the group. + * @param requestingUser the requesting user. * @return an [[AdministrativePermissionForProjectGroupGetResponseADM]] */ private def administrativePermissionForProjectGroupGetRequestADM(projectIri: IRI, @@ -488,15 +495,16 @@ class PermissionsResponderADM(responderData: ResponderData) extends Responder(re /** * Adds a new administrative permission (internal use). * - * @param createRequest the administrative permission to add. - * @param requestingUser the requesting user. - * @param apiRequestID the API request ID. + * @param createRequest the administrative permission to add. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the requesting user. + * @param apiRequestID the API request ID. * @return an optional [[AdministrativePermissionADM]] */ private def administrativePermissionCreateRequestADM(createRequest: CreateAdministrativePermissionAPIRequestADM, - requestingUser: UserADM, - apiRequestID: UUID - ): Future[AdministrativePermissionCreateResponseADM] = { + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): Future[AdministrativePermissionCreateResponseADM] = { log.debug("administrativePermissionCreateRequestADM") /** @@ -520,16 +528,18 @@ class PermissionsResponderADM(responderData: ResponderData) extends Responder(re // get project maybeProject: Option[ProjectADM] <- (responderManager ? ProjectGetADM( identifier = ProjectIdentifierADM(maybeIri = Some(createRequest.forProject)), - requestingUser = KnoraSystemInstances.Users.SystemUser) - ).mapTo[Option[ProjectADM]] + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + )).mapTo[Option[ProjectADM]] // if it doesnt exist then throw an error project: ProjectADM = maybeProject.getOrElse(throw NotFoundException(s"Project '${createRequest.forProject}' not found. Aborting request.")) // get group maybeGroup <- (responderManager ? GroupGetADM( - createRequest.forGroup, - KnoraSystemInstances.Users.SystemUser + groupIri = createRequest.forGroup, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser )).mapTo[Option[GroupADM]] // if it does not exist then throw an error @@ -554,7 +564,7 @@ class PermissionsResponderADM(responderData: ResponderData) extends Responder(re _ <- (storeManager ? SparqlUpdateRequest(createAdministrativePermissionSparqlString)).mapTo[SparqlUpdateResponse] // try to retrieve the newly created permission - maybePermission <- administrativePermissionForIriGetRequestADM( administrativePermissionIri = newPermissionIri, + maybePermission <- administrativePermissionForIriGetRequestADM(administrativePermissionIri = newPermissionIri, requestingUser = KnoraSystemInstances.Users.SystemUser, apiRequestID = apiRequestID) newAdminPermission: AdministrativePermissionADM = maybePermission.administrativePermission @@ -578,8 +588,8 @@ class PermissionsResponderADM(responderData: ResponderData) extends Responder(re /** * Gets all permissions attached to the resource. * - * @param resourceIri the IRI of the resource. - * @param requestingUser the requesting user. + * @param resourceIri the IRI of the resource. + * @param requestingUser the requesting user. * @return a sequence of [[PermissionADM]] */ private def objectAccessPermissionsForResourceGetADM(resourceIri: IRI, @@ -618,8 +628,8 @@ class PermissionsResponderADM(responderData: ResponderData) extends Responder(re /** * Gets all permissions attached to the value. * - * @param valueIri the IRI of the value. - * @param requestingUser the requesting user. + * @param valueIri the IRI of the value. + * @param requestingUser the requesting user. * @return a sequence of [[PermissionADM]] */ private def objectAccessPermissionsForValueGetADM(valueIri: IRI, @@ -663,9 +673,9 @@ class PermissionsResponderADM(responderData: ResponderData) extends Responder(re /** * Gets all IRI's of all default object access permissions defined inside a project. * - * @param projectIri the IRI of the project. - * @param requestingUser the [[UserADM]] of the requesting user. - * @param apiRequestID the API request ID. + * @param projectIri the IRI of the project. + * @param requestingUser the [[UserADM]] of the requesting user. + * @param apiRequestID the API request ID. * @return a list of IRIs of [[DefaultObjectAccessPermissionADM]] objects. */ private def defaultObjectAccessPermissionsForProjectGetRequestADM(projectIri: IRI, @@ -710,9 +720,9 @@ class PermissionsResponderADM(responderData: ResponderData) extends Responder(re /** * Gets a single default object access permission identified by its IRI. * - * @param permissionIri the IRI of the default object access permission. - * @param requestingUser the [[UserADM]] of the requesting user. - * @param apiRequestID the API request ID. + * @param permissionIri the IRI of the default object access permission. + * @param requestingUser the [[UserADM]] of the requesting user. + * @param apiRequestID the API request ID. * @return a single [[DefaultObjectAccessPermissionADM]] object. */ private def defaultObjectAccessPermissionForIriGetRequestADM(permissionIri: IRI, @@ -1196,86 +1206,92 @@ class PermissionsResponderADM(responderData: ResponderData) extends Responder(re } yield permissionsmessages.DefaultObjectAccessPermissionsStringResponseADM(result) } - private def defaultObjectAccessPermissionCreateRequestADM(createRequest: CreateDefaultObjectAccessPermissionAPIRequestADM, requestingUser: UserADM, apiRequestID: UUID): Future[DefaultObjectAccessPermissionCreateResponseADM] = { + private def defaultObjectAccessPermissionCreateRequestADM(createRequest: CreateDefaultObjectAccessPermissionAPIRequestADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, apiRequestID: UUID): Future[DefaultObjectAccessPermissionCreateResponseADM] = { - /** - * The actual change project task run with an IRI lock. - */ - def createPermissionTask(createRequest: CreateDefaultObjectAccessPermissionAPIRequestADM, - requestingUser: UserADM): Future[DefaultObjectAccessPermissionCreateResponseADM] = - for { - checkResult <- defaultObjectAccessPermissionGetADM( - createRequest.forProject, - createRequest.forGroup, - createRequest.forResourceClass, - createRequest.forProperty) - - _ = checkResult match { - case Some(doap) => throw DuplicateValueException(s"Default object access permission already exists.") - case None => () - } + /** + * The actual change project task run with an IRI lock. + */ + def createPermissionTask(createRequest: CreateDefaultObjectAccessPermissionAPIRequestADM, + requestingUser: UserADM): Future[DefaultObjectAccessPermissionCreateResponseADM] = + for { + checkResult <- defaultObjectAccessPermissionGetADM( + createRequest.forProject, + createRequest.forGroup, + createRequest.forResourceClass, + createRequest.forProperty) - // get project - maybeProject: Option[ProjectADM] <- (responderManager ? ProjectGetADM( - identifier = ProjectIdentifierADM(maybeIri = Some(createRequest.forProject)), - requestingUser = KnoraSystemInstances.Users.SystemUser) - ).mapTo[Option[ProjectADM]] + _ = checkResult match { + case Some(doap) => throw DuplicateValueException(s"Default object access permission already exists.") + case None => () + } - // if it doesnt exist then throw an error - project: ProjectADM = maybeProject.getOrElse(throw NotFoundException(s"Project '${createRequest.forProject}' not found. Aborting request.")) + // get project + maybeProject: Option[ProjectADM] <- (responderManager ? ProjectGetADM( + identifier = ProjectIdentifierADM(maybeIri = Some(createRequest.forProject)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + )).mapTo[Option[ProjectADM]] - customPermissionIri: Option[SmartIri] = createRequest.id.map(iri => iri.toSmartIri) - newPermissionIri: IRI <- checkOrCreateEntityIri(customPermissionIri, stringFormatter.makeRandomPermissionIri(project.shortcode)) + // if it doesnt exist then throw an error + project: ProjectADM = maybeProject.getOrElse(throw NotFoundException(s"Project '${createRequest.forProject}' not found. Aborting request.")) - // Create the default object access permission. - createNewDefaultObjectAccessPermissionSparqlString = org.knora.webapi.messages.twirl.queries.sparql.admin.txt.createNewDefaultObjectAccessPermission( - adminNamedGraphIri = OntologyConstants.NamedGraphs.AdminNamedGraph, - triplestore = settings.triplestoreType, - permissionIri = newPermissionIri, - permissionClassIri = OntologyConstants.KnoraAdmin.DefaultObjectAccessPermission, - projectIri = project.id, - maybeGroupIri = createRequest.forGroup, - maybeResourceClassIri = createRequest.forResourceClass, - maybePropertyIri = createRequest.forProperty, - permissions = PermissionUtilADM.formatPermissionADMs(createRequest.hasPermissions, PermissionType.OAP) - ).toString - - _ <- (storeManager ? SparqlUpdateRequest(createNewDefaultObjectAccessPermissionSparqlString)).mapTo[SparqlUpdateResponse] - - // try to retrieve the newly created permission - maybePermission <- defaultObjectAccessPermissionGetADM( - createRequest.forProject, - createRequest.forGroup, - createRequest.forResourceClass, - createRequest.forProperty) - - newDefaultObjectAcessPermission: DefaultObjectAccessPermissionADM = maybePermission.getOrElse(throw - BadRequestException("Requested default object access permission could not be created, report this as a possible bug.")) - - } yield DefaultObjectAccessPermissionCreateResponseADM( - defaultObjectAccessPermission = newDefaultObjectAcessPermission) - for { - // run the task with an IRI lock - taskResult <- IriLocker.runWithIriLock( - apiRequestID, - PERMISSIONS_GLOBAL_LOCK_IRI, - () => createPermissionTask(createRequest, requestingUser) - ) - } yield taskResult + customPermissionIri: Option[SmartIri] = createRequest.id.map(iri => iri.toSmartIri) + newPermissionIri: IRI <- checkOrCreateEntityIri(customPermissionIri, stringFormatter.makeRandomPermissionIri(project.shortcode)) + + // Create the default object access permission. + createNewDefaultObjectAccessPermissionSparqlString = org.knora.webapi.messages.twirl.queries.sparql.admin.txt.createNewDefaultObjectAccessPermission( + adminNamedGraphIri = OntologyConstants.NamedGraphs.AdminNamedGraph, + triplestore = settings.triplestoreType, + permissionIri = newPermissionIri, + permissionClassIri = OntologyConstants.KnoraAdmin.DefaultObjectAccessPermission, + projectIri = project.id, + maybeGroupIri = createRequest.forGroup, + maybeResourceClassIri = createRequest.forResourceClass, + maybePropertyIri = createRequest.forProperty, + permissions = PermissionUtilADM.formatPermissionADMs(createRequest.hasPermissions, PermissionType.OAP) + ).toString + + _ <- (storeManager ? SparqlUpdateRequest(createNewDefaultObjectAccessPermissionSparqlString)).mapTo[SparqlUpdateResponse] + + // try to retrieve the newly created permission + maybePermission <- defaultObjectAccessPermissionGetADM( + createRequest.forProject, + createRequest.forGroup, + createRequest.forResourceClass, + createRequest.forProperty) + + newDefaultObjectAcessPermission: DefaultObjectAccessPermissionADM = maybePermission.getOrElse(throw + BadRequestException("Requested default object access permission could not be created, report this as a possible bug.")) + + } yield DefaultObjectAccessPermissionCreateResponseADM( + defaultObjectAccessPermission = newDefaultObjectAcessPermission) + + for { + // run the task with an IRI lock + taskResult <- IriLocker.runWithIriLock( + apiRequestID, + PERMISSIONS_GLOBAL_LOCK_IRI, + () => createPermissionTask(createRequest, requestingUser) + ) + } yield taskResult } /** * Gets all permissions defined inside a project. * - * @param projectIRI the IRI of the project. - * @param requestingUser the [[UserADM]] of the requesting user. - * @param apiRequestID the API request ID. + * @param projectIRI the IRI of the project. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the [[UserADM]] of the requesting user. + * @param apiRequestID the API request ID. * @return a list of of [[PermissionInfoADM]] objects. */ private def permissionsForProjectGetRequestADM(projectIRI: IRI, - requestingUser: UserADM, - apiRequestID: UUID - ): Future[PermissionsForProjectGetResponseADM] = { + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID + ): Future[PermissionsForProjectGetResponseADM] = { for { sparqlQueryString <- Future(org.knora.webapi.messages.twirl.queries.sparql.admin.txt.getProjectPermissions( @@ -1283,7 +1299,10 @@ class PermissionsResponderADM(responderData: ResponderData) extends Responder(re projectIri = projectIRI ).toString()) - permissionsQueryResponse <- (storeManager ? SparqlConstructRequest(sparqlQueryString)).mapTo[SparqlConstructResponse] + permissionsQueryResponse <- (storeManager ? SparqlConstructRequest( + sparql = sparqlQueryString, + featureFactoryConfig = featureFactoryConfig + )).mapTo[SparqlConstructResponse] /* extract response statements */ permissionsQueryResponseStatements: Map[IRI, Seq[(IRI, String)]] = permissionsQueryResponse.statements @@ -1292,10 +1311,10 @@ class PermissionsResponderADM(responderData: ResponderData) extends Responder(re permissionsInfo: Set[PermissionInfoADM] = if (permissionsQueryResponseStatements.isEmpty) { throw NotFoundException(s"No permission could be found for $projectIRI.") } else { - permissionsQueryResponseStatements.map{ statement => - val permissionIri = statement._1 - val (_, permissionType) = statement._2.filter(_._1 == OntologyConstants.Rdf.Type).head - PermissionInfoADM(iri = permissionIri, permissionType = permissionType) + permissionsQueryResponseStatements.map { statement => + val permissionIri = statement._1 + val (_, permissionType) = statement._2.filter(_._1 == OntologyConstants.Rdf.Type).head + PermissionInfoADM(iri = permissionIri, permissionType = permissionType) }.toSet } diff --git a/webapi/src/main/scala/org/knora/webapi/responders/admin/ProjectsResponderADM.scala b/webapi/src/main/scala/org/knora/webapi/responders/admin/ProjectsResponderADM.scala index 4af02e67cf..6685b629ca 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/admin/ProjectsResponderADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/admin/ProjectsResponderADM.scala @@ -30,6 +30,7 @@ import org.eclipse.rdf4j.rio.{RDFFormat, RDFHandler, RDFWriter, Rio} import org.knora.webapi._ import org.knora.webapi.annotation.ApiMayChange import org.knora.webapi.exceptions._ +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.instrumentation.InstrumentationSupport import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.admin.responder.projectsmessages._ @@ -61,29 +62,31 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo * Receives a message extending [[ProjectsResponderRequestV1]], and returns an appropriate response message. */ def receive(msg: ProjectsResponderRequestADM) = msg match { - case ProjectsGetADM(requestingUser) => projectsGetADM(requestingUser) - case ProjectsGetRequestADM(requestingUser) => projectsGetRequestADM(requestingUser) - case ProjectGetADM(identifier, requestingUser) => getSingleProjectADM(identifier, requestingUser) - case ProjectGetRequestADM(identifier, requestingUser) => getSingleProjectADMRequest(identifier, requestingUser) - case ProjectMembersGetRequestADM(identifier, requestingUser) => projectMembersGetRequestADM(identifier, requestingUser) - case ProjectAdminMembersGetRequestADM(identifier, requestingUser) => projectAdminMembersGetRequestADM(identifier, requestingUser) - case ProjectsKeywordsGetRequestADM(requestingUser) => projectsKeywordsGetRequestADM(requestingUser) - case ProjectKeywordsGetRequestADM(projectIri, requestingUser) => projectKeywordsGetRequestADM(projectIri, requestingUser) - case ProjectRestrictedViewSettingsGetADM(identifier, requestingUser) => projectRestrictedViewSettingsGetADM(identifier, requestingUser) - case ProjectRestrictedViewSettingsGetRequestADM(identifier, requestingUser) => projectRestrictedViewSettingsGetRequestADM(identifier, requestingUser) - case ProjectCreateRequestADM(createRequest, requestingUser, apiRequestID) => projectCreateRequestADM(createRequest, requestingUser, apiRequestID) - case ProjectChangeRequestADM(projectIri, changeProjectRequest, requestingUser, apiRequestID) => changeBasicInformationRequestADM(projectIri, changeProjectRequest, requestingUser, apiRequestID) - case ProjectDataGetRequestADM(projectIdentifier, requestingUser) => projectDataGetRequestADM(projectIdentifier, requestingUser) + case ProjectsGetADM(featureFactoryConfig, requestingUser) => projectsGetADM(featureFactoryConfig, requestingUser) + case ProjectsGetRequestADM(featureFactoryConfig, requestingUser) => projectsGetRequestADM(featureFactoryConfig, requestingUser) + case ProjectGetADM(identifier, featureFactoryConfig, requestingUser) => getSingleProjectADM(identifier, featureFactoryConfig, requestingUser) + case ProjectGetRequestADM(identifier, featureFactoryConfig, requestingUser) => getSingleProjectADMRequest(identifier, featureFactoryConfig, requestingUser) + case ProjectMembersGetRequestADM(identifier, featureFactoryConfig, requestingUser) => projectMembersGetRequestADM(identifier, featureFactoryConfig, requestingUser) + case ProjectAdminMembersGetRequestADM(identifier, featureFactoryConfig, requestingUser) => projectAdminMembersGetRequestADM(identifier, featureFactoryConfig, requestingUser) + case ProjectsKeywordsGetRequestADM(featureFactoryConfig, requestingUser) => projectsKeywordsGetRequestADM(featureFactoryConfig, requestingUser) + case ProjectKeywordsGetRequestADM(projectIri, featureFactoryConfig, requestingUser) => projectKeywordsGetRequestADM(projectIri, featureFactoryConfig, requestingUser) + case ProjectRestrictedViewSettingsGetADM(identifier, featureFactoryConfig, requestingUser) => projectRestrictedViewSettingsGetADM(identifier, featureFactoryConfig, requestingUser) + case ProjectRestrictedViewSettingsGetRequestADM(identifier, featureFactoryConfig, requestingUser) => projectRestrictedViewSettingsGetRequestADM(identifier, featureFactoryConfig, requestingUser) + case ProjectCreateRequestADM(createRequest, featureFactoryConfig, requestingUser, apiRequestID) => projectCreateRequestADM(createRequest, featureFactoryConfig, requestingUser, apiRequestID) + case ProjectChangeRequestADM(projectIri, changeProjectRequest, featureFactoryConfig, requestingUser, apiRequestID) => changeBasicInformationRequestADM(projectIri, changeProjectRequest, featureFactoryConfig, requestingUser, apiRequestID) + case ProjectDataGetRequestADM(projectIdentifier, featureFactoryConfig, requestingUser) => projectDataGetRequestADM(projectIdentifier, featureFactoryConfig, requestingUser) case other => handleUnexpectedMessage(other, log, this.getClass.getName) } /** * Gets all the projects and returns them as a sequence containing [[ProjectADM]]. * - * @param requestingUser the user making the request. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return all the projects as a sequence containing [[ProjectADM]]. */ - private def projectsGetADM(requestingUser: UserADM): Future[Seq[ProjectADM]] = { + private def projectsGetADM(featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[Seq[ProjectADM]] = { for { sparqlQueryString <- Future(org.knora.webapi.messages.twirl.queries.sparql.admin.txt.getProjects( @@ -94,7 +97,10 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo ).toString()) // _ = log.debug(s"getProjectsResponseV1 - query: $sparqlQueryString") - projectsResponse <- (storeManager ? SparqlExtendedConstructRequest(sparqlQueryString)).mapTo[SparqlExtendedConstructResponse] + projectsResponse <- (storeManager ? SparqlExtendedConstructRequest( + sparql = sparqlQueryString, + featureFactoryConfig = featureFactoryConfig + )).mapTo[SparqlExtendedConstructResponse] // _ = log.debug(s"projectsGetADM - projectsResponse: $projectsResponse") statements: List[(SubjectV2, Map[SmartIri, Seq[LiteralV2]])] = projectsResponse.statements.toList @@ -139,18 +145,23 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo /** * Gets all the projects and returns them as a [[ProjectsResponseV1]]. * - * @param requestingUser the user that is making the request. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user that is making the request. * @return all the projects as a [[ProjectsResponseV1]]. * @throws NotFoundException if no projects are found. */ - private def projectsGetRequestADM(requestingUser: UserADM): Future[ProjectsGetResponseADM] = { + private def projectsGetRequestADM(featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[ProjectsGetResponseADM] = { // log.debug("projectsGetRequestADM") // ToDo: What permissions should be required, if any? for { - projects <- projectsGetADM(requestingUser = requestingUser) + projects <- projectsGetADM( + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) result = if (projects.nonEmpty) { ProjectsGetResponseADM( @@ -167,11 +178,13 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo /** * Gets the project with the given project IRI, shortname, or shortcode and returns the information as a [[ProjectADM]]. * - * @param identifier the IRI, shortname, or shortcode of the project. - * @param requestingUser the user making the request. + * @param identifier the IRI, shortname, or shortcode of the project. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return information about the project as a [[ProjectInfoV1]]. */ private def getSingleProjectADM(identifier: ProjectIdentifierADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, skipCache: Boolean = false ): Future[Option[ProjectADM]] = tracedFuture("admin-get-project") { @@ -186,10 +199,10 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo for { maybeProjectADM <- if (skipCache) { // getting directly from triplestore - getProjectFromTriplestore(identifier) + getProjectFromTriplestore(identifier = identifier, featureFactoryConfig = featureFactoryConfig) } else { // getting from cache or triplestore - getProjectFromCacheOrTriplestore(identifier) + getProjectFromCacheOrTriplestore(identifier = identifier, featureFactoryConfig = featureFactoryConfig) } _ = if (maybeProjectADM.nonEmpty) { @@ -205,17 +218,25 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo * Gets the project with the given project IRI, shortname, or shortcode and returns the information * as a [[ProjectGetResponseADM]]. * - * @param identifier the IRI, shortname, or shortcode of the project. - * @param requestingUser the user making the request. + * @param identifier the IRI, shortname, or shortcode of the project. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return information about the project as a [[ProjectInfoResponseV1]]. * @throws NotFoundException when no project for the given IRI can be found */ - private def getSingleProjectADMRequest(identifier: ProjectIdentifierADM, requestingUser: UserADM): Future[ProjectGetResponseADM] = { + private def getSingleProjectADMRequest(identifier: ProjectIdentifierADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[ProjectGetResponseADM] = { // log.debug("getSingleProjectADMRequest - maybeIri: {}, maybeShortname: {}, maybeShortcode: {}", maybeIri, maybeShortname, maybeShortcode) for { - maybeProject: Option[ProjectADM] <- getSingleProjectADM(identifier, requestingUser) + maybeProject: Option[ProjectADM] <- getSingleProjectADM( + identifier = identifier, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) + project = maybeProject match { case Some(p) => p case None => throw NotFoundException(s"Project '${identifier.value}' not found") @@ -229,18 +250,26 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo * Gets the members of a project with the given IRI, shortname, oder shortcode. Returns an empty list * if none are found. * - * @param identifier the IRI, shortname, or shortcode of the project. - * @param requestingUser the user making the request. + * @param identifier the IRI, shortname, or shortcode of the project. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return the members of a project as a [[ProjectMembersGetResponseADM]] */ - private def projectMembersGetRequestADM(identifier: ProjectIdentifierADM, requestingUser: UserADM): Future[ProjectMembersGetResponseADM] = { + private def projectMembersGetRequestADM(identifier: ProjectIdentifierADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[ProjectMembersGetResponseADM] = { // log.debug("projectMembersGetRequestADM - maybeIri: {}, maybeShortname: {}, maybeShortcode: {}", maybeIri, maybeShortname, maybeShortcode) for { /* Get project and verify permissions. */ - project <- getSingleProjectADM(identifier, KnoraSystemInstances.Users.SystemUser) + project <- getSingleProjectADM( + identifier = identifier, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) + _ = if (project.isEmpty) { throw NotFoundException(s"Project '${identifier.value}' not found.") } else { @@ -257,7 +286,10 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo ).toString()) //_ = log.debug(s"projectMembersGetRequestADM - query: $sparqlQueryString") - projectMembersResponse <- (storeManager ? SparqlExtendedConstructRequest(sparqlQueryString)).mapTo[SparqlExtendedConstructResponse] + projectMembersResponse <- (storeManager ? SparqlExtendedConstructRequest( + sparql = sparqlQueryString, + featureFactoryConfig = featureFactoryConfig + )).mapTo[SparqlExtendedConstructResponse] statements = projectMembersResponse.statements.toList @@ -271,7 +303,12 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo } maybeUserFutures: Seq[Future[Option[UserADM]]] = userIris.map { - userIri => (responderManager ? UserGetADM(identifier = UserIdentifierADM(maybeIri = Some(userIri)), userInformationTypeADM = UserInformationTypeADM.RESTRICTED, requestingUser = KnoraSystemInstances.Users.SystemUser)).mapTo[Option[UserADM]] + userIri => (responderManager ? UserGetADM( + identifier = UserIdentifierADM(maybeIri = Some(userIri)), + userInformationTypeADM = UserInformationTypeADM.RESTRICTED, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + )).mapTo[Option[UserADM]] } maybeUsers: Seq[Option[UserADM]] <- Future.sequence(maybeUserFutures) users: Seq[UserADM] = maybeUsers.flatten @@ -285,17 +322,25 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo * Gets the admin members of a project with the given IRI, shortname, or shortcode. Returns an empty list * if none are found * - * @param identifier the IRI, shortname, or shortcode of the project. - * @param requestingUser the user making the request. + * @param identifier the IRI, shortname, or shortcode of the project. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return the members of a project as a [[ProjectMembersGetResponseADM]] */ - private def projectAdminMembersGetRequestADM(identifier: ProjectIdentifierADM, requestingUser: UserADM): Future[ProjectAdminMembersGetResponseADM] = { + private def projectAdminMembersGetRequestADM(identifier: ProjectIdentifierADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[ProjectAdminMembersGetResponseADM] = { // log.debug("projectAdminMembersGetRequestADM - maybeIri: {}, maybeShortname: {}, maybeShortcode: {}", maybeIri, maybeShortname, maybeShortcode) for { /* Get project and verify permissions. */ - project <- getSingleProjectADM(identifier, KnoraSystemInstances.Users.SystemUser) + project <- getSingleProjectADM( + identifier = identifier, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) + _ = if (project.isEmpty) { throw NotFoundException(s"Project '${identifier.value}' not found.") } else { @@ -312,7 +357,10 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo ).toString()) //_ = log.debug(s"projectAdminMembersByIRIGetRequestV1 - query: $sparqlQueryString") - projectAdminMembersResponse <- (storeManager ? SparqlExtendedConstructRequest(sparqlQueryString)).mapTo[SparqlExtendedConstructResponse] + projectAdminMembersResponse <- (storeManager ? SparqlExtendedConstructRequest( + sparql = sparqlQueryString, + featureFactoryConfig = featureFactoryConfig + )).mapTo[SparqlExtendedConstructResponse] //_ = log.debug(s"projectAdminMembersByIRIGetRequestV1 - result: ${MessageUtil.toSource(projectMembersResponse)}") statements = projectAdminMembersResponse.statements.toList @@ -325,7 +373,12 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo } maybeUserFutures: Seq[Future[Option[UserADM]]] = userIris.map { - userIri => (responderManager ? UserGetADM(identifier = UserIdentifierADM(maybeIri = Some(userIri)), userInformationTypeADM = UserInformationTypeADM.RESTRICTED, requestingUser = KnoraSystemInstances.Users.SystemUser)).mapTo[Option[UserADM]] + userIri => (responderManager ? UserGetADM( + identifier = UserIdentifierADM(maybeIri = Some(userIri)), + userInformationTypeADM = UserInformationTypeADM.RESTRICTED, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + )).mapTo[Option[UserADM]] } maybeUsers: Seq[Option[UserADM]] <- Future.sequence(maybeUserFutures) users: Seq[UserADM] = maybeUsers.flatten @@ -338,13 +391,18 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo /** * Gets all unique keywords for all projects and returns them. Returns an empty list if none are found. * - * @param requestingUser the user making the request. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return all keywords for all projects as [[ProjectsKeywordsGetResponseADM]] */ - private def projectsKeywordsGetRequestADM(requestingUser: UserADM): Future[ProjectsKeywordsGetResponseADM] = { + private def projectsKeywordsGetRequestADM(featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[ProjectsKeywordsGetResponseADM] = { for { - projects <- projectsGetADM(KnoraSystemInstances.Users.SystemUser) + projects <- projectsGetADM( + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) keywords: Seq[String] = projects.flatMap(_.keywords).distinct.sorted @@ -354,14 +412,21 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo /** * Gets all keywords for a single project and returns them. Returns an empty list if none are found. * - * @param projectIri the IRI of the project. - * @param requestingUser the user making the request. + * @param projectIri the IRI of the project. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return keywords for a projects as [[ProjectKeywordsGetResponseADM]] */ - private def projectKeywordsGetRequestADM(projectIri: IRI, requestingUser: UserADM): Future[ProjectKeywordsGetResponseADM] = { + private def projectKeywordsGetRequestADM(projectIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[ProjectKeywordsGetResponseADM] = { for { - maybeProject <- getSingleProjectADM(ProjectIdentifierADM(maybeIri = Some(projectIri)), requestingUser = KnoraSystemInstances.Users.SystemUser) + maybeProject <- getSingleProjectADM( + identifier = ProjectIdentifierADM(maybeIri = Some(projectIri)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) keywords: Seq[String] = maybeProject match { case Some(p) => p.keywords @@ -371,7 +436,9 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo } yield ProjectKeywordsGetResponseADM(keywords = keywords) } - private def projectDataGetRequestADM(projectIdentifier: ProjectIdentifierADM, requestingUser: UserADM): Future[ProjectDataGetResponseADM] = { + private def projectDataGetRequestADM(projectIdentifier: ProjectIdentifierADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[ProjectDataGetResponseADM] = { /** * Represents a named graph to be saved to a TriG file. * @@ -425,6 +492,8 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo * @param resultFile the output file. */ def combineGraphs(namedGraphTrigFiles: Seq[NamedGraphTrigFile], resultFile: File): Unit = { + // TODO: Provide a streaming API in RdfFormatUtil for this. + var maybeBufferedFileWriter: Option[BufferedWriter] = None try { @@ -457,6 +526,7 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo // Get the project info. maybeProject: Option[ProjectADM] <- getSingleProjectADM( identifier = projectIdentifier, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) @@ -533,12 +603,15 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo /** * Get project's restricted view settings. * - * @param identifier the project's identifier (IRI / shortcode / shortname) - * @param requestingUser the user making the request. + * @param identifier the project's identifier (IRI / shortcode / shortname) + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return [[ProjectRestrictedViewSettingsADM]] */ @ApiMayChange - private def projectRestrictedViewSettingsGetADM(identifier: ProjectIdentifierADM, requestingUser: UserADM): Future[Option[ProjectRestrictedViewSettingsADM]] = { + private def projectRestrictedViewSettingsGetADM(identifier: ProjectIdentifierADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[Option[ProjectRestrictedViewSettingsADM]] = { // ToDo: We have two possible NotFound scenarios: 1. Project, 2. ProjectRestrictedViewSettings resource. How to send the client the correct NotFound reply? @@ -550,7 +623,10 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo maybeShortcode = identifier.toShortcodeOption ).toString()) - projectResponse <- (storeManager ? SparqlExtendedConstructRequest(sparqlQuery)).mapTo[SparqlExtendedConstructResponse] + projectResponse <- (storeManager ? SparqlExtendedConstructRequest( + sparql = sparqlQuery, + featureFactoryConfig = featureFactoryConfig + )).mapTo[SparqlExtendedConstructResponse] restrictedViewSettings = if (projectResponse.statements.nonEmpty) { @@ -572,18 +648,25 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo * Get project's restricted view settings. * * @param identifier the project's identifier (IRI / shortcode / shortname) + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the user making the request. * @return [[ProjectRestrictedViewSettingsGetResponseADM]] */ @ApiMayChange - private def projectRestrictedViewSettingsGetRequestADM(identifier: ProjectIdentifierADM, requestingUser: UserADM): Future[ProjectRestrictedViewSettingsGetResponseADM] = { + private def projectRestrictedViewSettingsGetRequestADM(identifier: ProjectIdentifierADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[ProjectRestrictedViewSettingsGetResponseADM] = { val maybeIri = identifier.toIriOption val maybeShortname = identifier.toShortnameOption val maybeShortcode = identifier.toShortcodeOption for { - maybeSettings: Option[ProjectRestrictedViewSettingsADM] <- projectRestrictedViewSettingsGetADM(identifier, requestingUser) + maybeSettings: Option[ProjectRestrictedViewSettingsADM] <- projectRestrictedViewSettingsGetADM( + identifier = identifier, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) settings = maybeSettings match { case Some(s) => s @@ -599,12 +682,17 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo * * @param projectIri the IRI of the project. * @param changeProjectRequest the change payload. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the user making the request. * @param apiRequestID the unique api request ID. * @return a [[ProjectOperationResponseADM]]. * @throws ForbiddenException in the case that the user is not allowed to perform the operation. */ - private def changeBasicInformationRequestADM(projectIri: IRI, changeProjectRequest: ChangeProjectApiRequestADM, requestingUser: UserADM, apiRequestID: UUID): Future[ProjectOperationResponseADM] = { + private def changeBasicInformationRequestADM(projectIri: IRI, + changeProjectRequest: ChangeProjectApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): Future[ProjectOperationResponseADM] = { //log.debug(s"changeBasicInformationRequestV1: changeProjectRequest: {}", changeProjectRequest) @@ -634,7 +722,12 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo selfjoin = changeProjectRequest.selfjoin ) - result <- updateProjectADM(projectIri, projectUpdatePayload, requestingUser = KnoraSystemInstances.Users.SystemUser) + result <- updateProjectADM( + projectIri = projectIri, + projectUpdatePayload = projectUpdatePayload, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) } yield result @@ -656,10 +749,14 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo * @param projectUpdatePayload the data to be updated. Update means exchanging what is in the triplestore with * this data. If only some parts of the data need to be changed, then this needs to * be prepared in the step before this one. + * @param featureFactoryConfig the feature factory configuration. * @return a [[ProjectOperationResponseADM]]. * @throws NotFoundException in the case that the project's IRI is not found. */ - private def updateProjectADM(projectIri: IRI, projectUpdatePayload: ProjectUpdatePayloadADM, requestingUser: UserADM): Future[ProjectOperationResponseADM] = { + private def updateProjectADM(projectIri: IRI, + projectUpdatePayload: ProjectUpdatePayloadADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[ProjectOperationResponseADM] = { // log.debug("updateProjectADM - projectIri: {}, projectUpdatePayload: {}", projectIri, projectUpdatePayload) @@ -676,7 +773,13 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo for { - maybeCurrentProject: Option[ProjectADM] <- getSingleProjectADM(identifier = ProjectIdentifierADM(maybeIri = Some(projectIri)), requestingUser = requestingUser, skipCache = true) + maybeCurrentProject: Option[ProjectADM] <- getSingleProjectADM( + identifier = ProjectIdentifierADM(maybeIri = Some(projectIri)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser, + skipCache = true + ) + _ = if (maybeCurrentProject.isEmpty) { throw NotFoundException(s"Project '$projectIri' not found. Aborting update request.") } @@ -702,7 +805,13 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo updateProjectResponse <- (storeManager ? SparqlUpdateRequest(updateProjectSparqlString)).mapTo[SparqlUpdateResponse] /* Verify that the project was updated. */ - maybeUpdatedProject <- getSingleProjectADM(identifier = ProjectIdentifierADM(maybeIri = Some(projectIri)), requestingUser = KnoraSystemInstances.Users.SystemUser, skipCache = true) + maybeUpdatedProject <- getSingleProjectADM( + identifier = ProjectIdentifierADM(maybeIri = Some(projectIri)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser, + skipCache = true + ) + updatedProject: ProjectADM = maybeUpdatedProject.getOrElse(throw UpdateNotPerformedException("Project was not updated. Please report this as a possible bug.")) _ = log.debug("updateProjectADM - projectUpdatePayload: {} / updatedProject: {}", projectUpdatePayload, updatedProject) @@ -743,6 +852,7 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo * Creates a project. * * @param createProjectRequest the new project's information. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the user that is making the request. * @param apiRequestID the unique api request ID. * @return a [[ProjectOperationResponseADM]]. @@ -750,7 +860,10 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo * @throws DuplicateValueException in the case when either the shortname or shortcode are not unique. * @throws BadRequestException in the case when the shortcode is invalid. */ - private def projectCreateRequestADM(createProjectRequest: CreateProjectApiRequestADM, requestingUser: UserADM, apiRequestID: UUID): Future[ProjectOperationResponseADM] = { + private def projectCreateRequestADM(createProjectRequest: CreateProjectApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): Future[ProjectOperationResponseADM] = { def projectCreateTask(createProjectRequest: CreateProjectApiRequestADM, requestingUser: UserADM): Future[ProjectOperationResponseADM] = for { @@ -807,9 +920,9 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo createProjectResponse <- (storeManager ? SparqlUpdateRequest(createNewProjectSparqlString)).mapTo[SparqlUpdateResponse] // try to retrieve newly created project (will also add to cache) - maybeNewProjectADM - <- getSingleProjectADM( + maybeNewProjectADM <- getSingleProjectADM( identifier = ProjectIdentifierADM(maybeIri = Some(newProjectIRI)), + featureFactoryConfig = featureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser, skipCache = true ) @@ -839,15 +952,18 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo /** * Tries to retrieve a [[ProjectADM]] either from triplestore or cache if caching is enabled. * If project is not found in cache but in triplestore, then project is written to cache. + * + * @param featureFactoryConfig the feature factory configuration. */ - private def getProjectFromCacheOrTriplestore(identifier: ProjectIdentifierADM): Future[Option[ProjectADM]] = { + private def getProjectFromCacheOrTriplestore(identifier: ProjectIdentifierADM, + featureFactoryConfig: FeatureFactoryConfig): Future[Option[ProjectADM]] = { if (settings.cacheServiceEnabled) { // caching enabled getProjectFromCache(identifier) .flatMap { case None => // none found in cache. getting from triplestore. - getProjectFromTriplestore(identifier) + getProjectFromTriplestore(identifier = identifier, featureFactoryConfig = featureFactoryConfig) .flatMap { case None => // also none found in triplestore. finally returning none. @@ -866,14 +982,17 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo } else { // caching disabled log.debug("getProjectFromCacheOrTriplestore - caching disabled. getting from triplestore.") - getProjectFromTriplestore(identifier) + getProjectFromTriplestore(identifier = identifier, featureFactoryConfig = featureFactoryConfig) } } /** * Tries to retrieve a [[ProjectADM]] from the triplestore. + * + * @param featureFactoryConfig the feature factory configuration. */ - private def getProjectFromTriplestore(identifier: ProjectIdentifierADM): Future[Option[ProjectADM]] = for { + private def getProjectFromTriplestore(identifier: ProjectIdentifierADM, + featureFactoryConfig: FeatureFactoryConfig): Future[Option[ProjectADM]] = for { sparqlQuery <- Future(org.knora.webapi.messages.twirl.queries.sparql.admin.txt.getProjects( triplestore = settings.triplestoreType, @@ -882,7 +1001,10 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo maybeShortcode = identifier.toShortcodeOption ).toString()) - projectResponse <- (storeManager ? SparqlExtendedConstructRequest(sparqlQuery)).mapTo[SparqlExtendedConstructResponse] + projectResponse <- (storeManager ? SparqlExtendedConstructRequest( + sparql = sparqlQuery, + featureFactoryConfig = featureFactoryConfig + )).mapTo[SparqlExtendedConstructResponse] projectIris = projectResponse.statements.keySet.map(_.toString) diff --git a/webapi/src/main/scala/org/knora/webapi/responders/admin/SipiResponderADM.scala b/webapi/src/main/scala/org/knora/webapi/responders/admin/SipiResponderADM.scala index 597a793a3b..c5446f5b03 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/admin/SipiResponderADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/admin/SipiResponderADM.scala @@ -69,7 +69,10 @@ class SipiResponderADM(responderData: ResponderData) extends Responder(responder filename = request.filename ).toString()) - queryResponse: SparqlExtendedConstructResponse <- (storeManager ? SparqlExtendedConstructRequest(sparqlQuery)).mapTo[SparqlExtendedConstructResponse] + queryResponse: SparqlExtendedConstructResponse <- (storeManager ? SparqlExtendedConstructRequest( + sparql = sparqlQuery, + featureFactoryConfig = request.featureFactoryConfig + )).mapTo[SparqlExtendedConstructResponse] _ = if (queryResponse.statements.isEmpty) throw NotFoundException(s"No file value was found for filename ${request.filename}") _ = if (queryResponse.statements.size > 1) throw InconsistentTriplestoreDataException(s"Filename ${request.filename} is used in more than one file value") @@ -101,7 +104,8 @@ class SipiResponderADM(responderData: ResponderData) extends Responder(responder for { maybeRVSettings <- ( responderManager ? ProjectRestrictedViewSettingsGetADM( - ProjectIdentifierADM(maybeShortcode = Some(request.projectID)), + identifier = ProjectIdentifierADM(maybeShortcode = Some(request.projectID)), + featureFactoryConfig = request.featureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser) ).mapTo[Option[ProjectRestrictedViewSettingsADM]] } yield SipiFileInfoGetResponseADM(permissionCode = permissionCode, maybeRVSettings) diff --git a/webapi/src/main/scala/org/knora/webapi/responders/admin/StoresResponderADM.scala b/webapi/src/main/scala/org/knora/webapi/responders/admin/StoresResponderADM.scala index 6b3b168546..d5c42b3055 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/admin/StoresResponderADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/admin/StoresResponderADM.scala @@ -21,12 +21,14 @@ package org.knora.webapi.responders.admin import akka.pattern._ import org.knora.webapi.exceptions.ForbiddenException +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.admin.responder.storesmessages.{ResetTriplestoreContentRequestADM, ResetTriplestoreContentResponseADM, StoreResponderRequestADM} import org.knora.webapi.messages.app.appmessages.GetAllowReloadOverHTTPState import org.knora.webapi.messages.store.cacheservicemessages.{CacheServiceFlushDB, CacheServiceFlushDBACK} import org.knora.webapi.messages.store.triplestoremessages.{RdfDataObject, ResetRepositoryContent, ResetRepositoryContentACK} import org.knora.webapi.messages.util.{KnoraSystemInstances, ResponderData} -import org.knora.webapi.messages.v1.responder.ontologymessages.{LoadOntologiesRequest, LoadOntologiesResponse} +import org.knora.webapi.messages.v2.responder.SuccessResponseV2 +import org.knora.webapi.messages.v2.responder.ontologymessages.LoadOntologiesRequestV2 import org.knora.webapi.responders.Responder import org.knora.webapi.responders.Responder.handleUnexpectedMessage @@ -48,7 +50,7 @@ class StoresResponderADM(responderData: ResponderData) extends Responder(respond * Receives a message extending [[StoreResponderRequestADM]], and returns an appropriate response message. */ def receive(msg: StoreResponderRequestADM) = msg match { - case ResetTriplestoreContentRequestADM(rdfDataObjects: Seq[RdfDataObject], prependDefaults: Boolean) => resetTriplestoreContent(rdfDataObjects, prependDefaults) + case ResetTriplestoreContentRequestADM(rdfDataObjects: Seq[RdfDataObject], prependDefaults: Boolean, featureFactoryConfig: FeatureFactoryConfig) => resetTriplestoreContent(rdfDataObjects, prependDefaults, featureFactoryConfig) case other => handleUnexpectedMessage(other, log, this.getClass.getName) } @@ -58,7 +60,9 @@ class StoresResponderADM(responderData: ResponderData) extends Responder(respond * @param rdfDataObjects the payload consisting of a list of [[RdfDataObject]] send inside the message. * @return a future containing a [[ResetTriplestoreContentResponseADM]]. */ - private def resetTriplestoreContent(rdfDataObjects: Seq[RdfDataObject], prependDefaults: Boolean = true): Future[ResetTriplestoreContentResponseADM] = { + private def resetTriplestoreContent(rdfDataObjects: Seq[RdfDataObject], + prependDefaults: Boolean = true, + featureFactoryConfig: FeatureFactoryConfig): Future[ResetTriplestoreContentResponseADM] = { log.debug(s"resetTriplestoreContent - called") @@ -71,7 +75,10 @@ class StoresResponderADM(responderData: ResponderData) extends Responder(respond resetResponse <- (storeManager ? ResetRepositoryContent(rdfDataObjects, prependDefaults)).mapTo[ResetRepositoryContentACK] _ = log.debug(s"resetTriplestoreContent - triplestore reset done - {}", resetResponse.toString) - loadOntologiesResponse <- (responderManager ? LoadOntologiesRequest(systemUser)).mapTo[LoadOntologiesResponse] + loadOntologiesResponse <- (responderManager ? LoadOntologiesRequestV2( + featureFactoryConfig = featureFactoryConfig, + requestingUser = systemUser + )).mapTo[SuccessResponseV2] _ = log.debug(s"resetTriplestoreContent - load ontology done - {}", loadOntologiesResponse.toString) redisFlushDB <- (storeManager ? CacheServiceFlushDB(systemUser)).mapTo[CacheServiceFlushDBACK] diff --git a/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala b/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala index e6c9059ea9..04c54a8b1a 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala @@ -24,6 +24,7 @@ import java.util.UUID import akka.http.scaladsl.util.FastFuture import akka.pattern._ import org.knora.webapi.exceptions._ +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.instrumentation.InstrumentationSupport import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.admin.responder.groupsmessages.{GroupADM, GroupGetADM} @@ -55,24 +56,24 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde * Receives a message extending [[UsersResponderRequestV1]], and returns an appropriate message. */ def receive(msg: UsersResponderRequestADM) = msg match { - case UsersGetADM(userInformationTypeADM, requestingUser) => getAllUserADM(userInformationTypeADM, requestingUser) - case UsersGetRequestADM(userInformationTypeADM, requestingUser) => getAllUserADMRequest(userInformationTypeADM, requestingUser) - case UserGetADM(identifier, userInformationTypeADM, requestingUser) => getSingleUserADM(identifier, userInformationTypeADM, requestingUser) - case UserGetRequestADM(identifier, userInformationTypeADM, requestingUser) => getSingleUserADMRequest(identifier, userInformationTypeADM, requestingUser) - case UserCreateRequestADM(createRequest, requestingUser, apiRequestID) => createNewUserADM(createRequest, requestingUser, apiRequestID) - case UserChangeBasicUserInformationRequestADM(userIri, changeUserRequest, requestingUser, apiRequestID) => changeBasicUserInformationADM(userIri, changeUserRequest, requestingUser, apiRequestID) - case UserChangePasswordRequestADM(userIri, changeUserRequest, requestingUser, apiRequestID) => changePasswordADM(userIri, changeUserRequest, requestingUser, apiRequestID) - case UserChangeStatusRequestADM(userIri, changeUserRequest, requestingUser, apiRequestID) => changeUserStatusADM(userIri, changeUserRequest, requestingUser, apiRequestID) - case UserChangeSystemAdminMembershipStatusRequestADM(userIri, changeSystemAdminMembershipStatusRequest, requestingUser, apiRequestID) => changeUserSystemAdminMembershipStatusADM(userIri, changeSystemAdminMembershipStatusRequest, requestingUser, apiRequestID) - case UserProjectMembershipsGetRequestADM(userIri, requestingUser, apiRequestID) => userProjectMembershipsGetRequestADM(userIri, requestingUser, apiRequestID) - case UserProjectMembershipAddRequestADM(userIri, projectIri, requestingUser, apiRequestID) => userProjectMembershipAddRequestADM(userIri, projectIri, requestingUser, apiRequestID) - case UserProjectMembershipRemoveRequestADM(userIri, projectIri, requestingUser, apiRequestID) => userProjectMembershipRemoveRequestADM(userIri, projectIri, requestingUser, apiRequestID) - case UserProjectAdminMembershipsGetRequestADM(userIri, requestingUser, apiRequestID) => userProjectAdminMembershipsGetRequestADM(userIri, requestingUser, apiRequestID) - case UserProjectAdminMembershipAddRequestADM(userIri, projectIri, requestingUser, apiRequestID) => userProjectAdminMembershipAddRequestADM(userIri, projectIri, requestingUser, apiRequestID) - case UserProjectAdminMembershipRemoveRequestADM(userIri, projectIri, requestingUser, apiRequestID) => userProjectAdminMembershipRemoveRequestADM(userIri, projectIri, requestingUser, apiRequestID) - case UserGroupMembershipsGetRequestADM(userIri, requestingUser, apiRequestID) => userGroupMembershipsGetRequestADM(userIri, requestingUser, apiRequestID) - case UserGroupMembershipAddRequestADM(userIri, projectIri, requestingUser, apiRequestID) => userGroupMembershipAddRequestADM(userIri, projectIri, requestingUser, apiRequestID) - case UserGroupMembershipRemoveRequestADM(userIri, projectIri, requestingUser, apiRequestID) => userGroupMembershipRemoveRequestADM(userIri, projectIri, requestingUser, apiRequestID) + case UsersGetADM(userInformationTypeADM, featureFactoryConfig, requestingUser) => getAllUserADM(userInformationTypeADM, featureFactoryConfig, requestingUser) + case UsersGetRequestADM(userInformationTypeADM, featureFactoryConfig, requestingUser) => getAllUserADMRequest(userInformationTypeADM, featureFactoryConfig, requestingUser) + case UserGetADM(identifier, userInformationTypeADM, featureFactoryConfig, requestingUser) => getSingleUserADM(identifier, userInformationTypeADM, featureFactoryConfig, requestingUser) + case UserGetRequestADM(identifier, userInformationTypeADM, featureFactoryConfig, requestingUser) => getSingleUserADMRequest(identifier, userInformationTypeADM, featureFactoryConfig, requestingUser) + case UserCreateRequestADM(createRequest, featureFactoryConfig, requestingUser, apiRequestID) => createNewUserADM(createRequest, featureFactoryConfig, requestingUser, apiRequestID) + case UserChangeBasicUserInformationRequestADM(userIri, changeUserRequest, featureFactoryConfig, requestingUser, apiRequestID) => changeBasicUserInformationADM(userIri, changeUserRequest, featureFactoryConfig, requestingUser, apiRequestID) + case UserChangePasswordRequestADM(userIri, changeUserRequest, featureFactoryConfig, requestingUser, apiRequestID) => changePasswordADM(userIri, changeUserRequest, featureFactoryConfig, requestingUser, apiRequestID) + case UserChangeStatusRequestADM(userIri, changeUserRequest, featureFactoryConfig, requestingUser, apiRequestID) => changeUserStatusADM(userIri, changeUserRequest, featureFactoryConfig, requestingUser, apiRequestID) + case UserChangeSystemAdminMembershipStatusRequestADM(userIri, changeSystemAdminMembershipStatusRequest, featureFactoryConfig, requestingUser, apiRequestID) => changeUserSystemAdminMembershipStatusADM(userIri, changeSystemAdminMembershipStatusRequest, featureFactoryConfig, requestingUser, apiRequestID) + case UserProjectMembershipsGetRequestADM(userIri, featureFactoryConfig, requestingUser) => userProjectMembershipsGetRequestADM(userIri, featureFactoryConfig, requestingUser) + case UserProjectMembershipAddRequestADM(userIri, projectIri, featureFactoryConfig, requestingUser, apiRequestID) => userProjectMembershipAddRequestADM(userIri, projectIri, featureFactoryConfig, requestingUser, apiRequestID) + case UserProjectMembershipRemoveRequestADM(userIri, projectIri, featureFactoryConfig, requestingUser, apiRequestID) => userProjectMembershipRemoveRequestADM(userIri, projectIri, featureFactoryConfig, requestingUser, apiRequestID) + case UserProjectAdminMembershipsGetRequestADM(userIri, featureFactoryConfig, requestingUser, apiRequestID) => userProjectAdminMembershipsGetRequestADM(userIri, featureFactoryConfig, requestingUser, apiRequestID) + case UserProjectAdminMembershipAddRequestADM(userIri, projectIri, featureFactoryConfig, requestingUser, apiRequestID) => userProjectAdminMembershipAddRequestADM(userIri, projectIri, featureFactoryConfig, requestingUser, apiRequestID) + case UserProjectAdminMembershipRemoveRequestADM(userIri, projectIri, featureFactoryConfig, requestingUser, apiRequestID) => userProjectAdminMembershipRemoveRequestADM(userIri, projectIri, featureFactoryConfig, requestingUser, apiRequestID) + case UserGroupMembershipsGetRequestADM(userIri, featureFactoryConfig, requestingUser) => userGroupMembershipsGetRequestADM(userIri, featureFactoryConfig, requestingUser) + case UserGroupMembershipAddRequestADM(userIri, projectIri, featureFactoryConfig, requestingUser, apiRequestID) => userGroupMembershipAddRequestADM(userIri, projectIri, featureFactoryConfig, requestingUser, apiRequestID) + case UserGroupMembershipRemoveRequestADM(userIri, projectIri, featureFactoryConfig, requestingUser, apiRequestID) => userGroupMembershipRemoveRequestADM(userIri, projectIri, featureFactoryConfig, requestingUser, apiRequestID) case other => handleUnexpectedMessage(other, log, this.getClass.getName) } @@ -80,11 +81,14 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde /** * Gets all the users and returns them as a sequence of [[UserADM]]. * - * @param userInformationType the extent of the information returned. - * @param requestingUser the user initiating the request. + * @param userInformationType the extent of the information returned. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. * @return all the users as a sequence of [[UserADM]]. */ - private def getAllUserADM(userInformationType: UserInformationTypeADM, requestingUser: UserADM): Future[Seq[UserADM]] = { + private def getAllUserADM(userInformationType: UserInformationTypeADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[Seq[UserADM]] = { //log.debug("getAllUserADM") @@ -102,7 +106,10 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde maybeEmail = None ).toString()) - usersResponse <- (storeManager ? SparqlExtendedConstructRequest(sparqlQueryString)).mapTo[SparqlExtendedConstructResponse] + usersResponse <- (storeManager ? SparqlExtendedConstructRequest( + sparql = sparqlQueryString, + featureFactoryConfig = featureFactoryConfig + )).mapTo[SparqlExtendedConstructResponse] statements = usersResponse.statements.toList @@ -127,13 +134,21 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde /** * Gets all the users and returns them as a [[UsersGetResponseADM]]. * - * @param userInformationType the extent of the information returned. - * @param requestingUser the user initiating the request. + * @param userInformationType the extent of the information returned. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. * @return all the users as a [[UsersGetResponseV1]]. */ - private def getAllUserADMRequest(userInformationType: UserInformationTypeADM, requestingUser: UserADM): Future[UsersGetResponseADM] = { + private def getAllUserADMRequest(userInformationType: UserInformationTypeADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[UsersGetResponseADM] = { for { - maybeUsersListToReturn <- getAllUserADM(userInformationType, requestingUser) + maybeUsersListToReturn <- getAllUserADM( + userInformationType = userInformationType, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) + result = maybeUsersListToReturn match { case users: Seq[UserADM] if users.nonEmpty => UsersGetResponseADM(users = users) @@ -150,19 +165,20 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde * it from the triplestore, and then writes it to the cache. Writes to the * cache are always `UserInformationTypeADM.FULL`. * - * @param identifier the IRI, email, or username of the user. - * @param userInformationType the type of the requested profile (restricted - * of full). - * @param requestingUser the user initiating the request. - * @param skipCache the flag denotes to skip the cache and instead - * get data from the triplestore + * @param identifier the IRI, email, or username of the user. + * @param userInformationType the type of the requested profile (restricted + * of full). + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user initiating the request. + * @param skipCache the flag denotes to skip the cache and instead + * get data from the triplestore * @return a [[UserADM]] describing the user. */ private def getSingleUserADM(identifier: UserIdentifierADM, userInformationType: UserInformationTypeADM, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, - skipCache: Boolean = false - ): Future[Option[UserADM]] = tracedFuture("admin-get-user") { + skipCache: Boolean = false): Future[Option[UserADM]] = tracedFuture("admin-get-user") { log.debug(s"getSingleUserADM - id: {}, type: {}, requester: {}, skipCache: {}", identifier.value, @@ -173,10 +189,10 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde for { maybeUserADM <- if (skipCache) { // getting directly from triplestore - getUserFromTriplestore(identifier) + getUserFromTriplestore(identifier = identifier, featureFactoryConfig = featureFactoryConfig) } else { // getting from cache or triplestore - getUserFromCacheOrTriplestore(identifier) + getUserFromCacheOrTriplestore(identifier, featureFactoryConfig) } // return the correct amount of information depending on either the request or user permission @@ -205,9 +221,18 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde * @param requestingUser the user initiating the request. * @return a [[UserResponseADM]] */ - private def getSingleUserADMRequest(identifier: UserIdentifierADM, userInformationType: UserInformationTypeADM, requestingUser: UserADM): Future[UserResponseADM] = { + private def getSingleUserADMRequest(identifier: UserIdentifierADM, + userInformationType: UserInformationTypeADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[UserResponseADM] = { for { - maybeUserADM <- getSingleUserADM(identifier, userInformationType, requestingUser) + maybeUserADM <- getSingleUserADM( + identifier = identifier, + userInformationType = userInformationType, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) + result = maybeUserADM match { case Some(user) => UserResponseADM(user = user) case None => throw NotFoundException(s"User '${identifier.value}' not found") @@ -220,15 +245,20 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde * Updates an existing user. Only basic user data information (username, email, givenName, familyName, lang) * can be changed. For changing the password or user status, use the separate methods. * - * @param userIri the IRI of the existing user that we want to update. - * @param changeUserRequest the updated information. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. + * @param userIri the IRI of the existing user that we want to update. + * @param changeUserRequest the updated information. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. * @return a future containing a [[UserOperationResponseADM]]. * @throws BadRequestException if the necessary parameters are not supplied. * @throws ForbiddenException if the user doesn't hold the necessary permission for the operation. */ - private def changeBasicUserInformationADM(userIri: IRI, changeUserRequest: ChangeUserApiRequestADM, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = { + private def changeBasicUserInformationADM(userIri: IRI, + changeUserRequest: ChangeUserApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): Future[UserOperationResponseADM] = { //log.debug(s"changeBasicUserDataV1: changeUserRequest: {}", changeUserRequest) @@ -254,9 +284,10 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde // get current user information currentUserInformation: Option[UserADM] <- getSingleUserADM( - UserIdentifierADM(maybeIri = Some(userIri)), - UserInformationTypeADM.FULL, - KnoraSystemInstances.Users.SystemUser + identifier = UserIdentifierADM(maybeIri = Some(userIri)), + userInformationType = UserInformationTypeADM.FULL, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser ) // check if user exists @@ -285,7 +316,13 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde ) // send change request as SystemUser - result <- updateUserADM(userIri, userUpdatePayload, KnoraSystemInstances.Users.SystemUser, apiRequestID) + result <- updateUserADM( + userIri = userIri, + userUpdatePayload = userUpdatePayload, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser, + apiRequestID = apiRequestID + ) } yield result for { @@ -302,17 +339,22 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde /** * Change the users password. The old password needs to be supplied for security purposes. * - * @param userIri the IRI of the existing user that we want to update. - * @param changeUserRequest the current password of the requesting user and the new password. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. + * @param userIri the IRI of the existing user that we want to update. + * @param changeUserRequest the current password of the requesting user and the new password. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. * @return a future containing a [[UserOperationResponseADM]]. * @throws BadRequestException if necessary parameters are not supplied. * @throws ForbiddenException if the user doesn't hold the necessary permission for the operation. * @throws ForbiddenException if the supplied old password doesn't match with the user's current password. * @throws NotFoundException if the user is not found. */ - private def changePasswordADM(userIri: IRI, changeUserRequest: ChangeUserApiRequestADM, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = { + private def changePasswordADM(userIri: IRI, + changeUserRequest: ChangeUserApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): Future[UserOperationResponseADM] = { log.debug(s"changePasswordADM - userIri: {}", userIri) log.debug(s"changePasswordADM - changeUserRequest: {}", changeUserRequest) @@ -345,7 +387,13 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde userUpdatePayload = UserUpdatePayloadADM(password = Some(newHashedPassword)) // update the users password as SystemUser - result <- updateUserADM(userIri, userUpdatePayload, KnoraSystemInstances.Users.SystemUser, apiRequestID) + result <- updateUserADM( + userIri = userIri, + userUpdatePayload = userUpdatePayload, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser, + apiRequestID = apiRequestID + ) } yield result @@ -362,15 +410,20 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde /** * Change the user's status (active / inactive). * - * @param userIri the IRI of the existing user that we want to update. - * @param changeUserRequest the new status. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. + * @param userIri the IRI of the existing user that we want to update. + * @param changeUserRequest the new status. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. * @return a future containing a [[UserOperationResponseADM]]. * @throws BadRequestException if necessary parameters are not supplied. * @throws ForbiddenException if the user doesn't hold the necessary permission for the operation. */ - private def changeUserStatusADM(userIri: IRI, changeUserRequest: ChangeUserApiRequestADM, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = { + private def changeUserStatusADM(userIri: IRI, + changeUserRequest: ChangeUserApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): Future[UserOperationResponseADM] = { log.debug(s"changeUserStatusADM - changeUserRequest: {}", changeUserRequest) @@ -395,7 +448,13 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde // create the update request userUpdatePayload = UserUpdatePayloadADM(status = changeUserRequest.status) - result <- updateUserADM(userIri, userUpdatePayload, KnoraSystemInstances.Users.SystemUser, apiRequestID) + result <- updateUserADM( + userIri = userIri, + userUpdatePayload = userUpdatePayload, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser, + apiRequestID = apiRequestID + ) } yield result @@ -412,15 +471,20 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde /** * Change the user's system admin membership status (active / inactive). * - * @param userIri the IRI of the existing user that we want to update. - * @param changeUserRequest the new status. - * @param requestingUser the user profile of the requesting user. - * @param apiRequestID the unique api request ID. + * @param userIri the IRI of the existing user that we want to update. + * @param changeUserRequest the new status. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user profile of the requesting user. + * @param apiRequestID the unique api request ID. * @return a future containing a [[UserOperationResponseADM]]. * @throws BadRequestException if necessary parameters are not supplied. * @throws ForbiddenException if the user doesn't hold the necessary permission for the operation. */ - private def changeUserSystemAdminMembershipStatusADM(userIri: IRI, changeUserRequest: ChangeUserApiRequestADM, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = { + private def changeUserSystemAdminMembershipStatusADM(userIri: IRI, + changeUserRequest: ChangeUserApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): Future[UserOperationResponseADM] = { //log.debug(s"changeUserSystemAdminMembershipStatusV1: changeUserRequest: {}", changeUserRequest) @@ -443,7 +507,13 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde // create the update request userUpdatePayload = UserUpdatePayloadADM(systemAdmin = changeUserRequest.systemAdmin) - result <- updateUserADM(userIri, userUpdatePayload, KnoraSystemInstances.Users.SystemUser, apiRequestID) + result <- updateUserADM( + userIri = userIri, + userUpdatePayload = userUpdatePayload, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser, + apiRequestID = apiRequestID + ) } yield result @@ -464,12 +534,19 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde * * @param userIri the IRI of the user. * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. * @return a sequence of [[ProjectADM]] */ - private def userProjectMembershipsGetADM(userIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[Seq[ProjectADM]] = { + private def userProjectMembershipsGetADM(userIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[Seq[ProjectADM]] = { for { - maybeUser <- getSingleUserADM(identifier = UserIdentifierADM(maybeIri = Some(userIri)), userInformationType = UserInformationTypeADM.FULL, requestingUser = KnoraSystemInstances.Users.SystemUser) + maybeUser <- getSingleUserADM( + identifier = UserIdentifierADM(maybeIri = Some(userIri)), + userInformationType = UserInformationTypeADM.FULL, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) + result = maybeUser match { case Some(userADM) => userADM.projects case None => Seq.empty[ProjectADM] @@ -484,10 +561,11 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde * * @param userIri the user's IRI. * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. * @return a [[UserProjectMembershipsGetResponseADM]]. */ - private def userProjectMembershipsGetRequestADM(userIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[UserProjectMembershipsGetResponseADM] = { + private def userProjectMembershipsGetRequestADM(userIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[UserProjectMembershipsGetResponseADM] = { for { userExists <- userExists(userIri) @@ -495,7 +573,12 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde throw BadRequestException(s"User $userIri does not exist.") } - projects: Seq[ProjectADM] <- userProjectMembershipsGetADM(userIri, requestingUser, apiRequestID = apiRequestID) + projects: Seq[ProjectADM] <- userProjectMembershipsGetADM( + userIri = userIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) + result = UserProjectMembershipsGetResponseADM(projects = projects) } yield result } @@ -503,13 +586,18 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde /** * Adds a user to a project. * - * @param userIri the user's IRI. - * @param projectIri the project's IRI. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. + * @param userIri the user's IRI. + * @param projectIri the project's IRI. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. * @return */ - private def userProjectMembershipAddRequestADM(userIri: IRI, projectIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = { + private def userProjectMembershipAddRequestADM(userIri: IRI, + projectIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): Future[UserOperationResponseADM] = { log.debug(s"userProjectMembershipAddRequestADM: userIri: {}, projectIri: {}", userIri, projectIri) @@ -540,8 +628,8 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde // get users current project membership list currentProjectMemberships <- userProjectMembershipsGetRequestADM( userIri = userIri, - requestingUser = KnoraSystemInstances.Users.SystemUser, - apiRequestID = apiRequestID + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser ) currentProjectMembershipIris: Seq[IRI] = currentProjectMemberships.projects.map(_.id) @@ -556,8 +644,13 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde // create the update request userUpdatePayload = UserUpdatePayloadADM(projects = Some(updatedProjectMembershipIris)) - result <- updateUserADM(userIri, userUpdatePayload, requestingUser, apiRequestID) - + result <- updateUserADM( + userIri = userIri, + userUpdatePayload = userUpdatePayload, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser, + apiRequestID = apiRequestID + ) } yield result @@ -575,13 +668,18 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde /** * Removes a user from a project. * - * @param userIri the user's IRI. - * @param projectIri the project's IRI. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. + * @param userIri the user's IRI. + * @param projectIri the project's IRI. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. * @return */ - private def userProjectMembershipRemoveRequestADM(userIri: IRI, projectIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = { + private def userProjectMembershipRemoveRequestADM(userIri: IRI, + projectIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): Future[UserOperationResponseADM] = { // log.debug(s"userProjectMembershipRemoveRequestV1: userIri: {}, projectIri: {}", userIri, projectIri) @@ -612,8 +710,8 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde // get users current project membership list currentProjectMemberships <- userProjectMembershipsGetADM( userIri = userIri, - requestingUser = KnoraSystemInstances.Users.SystemUser, - apiRequestID = apiRequestID + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser ) currentProjectMembershipIris = currentProjectMemberships.map(_.id) @@ -627,8 +725,13 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde // create the update request by using the SystemUser userUpdatePayload = UserUpdatePayloadADM(projects = Some(updatedProjectMembershipIris)) - result <- updateUserADM(userIri = userIri, userUpdatePayload = userUpdatePayload, requestingUser = KnoraSystemInstances.Users.SystemUser, apiRequestID = apiRequestID) - + result <- updateUserADM( + userIri = userIri, + userUpdatePayload = userUpdatePayload, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser, + apiRequestID = apiRequestID + ) } yield result @@ -645,12 +748,16 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde /** * Returns the user's project admin group memberships as a sequence of [[IRI]] * - * @param userIri the user's IRI. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. + * @param userIri the user's IRI. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. * @return a [[UserProjectMembershipsGetResponseV1]]. */ - private def userProjectAdminMembershipsGetADM(userIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[Seq[ProjectADM]] = { + private def userProjectAdminMembershipsGetADM(userIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): Future[Seq[ProjectADM]] = { // ToDo: only allow system user // ToDo: this is a bit of a hack since the ProjectAdmin group doesn't really exist. @@ -676,7 +783,12 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } maybeProjectFutures: Seq[Future[Option[ProjectADM]]] = projectIris.map { - projectIri => (responderManager ? ProjectGetADM(identifier = ProjectIdentifierADM(maybeIri = Some(projectIri)), requestingUser = KnoraSystemInstances.Users.SystemUser)).mapTo[Option[ProjectADM]] + projectIri => + (responderManager ? ProjectGetADM( + identifier = ProjectIdentifierADM(maybeIri = Some(projectIri)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + )).mapTo[Option[ProjectADM]] } maybeProjects: Seq[Option[ProjectADM]] <- Future.sequence(maybeProjectFutures) projects: Seq[ProjectADM] = maybeProjects.flatten @@ -689,12 +801,16 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde * Returns the user's project admin group memberships, where the result contains the IRIs of the projects the user * is a member of the project admin group. * - * @param userIri the user's IRI. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. + * @param userIri the user's IRI. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. * @return a [[UserProjectMembershipsGetResponseV1]]. */ - private def userProjectAdminMembershipsGetRequestADM(userIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[UserProjectAdminMembershipsGetResponseADM] = { + private def userProjectAdminMembershipsGetRequestADM(userIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): Future[UserProjectAdminMembershipsGetResponseADM] = { // ToDo: which user is allowed to do this operation? // ToDo: check permissions @@ -705,20 +821,30 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde throw BadRequestException(s"User $userIri does not exist.") } - projects: Seq[ProjectADM] <- userProjectAdminMembershipsGetADM(userIri = userIri, requestingUser = KnoraSystemInstances.Users.SystemUser, apiRequestID = apiRequestID) + projects: Seq[ProjectADM] <- userProjectAdminMembershipsGetADM( + userIri = userIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser, + apiRequestID = apiRequestID + ) } yield UserProjectAdminMembershipsGetResponseADM(projects = projects) } /** * Adds a user to the project admin group of a project. * - * @param userIri the user's IRI. - * @param projectIri the project's IRI. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. + * @param userIri the user's IRI. + * @param projectIri the project's IRI. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. * @return */ - private def userProjectAdminMembershipAddRequestADM(userIri: IRI, projectIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = { + private def userProjectAdminMembershipAddRequestADM(userIri: IRI, + projectIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): Future[UserOperationResponseADM] = { // log.debug(s"userProjectAdminMembershipAddRequestV1: userIri: {}, projectIri: {}", userIri, projectIri) @@ -749,6 +875,7 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde // get users current project membership list currentProjectAdminMemberships <- userProjectAdminMembershipsGetADM( userIri = userIri, + featureFactoryConfig = featureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser, apiRequestID = apiRequestID ) @@ -765,8 +892,13 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde // create the update request userUpdatePayload = UserUpdatePayloadADM(projectsAdmin = Some(updatedProjectAdminMembershipIris)) - result <- updateUserADM(userIri, userUpdatePayload, requestingUser = KnoraSystemInstances.Users.SystemUser, apiRequestID) - + result <- updateUserADM( + userIri = userIri, + userUpdatePayload = userUpdatePayload, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser, + apiRequestID = apiRequestID + ) } yield result @@ -784,13 +916,18 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde /** * Removes a user from project admin group of a project. * - * @param userIri the user's IRI. - * @param projectIri the project's IRI. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. + * @param userIri the user's IRI. + * @param projectIri the project's IRI. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. * @return */ - private def userProjectAdminMembershipRemoveRequestADM(userIri: IRI, projectIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = { + private def userProjectAdminMembershipRemoveRequestADM(userIri: IRI, + projectIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): Future[UserOperationResponseADM] = { // log.debug(s"userProjectAdminMembershipRemoveRequestV1: userIri: {}, projectIri: {}", userIri, projectIri) @@ -821,6 +958,7 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde // get users current project membership list currentProjectAdminMemberships <- userProjectAdminMembershipsGetADM( userIri = userIri, + featureFactoryConfig = featureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser, apiRequestID = apiRequestID ) @@ -837,8 +975,13 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde // create the update request userUpdatePayload = UserUpdatePayloadADM(projectsAdmin = Some(updatedProjectAdminMembershipIris)) - result <- updateUserADM(userIri, userUpdatePayload, requestingUser = KnoraSystemInstances.Users.SystemUser, apiRequestID) - + result <- updateUserADM( + userIri = userIri, + userUpdatePayload = userUpdatePayload, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser, + apiRequestID = apiRequestID + ) } yield result for { @@ -855,15 +998,23 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde /** * Returns the user's group memberships as a sequence of [[GroupADM]] * - * @param userIri the IRI of the user. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. + * @param userIri the IRI of the user. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the requesting user. * @return a sequence of [[GroupADM]]. */ - private def userGroupMembershipsGetADM(userIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[Seq[GroupADM]] = { + private def userGroupMembershipsGetADM(userIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[Seq[GroupADM]] = { for { - maybeUserADM: Option[UserADM] <- getSingleUserADM(identifier = UserIdentifierADM(maybeIri = Some(userIri)), userInformationType = UserInformationTypeADM.FULL, requestingUser = KnoraSystemInstances.Users.SystemUser) + maybeUserADM: Option[UserADM] <- getSingleUserADM( + identifier = UserIdentifierADM(maybeIri = Some(userIri)), + userInformationType = UserInformationTypeADM.FULL, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) + groups: Seq[GroupADM] = maybeUserADM match { case Some(user) => log.debug("userGroupMembershipsGetADM - user found. Returning his groups: {}.", user.groups) @@ -879,16 +1030,21 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde /** * Returns the user's group memberships as a [[UserGroupMembershipsGetResponseADM]] * - * @param userIri the IRI of the user. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. + * @param userIri the IRI of the user. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the requesting user. * @return a [[UserGroupMembershipsGetResponseADM]]. */ - private def userGroupMembershipsGetRequestADM(userIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[UserGroupMembershipsGetResponseADM] = { + private def userGroupMembershipsGetRequestADM(userIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[UserGroupMembershipsGetResponseADM] = { for { - groups: Seq[GroupADM] <- userGroupMembershipsGetADM(userIri, requestingUser, apiRequestID) - + groups: Seq[GroupADM] <- userGroupMembershipsGetADM( + userIri = userIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser, + ) } yield UserGroupMembershipsGetResponseADM(groups = groups) } @@ -896,13 +1052,18 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde /** * Adds a user to a group. * - * @param userIri the user's IRI. - * @param groupIri the group IRI. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. + * @param userIri the user's IRI. + * @param groupIri the group IRI. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. * @return a [[UserOperationResponseADM]]. */ - private def userGroupMembershipAddRequestADM(userIri: IRI, groupIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = { + private def userGroupMembershipAddRequestADM(userIri: IRI, + groupIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): Future[UserOperationResponseADM] = { log.debug(s"userGroupMembershipAddRequestADM - userIri: {}, groupIri: {}", userIri, groupIri) @@ -916,7 +1077,14 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde _ = if (groupIri.isEmpty) throw BadRequestException("Group IRI cannot be empty") // check if user exists - maybeUser <- getSingleUserADM(UserIdentifierADM(maybeIri = Some(userIri)), UserInformationTypeADM.FULL, KnoraSystemInstances.Users.SystemUser, skipCache = true) + maybeUser <- getSingleUserADM( + UserIdentifierADM(maybeIri = Some(userIri)), + UserInformationTypeADM.FULL, + featureFactoryConfig = featureFactoryConfig, + KnoraSystemInstances.Users.SystemUser, + skipCache = true + ) + userToChange: UserADM = maybeUser match { case Some(user) => user case None => throw NotFoundException(s"The user $userIri does not exist.") @@ -927,7 +1095,11 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde _ = if (!groupExists) throw NotFoundException(s"The group $groupIri does not exist.") // get group's info. we need the project IRI. - maybeGroupADM <- (responderManager ? GroupGetADM(groupIri, KnoraSystemInstances.Users.SystemUser)).mapTo[Option[GroupADM]] + maybeGroupADM <- (responderManager ? GroupGetADM( + groupIri = groupIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + )).mapTo[Option[GroupADM]] projectIri = maybeGroupADM.getOrElse(throw InconsistentTriplestoreDataException(s"Group $groupIri does not exist")).project.id // check if the requesting user is allowed to perform updates @@ -956,8 +1128,13 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde // create the update request userUpdatePayload = UserUpdatePayloadADM(groups = Some(updatedGroupMembershipIris)) - result <- updateUserADM(userIri, userUpdatePayload, requestingUser = KnoraSystemInstances.Users.SystemUser, apiRequestID) - + result <- updateUserADM( + userIri = userIri, + userUpdatePayload = userUpdatePayload, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser, + apiRequestID = apiRequestID + ) } yield result @@ -972,7 +1149,11 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } - private def userGroupMembershipRemoveRequestADM(userIri: IRI, groupIri: IRI, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = { + private def userGroupMembershipRemoveRequestADM(userIri: IRI, + groupIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): Future[UserOperationResponseADM] = { log.debug(s"userGroupMembershipRemoveRequestADM - userIri: {}, groupIri: {}", userIri, groupIri) @@ -994,7 +1175,12 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde _ = if (!projectExists) throw NotFoundException(s"The group $groupIri does not exist.") // get group's info. we need the project IRI. - maybeGroupADM <- (responderManager ? GroupGetADM(groupIri, KnoraSystemInstances.Users.SystemUser)).mapTo[Option[GroupADM]] + maybeGroupADM <- (responderManager ? GroupGetADM( + groupIri = groupIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + )).mapTo[Option[GroupADM]] + projectIri = maybeGroupADM.getOrElse(throw exceptions.InconsistentTriplestoreDataException(s"Group $groupIri does not exist")).project.id // check if the requesting user is allowed to perform updates @@ -1007,8 +1193,8 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde // get users current project membership list currentGroupMemberships <- userGroupMembershipsGetRequestADM( userIri = userIri, - requestingUser = KnoraSystemInstances.Users.SystemUser, - apiRequestID = apiRequestID + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser ) currentGroupMembershipIris: Seq[IRI] = currentGroupMemberships.groups.map(_.id) @@ -1027,8 +1213,13 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde // create the update request userUpdatePayload = UserUpdatePayloadADM(groups = Some(updatedGroupMembershipIris)) - result <- updateUserADM(userIri, userUpdatePayload, requestingUser, apiRequestID) - + result <- updateUserADM( + userIri = userIri, + userUpdatePayload = userUpdatePayload, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser, + apiRequestID = apiRequestID + ) } yield result @@ -1046,15 +1237,20 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde /** * Updates an existing user. Should not be directly used from the receive method. * - * @param userIri the IRI of the existing user that we want to update. - * @param userUpdatePayload the updated information. - * @param requestingUser the requesting user. - * @param apiRequestID the unique api request ID. + * @param userIri the IRI of the existing user that we want to update. + * @param userUpdatePayload the updated information. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the requesting user. + * @param apiRequestID the unique api request ID. * @return a future containing a [[UserOperationResponseADM]]. * @throws BadRequestException if necessary parameters are not supplied. * @throws UpdateNotPerformedException if the update was not performed. */ - private def updateUserADM(userIri: IRI, userUpdatePayload: UserUpdatePayloadADM, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = { + private def updateUserADM(userIri: IRI, + userUpdatePayload: UserUpdatePayloadADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): Future[UserOperationResponseADM] = { log.debug("updateUserADM - userUpdatePayload: {}", userUpdatePayload) @@ -1065,7 +1261,14 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } for { - maybeCurrentUser <- getSingleUserADM(identifier = UserIdentifierADM(maybeIri = Some(userIri)), requestingUser = requestingUser, userInformationType = UserInformationTypeADM.FULL, skipCache = true) + maybeCurrentUser <- getSingleUserADM( + identifier = UserIdentifierADM(maybeIri = Some(userIri)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser, + userInformationType = UserInformationTypeADM.FULL, + skipCache = true + ) + _ = if (maybeCurrentUser.isEmpty) { throw NotFoundException(s"User '$userIri' not found. Aborting update request.") } @@ -1093,7 +1296,14 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde updateResult <- (storeManager ? SparqlUpdateRequest(updateUserSparqlString)).mapTo[SparqlUpdateResponse] /* Verify that the user was updated. */ - maybeUpdatedUserADM <- getSingleUserADM(identifier = UserIdentifierADM(maybeIri = Some(userIri)), requestingUser = requestingUser, userInformationType = UserInformationTypeADM.FULL, skipCache = true) + maybeUpdatedUserADM <- getSingleUserADM( + identifier = UserIdentifierADM(maybeIri = Some(userIri)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser, + userInformationType = UserInformationTypeADM.FULL, + skipCache = true + ) + updatedUserADM: UserADM = maybeUpdatedUserADM.getOrElse(throw UpdateNotPerformedException("User was not updated. Please report this as a possible bug.")) // _ = log.debug(s"===>>> apiUpdateRequest: $userUpdatePayload / updatedUserADM: $updatedUserADM") @@ -1145,11 +1355,15 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde * - https://crackstation.net/hashing-security.htm * - http://blog.ircmaxell.com/2012/12/seven-ways-to-screw-up-bcrypt.html * - * @param createRequest a [[CreateUserApiRequestADM]] object containing information about the new user to be created. - * @param requestingUser a [[UserADM]] object containing information about the requesting user. + * @param createRequest a [[CreateUserApiRequestADM]] object containing information about the new user to be created. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser a [[UserADM]] object containing information about the requesting user. * @return a future containing the [[UserOperationResponseADM]]. */ - private def createNewUserADM(createRequest: CreateUserApiRequestADM, requestingUser: UserADM, apiRequestID: UUID): Future[UserOperationResponseADM] = { + private def createNewUserADM(createRequest: CreateUserApiRequestADM, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): Future[UserOperationResponseADM] = { log.debug("createNewUserADM - createRequest: {}", createRequest) @@ -1208,6 +1422,7 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde // try to retrieve newly created user (will also add to cache) maybeNewUserADM: Option[UserADM] <- getSingleUserADM( identifier = UserIdentifierADM(maybeIri = Some(userIri)), + featureFactoryConfig = featureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser, userInformationType = UserInformationTypeADM.FULL, skipCache = true @@ -1242,14 +1457,14 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde * Tries to retrieve a [[UserADM]] either from triplestore or cache if caching is enabled. * If user is not found in cache but in triplestore, then user is written to cache. */ - private def getUserFromCacheOrTriplestore(identifier: UserIdentifierADM): Future[Option[UserADM]] = { + private def getUserFromCacheOrTriplestore(identifier: UserIdentifierADM, featureFactoryConfig: FeatureFactoryConfig): Future[Option[UserADM]] = { if (settings.cacheServiceEnabled) { // caching enabled getUserFromCache(identifier) .flatMap { case None => // none found in cache. getting from triplestore. - getUserFromTriplestore(identifier) + getUserFromTriplestore(identifier = identifier, featureFactoryConfig = featureFactoryConfig) .flatMap { case None => // also none found in triplestore. finally returning none. @@ -1268,14 +1483,15 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde } else { // caching disabled log.debug("getUserFromCacheOrTriplestore - caching disabled. getting from triplestore.") - getUserFromTriplestore(identifier) + getUserFromTriplestore(identifier = identifier, featureFactoryConfig = featureFactoryConfig) } } /** * Tries to retrieve a [[UserADM]] from the triplestore. */ - private def getUserFromTriplestore(identifier: UserIdentifierADM): Future[Option[UserADM]] = for { + private def getUserFromTriplestore(identifier: UserIdentifierADM, + featureFactoryConfig: FeatureFactoryConfig): Future[Option[UserADM]] = for { sparqlQueryString <- Future(org.knora.webapi.messages.twirl.queries.sparql.admin.txt.getUsers( triplestore = settings.triplestoreType, maybeIri = identifier.toIriOption, @@ -1283,11 +1499,17 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde maybeEmail = identifier.toEmailOption ).toString()) - userQueryResponse <- (storeManager ? SparqlExtendedConstructRequest(sparqlQueryString)).mapTo[SparqlExtendedConstructResponse] + userQueryResponse <- (storeManager ? SparqlExtendedConstructRequest( + sparql = sparqlQueryString, + featureFactoryConfig = featureFactoryConfig + )).mapTo[SparqlExtendedConstructResponse] maybeUserADM: Option[UserADM] <- if (userQueryResponse.statements.nonEmpty) { log.debug("getUserFromTriplestore - triplestore hit for: {}", identifier) - statements2UserADM(userQueryResponse.statements.head) + statements2UserADM( + statements = userQueryResponse.statements.head, + featureFactoryConfig = featureFactoryConfig + ) } else { log.debug("getUserFromTriplestore - no triplestore hit for: {}", identifier) FastFuture.successful(None) @@ -1298,10 +1520,12 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde /** * Helper method used to create a [[UserADM]] from the [[SparqlExtendedConstructResponse]] containing user data. * - * @param statements result from the SPARQL query containing user data. + * @param statements result from the SPARQL query containing user data. + * @param featureFactoryConfig the feature factory configuration. * @return a [[UserADM]] containing the user's data. */ - private def statements2UserADM(statements: (SubjectV2, Map[SmartIri, Seq[LiteralV2]])): Future[Option[UserADM]] = { + private def statements2UserADM(statements: (SubjectV2, Map[SmartIri, Seq[LiteralV2]]), + featureFactoryConfig: FeatureFactoryConfig): Future[Option[UserADM]] = { // log.debug("statements2UserADM - statements: {}", statements) @@ -1340,11 +1564,17 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde groupIris = groupIris, isInProjectAdminGroups = isInProjectAdminGroups, isInSystemAdminGroup = isInSystemAdminGroup, + featureFactoryConfig = featureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser )).mapTo[PermissionsDataADM] maybeGroupFutures: Seq[Future[Option[GroupADM]]] = groupIris.map { - groupIri => (responderManager ? GroupGetADM(groupIri = groupIri, requestingUser = KnoraSystemInstances.Users.SystemUser)).mapTo[Option[GroupADM]] + groupIri => + (responderManager ? GroupGetADM( + groupIri = groupIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + )).mapTo[Option[GroupADM]] } maybeGroups: Seq[Option[GroupADM]] <- Future.sequence(maybeGroupFutures) groups: Seq[GroupADM] = maybeGroups.flatten @@ -1352,7 +1582,12 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde // _ = log.debug("statements2UserADM - groups: {}", MessageUtil.toSource(groups)) maybeProjectFutures: Seq[Future[Option[ProjectADM]]] = projectIris.map { - projectIri => (responderManager ? ProjectGetADM(ProjectIdentifierADM(maybeIri = Some(projectIri)), requestingUser = KnoraSystemInstances.Users.SystemUser)).mapTo[Option[ProjectADM]] + projectIri => + (responderManager ? ProjectGetADM( + ProjectIdentifierADM(maybeIri = Some(projectIri)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + )).mapTo[Option[ProjectADM]] } maybeProjects: Seq[Option[ProjectADM]] <- Future.sequence(maybeProjectFutures) projects: Seq[ProjectADM] = maybeProjects.flatten diff --git a/webapi/src/main/scala/org/knora/webapi/responders/v1/CkanResponderV1.scala b/webapi/src/main/scala/org/knora/webapi/responders/v1/CkanResponderV1.scala index 89b1604c38..dbabc7251b 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/v1/CkanResponderV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/v1/CkanResponderV1.scala @@ -25,6 +25,7 @@ import akka.actor.ActorRef import akka.pattern._ import akka.util.Timeout import org.knora.webapi.IRI +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.OntologyConstants import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.store.triplestoremessages.{SparqlSelectRequest, SparqlSelectResponse, VariableResultsRow} @@ -57,11 +58,15 @@ class CkanResponderV1(responderData: ResponderData) extends Responder(responderD * Receives a message extending [[CkanResponderRequestV1]], and returns an appropriate response message. */ def receive(msg: CkanResponderRequestV1) = msg match { - case CkanRequestV1(projects, limit, info, userProfile) => getCkanResponseV1(projects, limit, info, userProfile) + case CkanRequestV1(projects, limit, info, featureFactoryConfig, userProfile) => getCkanResponseV1(projects, limit, info, featureFactoryConfig, userProfile) case other => handleUnexpectedMessage(other, log, this.getClass.getName) } - private def getCkanResponseV1(project: Option[Seq[String]], limit: Option[Int], info: Boolean, userProfile: UserADM): Future[CkanResponseV1] = { + private def getCkanResponseV1(project: Option[Seq[String]], + limit: Option[Int], + info: Boolean, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[CkanResponseV1] = { log.debug("Ckan Endpoint:") @@ -75,18 +80,43 @@ class CkanResponderV1(responderData: ResponderData) extends Responder(responderD case Some(projectList) => // look up resources only for these projects if allowed val allowedProjects = projectList.filter(defaultProjectList.contains(_)) - getProjectInfos(allowedProjects, userProfile) + getProjectInfos( + projectNames = allowedProjects, + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) case None => // return our default project map, containing all projects that we want to serve over the Ckan endpoint - getProjectInfos(defaultProjectList, userProfile) + getProjectInfos( + projectNames = defaultProjectList, + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) } for { projects <- selectedProjectsFuture ckanProjects: Seq[Future[CkanProjectV1]] = projects flatMap { - case ("dokubib", projectFullInfo) => Some(getDokubibCkanProject(projectFullInfo, limit, userProfile)) - case ("incunabula", projectFullInfo) => Some(getIncunabulaCkanProject(projectFullInfo, limit, userProfile)) + case ("dokubib", projectFullInfo) => + Some( + getDokubibCkanProject( + pinfo = projectFullInfo, + limit = limit, + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) + ) + + case ("incunabula", projectFullInfo) => Some( + getIncunabulaCkanProject( + pinfo = projectFullInfo, + limit = limit, + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) + ) + case _ => None } result <- Future.sequence(ckanProjects) @@ -107,7 +137,10 @@ class CkanResponderV1(responderData: ResponderData) extends Responder(responderD * @param userProfile * @return */ - private def getDokubibCkanProject(pinfo: ProjectInfoV1, limit: Option[Int], userProfile: UserADM): Future[CkanProjectV1] = { + private def getDokubibCkanProject(pinfo: ProjectInfoV1, + limit: Option[Int], + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[CkanProjectV1] = { /* - datasets @@ -130,7 +163,13 @@ class CkanResponderV1(responderData: ResponderData) extends Responder(responderD val datasetsFuture: Future[Seq[CkanProjectDatasetV1]] = for { bilder <- getDokubibBilderIRIs(pIri, limit) - bilderMitPropsFuture = getResources(bilder, userProfile) + + bilderMitPropsFuture = getResources( + iris = bilder, + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) + bilderMitProps <- bilderMitPropsFuture dataset = bilderMitProps.map { case (iri, info, props) => @@ -195,10 +234,14 @@ class CkanResponderV1(responderData: ResponderData) extends Responder(responderD * * @param pinfo * @param limit + * @param featureFactoryConfig the feature factory configuration. * @param userProfile * @return */ - private def getIncunabulaCkanProject(pinfo: ProjectInfoV1, limit: Option[Int], userProfile: UserADM): Future[CkanProjectV1] = { + private def getIncunabulaCkanProject(pinfo: ProjectInfoV1, + limit: Option[Int], + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[CkanProjectV1] = { /* - datasets @@ -223,17 +266,26 @@ class CkanResponderV1(responderData: ResponderData) extends Responder(responderD val booksWithPagesFuture = getIncunabulaBooksWithPagesIRIs(pIri, limit) val bookDatasetsFuture = booksWithPagesFuture.flatMap { - case singleBook => + singleBook => val bookDataset = singleBook map { case (bookIri: IRI, pageIris: Seq[IRI]) => - val bookResourceFuture = getResource(bookIri, userProfile) + val bookResourceFuture = getResource( + iri = bookIri, + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) + bookResourceFuture flatMap { case (bIri, bInfo, bProps) => val bInfoMap = flattenInfo(bInfo) val bPropsMap = flattenProps(bProps) val files = pageIris map { - case pageIri => - getResource(pageIri, userProfile) map { + pageIri => + getResource( + iri = pageIri, + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) map { case (pIri, pInfo, pProps) => val pInfoMap = flattenInfo(pInfo) val pPropsMap = flattenProps(pProps) @@ -248,7 +300,7 @@ class CkanResponderV1(responderData: ResponderData) extends Responder(responderD } } Future.sequence(files) map { - case filesList => + filesList => CkanProjectDatasetV1( ckan_title = bPropsMap.getOrElse("Title", ""), ckan_tags = Vector("Kunstgeschichte"), @@ -304,16 +356,25 @@ class CkanResponderV1(responderData: ResponderData) extends Responder(responderD * Get detailed information about the projects * * @param projectNames + * @param featureFactoryConfig the feature factory configuration. * @param userProfile * @return */ - private def getProjectInfos(projectNames: Seq[String], userProfile: UserADM): Future[Seq[(String, ProjectInfoV1)]] = { + private def getProjectInfos(projectNames: Seq[String], + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[Seq[(String, ProjectInfoV1)]] = { Future.sequence { for { pName <- projectNames - projectInfoResponseFuture = (responderManager ? ProjectInfoByShortnameGetRequestV1(pName, Some(userProfile.asUserProfileV1))).mapTo[ProjectInfoResponseV1] + + projectInfoResponseFuture = (responderManager ? ProjectInfoByShortnameGetRequestV1( + shortname = pName, + featureFactoryConfig = featureFactoryConfig, + userProfileV1 = Some(userProfile.asUserProfileV1) + )).mapTo[ProjectInfoResponseV1] + result = projectInfoResponseFuture.map(_.project_info) map { - case pInfo => (pName, pInfo) + pInfo => (pName, pInfo) } } yield result } @@ -350,15 +411,23 @@ class CkanResponderV1(responderData: ResponderData) extends Responder(responderD * Get all information there is about these resources * * @param iris + * @param featureFactoryConfig the feature factory configuration. * @param userProfile * @return */ - private def getResources(iris: Seq[IRI], userProfile: UserADM): Future[Seq[(String, Option[ResourceInfoV1], Option[PropsV1])]] = { + private def getResources(iris: Seq[IRI], + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[Seq[(String, Option[ResourceInfoV1], Option[PropsV1])]] = { Future.sequence { for { iri <- iris - resource = getResource(iri, userProfile) + + resource = getResource( + iri = iri, + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) } yield resource } } @@ -367,12 +436,19 @@ class CkanResponderV1(responderData: ResponderData) extends Responder(responderD * Get all information there is about this one resource * * @param iri + * @param featureFactoryConfig the feature factory configuration. * @param userProfile * @return */ - private def getResource(iri: IRI, userProfile: UserADM): Future[(String, Option[ResourceInfoV1], Option[PropsV1])] = { - - val resourceFullResponseFuture = (responderManager ? ResourceFullGetRequestV1(iri, userProfile)).mapTo[ResourceFullResponseV1] + private def getResource(iri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[(String, Option[ResourceInfoV1], Option[PropsV1])] = { + + val resourceFullResponseFuture = (responderManager ? ResourceFullGetRequestV1( + iri = iri, + featureFactoryConfig = featureFactoryConfig, + userADM = userProfile + )).mapTo[ResourceFullResponseV1] resourceFullResponseFuture map { case ResourceFullResponseV1(resInfo, _, props, _, _) => (iri, resInfo, props) diff --git a/webapi/src/main/scala/org/knora/webapi/responders/v1/OntologyResponderV1.scala b/webapi/src/main/scala/org/knora/webapi/responders/v1/OntologyResponderV1.scala index 0c69a18c9d..6cfb7fcbc7 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/v1/OntologyResponderV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/v1/OntologyResponderV1.scala @@ -22,6 +22,7 @@ package org.knora.webapi.responders.v1 import akka.pattern._ import org.knora.webapi._ import org.knora.webapi.exceptions.{InconsistentTriplestoreDataException, NotFoundException} +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.OntologyConstants import org.knora.webapi.messages.admin.responder.projectsmessages.{ProjectADM, ProjectsGetRequestADM, ProjectsGetResponseADM} @@ -51,14 +52,14 @@ class OntologyResponderV1(responderData: ResponderData) extends Responder(respon * Receives a message extending [[OntologyResponderRequestV1]], and returns an appropriate response message. */ def receive(msg: OntologyResponderRequestV1) = msg match { - case LoadOntologiesRequest(userProfile) => loadOntologies(userProfile) + case LoadOntologiesRequestV1(featureFactoryConfig, userProfile) => loadOntologies(featureFactoryConfig, userProfile) case EntityInfoGetRequestV1(resourceIris, propertyIris, userProfile) => getEntityInfoResponseV1(resourceIris, propertyIris, userProfile) case ResourceTypeGetRequestV1(resourceTypeIri, userProfile) => getResourceTypeResponseV1(resourceTypeIri, userProfile) case checkSubClassRequest: CheckSubClassRequestV1 => checkSubClass(checkSubClassRequest) case subClassesGetRequest: SubClassesGetRequestV1 => getSubClasses(subClassesGetRequest) - case NamedGraphsGetRequestV1(projectIris, userProfile) => getNamedGraphs(projectIris, userProfile) - case ResourceTypesForNamedGraphGetRequestV1(namedGraphIri, userProfile) => getResourceTypesForNamedGraph(namedGraphIri, userProfile) - case PropertyTypesForNamedGraphGetRequestV1(namedGraphIri, userProfile) => getPropertyTypesForNamedGraph(namedGraphIri, userProfile) + case NamedGraphsGetRequestV1(projectIris, featureFactoryConfig, userProfile) => getNamedGraphs(projectIris, featureFactoryConfig, userProfile) + case ResourceTypesForNamedGraphGetRequestV1(namedGraphIri, featureFactoryConfig, userProfile) => getResourceTypesForNamedGraph(namedGraphIri, featureFactoryConfig, userProfile) + case PropertyTypesForNamedGraphGetRequestV1(namedGraphIri, featureFactoryConfig, userProfile) => getPropertyTypesForNamedGraph(namedGraphIri, featureFactoryConfig, userProfile) case PropertyTypesForResourceTypeGetRequestV1(restypeId, userProfile) => getPropertyTypesForResourceType(restypeId, userProfile) case StandoffEntityInfoGetRequestV1(standoffClassIris, standoffPropertyIris, userProfile) => getStandoffEntityInfoResponseV1(standoffClassIris, standoffPropertyIris, userProfile) case StandoffClassesWithDataTypeGetRequestV1(userProfile) => getStandoffStandoffClassesWithDataTypeV1(userProfile) @@ -70,15 +71,19 @@ class OntologyResponderV1(responderData: ResponderData) extends Responder(respon /** * Loads and caches all ontology information. * - * @param userProfile the profile of the user making the request. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. * @return a [[LoadOntologiesResponse]]. */ - private def loadOntologies(userProfile: UserADM): Future[LoadOntologiesResponse] = { + private def loadOntologies(featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[LoadOntologiesResponse] = { for { // forward the request to the v2 ontologies responder - _: SuccessResponseV2 <- (responderManager ? LoadOntologiesRequestV2(userProfile)).mapTo[SuccessResponseV2] - + _: SuccessResponseV2 <- (responderManager ? LoadOntologiesRequestV2( + featureFactoryConfig = featureFactoryConfig, + requestingUser = userProfile + )).mapTo[SuccessResponseV2] } yield LoadOntologiesResponse() } @@ -251,15 +256,23 @@ class OntologyResponderV1(responderData: ResponderData) extends Responder(respon } /** - * Returns all the existing named graphs as a [[NamedGraphsResponseV1]]. + * Returns information about ontology named graphs as a [[NamedGraphsResponseV1]]. * - * @param userProfile the profile of the user making the request. + * @param projectIris the IRIs of the projects whose named graphs should be returned. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. * @return a [[NamedGraphsResponseV1]]. */ - private def getNamedGraphs(projectIris: Set[IRI] = Set.empty[IRI], userProfile: UserADM): Future[NamedGraphsResponseV1] = { + private def getNamedGraphs(projectIris: Set[IRI] = Set.empty[IRI], + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[NamedGraphsResponseV1] = { for { - projectsResponse <- (responderManager ? ProjectsGetRequestADM(userProfile)).mapTo[ProjectsGetResponseADM] + projectsResponse <- (responderManager ? ProjectsGetRequestADM( + featureFactoryConfig = featureFactoryConfig, + requestingUser = userProfile + )).mapTo[ProjectsGetResponseADM] + readOntologyMetadataV2 <- (responderManager ? OntologyMetadataGetByProjectRequestV2(projectIris = projectIris.map(_.toSmartIri), requestingUser = userProfile)).mapTo[ReadOntologyMetadataV2] projectsMap: Map[IRI, ProjectADM] = projectsResponse.projects.map { @@ -316,11 +329,14 @@ class OntologyResponderV1(responderData: ResponderData) extends Responder(respon /** * Gets all the resource classes and their properties for a named graph. * - * @param namedGraphIriOption the IRI of the named graph or None if all the named graphs should be queried. - * @param userProfile the profile of the user making the request. + * @param namedGraphIriOption the IRI of the named graph or None if all the named graphs should be queried. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. * @return [[ResourceTypesForNamedGraphResponseV1]]. */ - private def getResourceTypesForNamedGraph(namedGraphIriOption: Option[IRI], userProfile: UserADM): Future[ResourceTypesForNamedGraphResponseV1] = { + private def getResourceTypesForNamedGraph(namedGraphIriOption: Option[IRI], + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[ResourceTypesForNamedGraphResponseV1] = { // get the resource types for a named graph def getResourceTypes(namedGraphIri: IRI): Future[Seq[ResourceTypeV1]] = { @@ -331,7 +347,7 @@ class OntologyResponderV1(responderData: ResponderData) extends Responder(respon // get resinfo for each resource class in namedGraphEntityInfo resInfosForNamedGraphFuture: Set[Future[(String, ResourceTypeResponseV1)]] = namedGraphEntityInfo.resourceClasses.map { - (resClassIri) => + resClassIri => for { resInfo <- getResourceTypeResponseV1(resClassIri, userProfile) } yield (resClassIri, resInfo) @@ -343,7 +359,7 @@ class OntologyResponderV1(responderData: ResponderData) extends Responder(respon case (resClassIri, resInfo) => val properties = resInfo.restype_info.properties.map { - (prop) => + prop => PropertyTypeV1( id = prop.id, label = prop.label.getOrElse(throw InconsistentTriplestoreDataException(s"No label given for ${prop.id}")) @@ -369,7 +385,11 @@ class OntologyResponderV1(responderData: ResponderData) extends Responder(respon case None => // map over all named graphs and collect the resource types for { - projectNamedGraphsResponse: NamedGraphsResponseV1 <- getNamedGraphs(userProfile = userProfile) + projectNamedGraphsResponse: NamedGraphsResponseV1 <- getNamedGraphs( + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) + projectNamedGraphIris: Seq[IRI] = projectNamedGraphsResponse.vocabularies.map(_.uri) resourceTypesPerProject: Seq[Future[Seq[ResourceTypeV1]]] = projectNamedGraphIris.map(iri => getResourceTypes(iri)) resourceTypes: Seq[Seq[ResourceTypeV1]] <- Future.sequence(resourceTypesPerProject) @@ -381,11 +401,14 @@ class OntologyResponderV1(responderData: ResponderData) extends Responder(respon /** * Gets the property types defined in the given named graph. If there is no named graph defined, get property types for all existing named graphs. * - * @param namedGraphIriOption the IRI of the named graph or None if all the named graphs should be queried. - * @param userProfile the profile of the user making the request. + * @param namedGraphIriOption the IRI of the named graph or None if all the named graphs should be queried. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. * @return a [[PropertyTypesForNamedGraphResponseV1]]. */ - private def getPropertyTypesForNamedGraph(namedGraphIriOption: Option[IRI], userProfile: UserADM): Future[PropertyTypesForNamedGraphResponseV1] = { + private def getPropertyTypesForNamedGraph(namedGraphIriOption: Option[IRI], + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[PropertyTypesForNamedGraphResponseV1] = { def getPropertiesForNamedGraph(namedGraphIri: IRI, userProfile: UserADM): Future[Seq[PropertyDefinitionInNamedGraphV1]] = { for { @@ -442,7 +465,11 @@ class OntologyResponderV1(responderData: ResponderData) extends Responder(respon case None => // get the property types for all named graphs (collect them by mapping over all named graphs) for { - projectNamedGraphsResponse: NamedGraphsResponseV1 <- getNamedGraphs(userProfile = userProfile) + projectNamedGraphsResponse: NamedGraphsResponseV1 <- getNamedGraphs( + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) + projectNamedGraphIris: Seq[IRI] = projectNamedGraphsResponse.vocabularies.map(_.uri) propertyTypesPerProject: Seq[Future[Seq[PropertyDefinitionInNamedGraphV1]]] = projectNamedGraphIris.map(iri => getPropertiesForNamedGraph(iri, userProfile)) propertyTypes: Seq[Seq[PropertyDefinitionInNamedGraphV1]] <- Future.sequence(propertyTypesPerProject) diff --git a/webapi/src/main/scala/org/knora/webapi/responders/v1/ProjectsResponderV1.scala b/webapi/src/main/scala/org/knora/webapi/responders/v1/ProjectsResponderV1.scala index 628087a5a0..cae0aedd18 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/v1/ProjectsResponderV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/v1/ProjectsResponderV1.scala @@ -23,6 +23,7 @@ import akka.http.scaladsl.util.FastFuture import akka.pattern._ import org.knora.webapi._ import org.knora.webapi.exceptions.{InconsistentTriplestoreDataException, NotFoundException} +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.OntologyConstants import org.knora.webapi.messages.admin.responder.usersmessages.{UserADM, UserGetRequestADM, UserIdentifierADM, UserResponseADM} import org.knora.webapi.messages.store.triplestoremessages._ @@ -47,27 +48,32 @@ class ProjectsResponderV1(responderData: ResponderData) extends Responder(respon * Receives a message extending [[ProjectsResponderRequestV1]], and returns an appropriate response message. */ def receive(msg: ProjectsResponderRequestV1) = msg match { - case ProjectsGetRequestV1(userProfile) => projectsGetRequestV1(userProfile) - case ProjectsGetV1(userProfile) => projectsGetV1(userProfile) - case ProjectInfoByIRIGetRequestV1(iri, userProfile) => projectInfoByIRIGetRequestV1(iri, userProfile) - case ProjectInfoByIRIGetV1(iri, userProfile) => projectInfoByIRIGetV1(iri, userProfile) - case ProjectInfoByShortnameGetRequestV1(shortname, userProfile) => projectInfoByShortnameGetRequestV1(shortname, userProfile) + case ProjectsGetRequestV1(featureFactoryConfig, userProfile) => projectsGetRequestV1(featureFactoryConfig, userProfile) + case ProjectsGetV1(featureFactoryConfig, userProfile) => projectsGetV1(featureFactoryConfig, userProfile) + case ProjectInfoByIRIGetRequestV1(iri, featureFactoryConfig, userProfile) => projectInfoByIRIGetRequestV1(iri, featureFactoryConfig, userProfile) + case ProjectInfoByIRIGetV1(iri, featureFactoryConfig, userProfile) => projectInfoByIRIGetV1(iri, featureFactoryConfig, userProfile) + case ProjectInfoByShortnameGetRequestV1(shortname, featureFactoryConfig, userProfile) => projectInfoByShortnameGetRequestV1(shortname, featureFactoryConfig, userProfile) case other => handleUnexpectedMessage(other, log, this.getClass.getName) } /** * Gets all the projects and returns them as a [[ProjectsResponseV1]]. * - * @param userProfile the profile of the user that is making the request. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user that is making the request. * @return all the projects as a [[ProjectsResponseV1]]. * @throws NotFoundException if no projects are found. */ - private def projectsGetRequestV1(userProfile: Option[UserProfileV1]): Future[ProjectsResponseV1] = { + private def projectsGetRequestV1(featureFactoryConfig: FeatureFactoryConfig, + userProfile: Option[UserProfileV1]): Future[ProjectsResponseV1] = { //log.debug("projectsGetRequestV1") for { - projects <- projectsGetV1(userProfile) + projects <- projectsGetV1( + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) result = if (projects.nonEmpty) { ProjectsResponseV1( @@ -83,10 +89,12 @@ class ProjectsResponderV1(responderData: ResponderData) extends Responder(respon /** * Gets all the projects and returns them as a sequence containing [[ProjectInfoV1]]. * - * @param userProfile the profile of the user that is making the request. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user that is making the request. * @return all the projects as a sequence containing [[ProjectInfoV1]]. */ - private def projectsGetV1(userProfile: Option[UserProfileV1]): Future[Seq[ProjectInfoV1]] = { + private def projectsGetV1(featureFactoryConfig: FeatureFactoryConfig, + userProfile: Option[UserProfileV1]): Future[Seq[ProjectInfoV1]] = { for { sparqlQueryString <- Future(org.knora.webapi.messages.twirl.queries.sparql.v1.txt.getProjects( @@ -106,7 +114,10 @@ class ProjectsResponderV1(responderData: ResponderData) extends Responder(respon } //_ = log.debug(s"getProjectsResponseV1 - projectsWithProperties: $projectsWithProperties") - ontologiesForProjects <- getOntologiesForProjects(userProfile = userProfile) + ontologiesForProjects <- getOntologiesForProjects( + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) projects = projectsWithProperties.map { case (projectIri: String, propsMap: Map[String, Seq[String]]) => @@ -148,7 +159,9 @@ class ProjectsResponderV1(responderData: ResponderData) extends Responder(respon * @param userProfile the requesting user. * @return a map of project IRIs to sequences of ontology IRIs. */ - private def getOntologiesForProjects(projectIris: Set[IRI] = Set.empty[IRI], userProfile: Option[UserProfileV1]): Future[Map[IRI, Seq[IRI]]] = { + private def getOntologiesForProjects(projectIris: Set[IRI] = Set.empty[IRI], + featureFactoryConfig: FeatureFactoryConfig, + userProfile: Option[UserProfileV1]): Future[Map[IRI, Seq[IRI]]] = { for { // Get a UserADM for the UserProfileV1, because we need it to send a message to OntologyResponderV1. @@ -158,6 +171,7 @@ class ProjectsResponderV1(responderData: ResponderData) extends Responder(respon case Some(user_iri) => (responderManager ? UserGetRequestADM( identifier = UserIdentifierADM(maybeIri = Some(user_iri)), + featureFactoryConfig = featureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser )).mapTo[UserResponseADM].map(_.user) @@ -169,7 +183,11 @@ class ProjectsResponderV1(responderData: ResponderData) extends Responder(respon // Get the ontologies per project. - namedGraphsResponse <- (responderManager ? NamedGraphsGetRequestV1(projectIris, userADM)).mapTo[NamedGraphsResponseV1] + namedGraphsResponse <- (responderManager ? NamedGraphsGetRequestV1( + projectIris = projectIris, + featureFactoryConfig = featureFactoryConfig, + userADM = userADM + )).mapTo[NamedGraphsResponseV1] } yield namedGraphsResponse.vocabularies.map { namedGraph: NamedGraphV1 => @@ -183,17 +201,25 @@ class ProjectsResponderV1(responderData: ResponderData) extends Responder(respon /** * Gets the project with the given project IRI and returns the information as a [[ProjectInfoResponseV1]]. * - * @param projectIri the IRI of the project requested. - * @param userProfile the profile of user that is making the request. + * @param projectIri the IRI of the project requested. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of user that is making the request. * @return information about the project as a [[ProjectInfoResponseV1]]. * @throws NotFoundException when no project for the given IRI can be found */ - private def projectInfoByIRIGetRequestV1(projectIri: IRI, userProfile: Option[UserProfileV1] = None): Future[ProjectInfoResponseV1] = { + private def projectInfoByIRIGetRequestV1(projectIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: Option[UserProfileV1] = None): Future[ProjectInfoResponseV1] = { //log.debug("projectInfoByIRIGetRequestV1 - projectIRI: {}", projectIRI) for { - maybeProjectInfo: Option[ProjectInfoV1] <- projectInfoByIRIGetV1(projectIri, userProfile) + maybeProjectInfo: Option[ProjectInfoV1] <- projectInfoByIRIGetV1( + projectIri = projectIri, + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) + projectInfo = maybeProjectInfo match { case Some(pi) => pi case None => throw NotFoundException(s"Project '$projectIri' not found") @@ -206,11 +232,14 @@ class ProjectsResponderV1(responderData: ResponderData) extends Responder(respon /** * Gets the project with the given project IRI and returns the information as a [[ProjectInfoV1]]. * - * @param projectIri the IRI of the project requested. - * @param userProfile the profile of user that is making the request. + * @param projectIri the IRI of the project requested. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of user that is making the request. * @return information about the project as a [[ProjectInfoV1]]. */ - private def projectInfoByIRIGetV1(projectIri: IRI, userProfile: Option[UserProfileV1] = None): Future[Option[ProjectInfoV1]] = { + private def projectInfoByIRIGetV1(projectIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: Option[UserProfileV1] = None): Future[Option[ProjectInfoV1]] = { //log.debug("projectInfoByIRIGetV1 - projectIRI: {}", projectIri) @@ -221,7 +250,13 @@ class ProjectsResponderV1(responderData: ResponderData) extends Responder(respon ).toString()) projectResponse <- (storeManager ? SparqlSelectRequest(sparqlQuery)).mapTo[SparqlSelectResponse] - ontologiesForProjects: Map[IRI, Seq[IRI]] <- getOntologiesForProjects(projectIris = Set(projectIri), userProfile = userProfile) + + ontologiesForProjects: Map[IRI, Seq[IRI]] <- getOntologiesForProjects( + projectIris = Set(projectIri), + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) + projectOntologies = ontologiesForProjects.getOrElse(projectIri, Seq.empty[IRI]) projectInfo = if (projectResponse.results.bindings.nonEmpty) { @@ -243,12 +278,15 @@ class ProjectsResponderV1(responderData: ResponderData) extends Responder(respon /** * Gets the project with the given shortname and returns the information as a [[ProjectInfoResponseV1]]. * - * @param shortName the shortname of the project requested. - * @param userProfile the profile of user that is making the request. + * @param shortName the shortname of the project requested. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of user that is making the request. * @return information about the project as a [[ProjectInfoResponseV1]]. * @throws NotFoundException in the case that no project for the given shortname can be found. */ - private def projectInfoByShortnameGetRequestV1(shortName: String, userProfile: Option[UserProfileV1]): Future[ProjectInfoResponseV1] = { + private def projectInfoByShortnameGetRequestV1(shortName: String, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: Option[UserProfileV1]): Future[ProjectInfoResponseV1] = { //log.debug("projectInfoByShortnameGetRequestV1 - shortName: {}", shortName) @@ -270,7 +308,12 @@ class ProjectsResponderV1(responderData: ResponderData) extends Responder(respon throw NotFoundException(s"Project '$shortName' not found") } - ontologiesForProjects: Map[IRI, Seq[IRI]] <- getOntologiesForProjects(projectIris = Set(projectIri), userProfile = userProfile) + ontologiesForProjects: Map[IRI, Seq[IRI]] <- getOntologiesForProjects( + projectIris = Set(projectIri), + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) + projectOntologies = ontologiesForProjects(projectIri) projectInfo = createProjectInfoV1( diff --git a/webapi/src/main/scala/org/knora/webapi/responders/v1/ResourcesResponderV1.scala b/webapi/src/main/scala/org/knora/webapi/responders/v1/ResourcesResponderV1.scala index 33e1b1e960..37f4433b3e 100755 --- a/webapi/src/main/scala/org/knora/webapi/responders/v1/ResourcesResponderV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/v1/ResourcesResponderV1.scala @@ -26,6 +26,7 @@ import akka.http.scaladsl.util.FastFuture import akka.pattern._ import org.knora.webapi._ import org.knora.webapi.exceptions._ +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.admin.responder.permissionsmessages.{DefaultObjectAccessPermissionsStringForPropertyGetADM, DefaultObjectAccessPermissionsStringForResourceClassGetADM, DefaultObjectAccessPermissionsStringResponseADM, ResourceCreateOperation} import org.knora.webapi.messages.admin.responder.projectsmessages.{ProjectADM, ProjectGetRequestADM, ProjectGetResponseADM, ProjectIdentifierADM} @@ -64,18 +65,18 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo * Receives a message extending [[ResourcesResponderRequestV1]], and returns an appropriate response message. */ def receive(msg: ResourcesResponderRequestV1) = msg match { - case ResourceInfoGetRequestV1(resourceIri, userProfile) => getResourceInfoResponseV1(resourceIri, userProfile) - case ResourceFullGetRequestV1(resourceIri, userProfile, getIncoming) => getFullResponseV1(resourceIri, userProfile, getIncoming) - case ResourceContextGetRequestV1(resourceIri, userProfile, resinfo) => getContextResponseV1(resourceIri, userProfile, resinfo) - case ResourceRightsGetRequestV1(resourceIri, userProfile) => getRightsResponseV1(resourceIri, userProfile) + case ResourceInfoGetRequestV1(resourceIri, featureFactoryConfig, userProfile) => getResourceInfoResponseV1(resourceIri, featureFactoryConfig, userProfile) + case ResourceFullGetRequestV1(resourceIri, featureFactoryConfig, userProfile, getIncoming) => getFullResponseV1(resourceIri, featureFactoryConfig, userProfile, getIncoming) + case ResourceContextGetRequestV1(resourceIri, featureFactoryConfig, userProfile, resinfo) => getContextResponseV1(resourceIri, featureFactoryConfig, userProfile, resinfo) + case ResourceRightsGetRequestV1(resourceIri, featureFactoryConfig, userProfile) => getRightsResponseV1(resourceIri, featureFactoryConfig, userProfile) case graphDataGetRequest: GraphDataGetRequestV1 => getGraphDataResponseV1(graphDataGetRequest) case ResourceSearchGetRequestV1(searchString: String, resourceIri: Option[IRI], numberOfProps: Int, limitOfResults: Int, userProfile: UserADM) => getResourceSearchResponseV1(searchString, resourceIri, numberOfProps, limitOfResults, userProfile) - case ResourceCreateRequestV1(resourceTypeIri, label, values, file, projectIri, userProfile, apiRequestID) => createNewResource(resourceTypeIri, label, values, file, projectIri, userProfile, apiRequestID) - case MultipleResourceCreateRequestV1(resourcesToCreate, projectIri, userProfile, apiRequestID) => createMultipleNewResources(resourcesToCreate, projectIri, userProfile, apiRequestID) - case ResourceCheckClassRequestV1(resourceIri: IRI, owlClass: IRI, userProfile: UserADM) => checkResourceClass(resourceIri, owlClass, userProfile) - case PropertiesGetRequestV1(resourceIri: IRI, userProfile: UserADM) => getPropertiesV1(resourceIri = resourceIri, userProfile = userProfile) + case ResourceCreateRequestV1(resourceTypeIri, label, values, file, projectIri, featureFactoryConfig, userProfile, apiRequestID) => createNewResource(resourceTypeIri, label, values, file, projectIri, featureFactoryConfig, userProfile, apiRequestID) + case MultipleResourceCreateRequestV1(resourcesToCreate, projectIri, featureFactoryConfig, userProfile, apiRequestID) => createMultipleNewResources(resourcesToCreate, projectIri, featureFactoryConfig, userProfile, apiRequestID) + case ResourceCheckClassRequestV1(resourceIri: IRI, owlClass: IRI, featureFactoryConfig, userProfile: UserADM) => checkResourceClass(resourceIri, owlClass, featureFactoryConfig, userProfile) + case PropertiesGetRequestV1(resourceIri: IRI, featureFactoryConfig, userProfile: UserADM) => getPropertiesV1(resourceIri = resourceIri, featureFactoryConfig = featureFactoryConfig, userProfile = userProfile) case resourceDeleteRequest: ResourceDeleteRequestV1 => deleteResourceV1(resourceDeleteRequest) - case ChangeResourceLabelRequestV1(resourceIri, label, userProfile, apiRequestID) => changeResourceLabelV1(resourceIri, label, apiRequestID, userProfile) + case ChangeResourceLabelRequestV1(resourceIri, label, featureFactoryConfig, userProfile, apiRequestID) => changeResourceLabelV1(resourceIri, label, apiRequestID, featureFactoryConfig, userProfile) case UnexpectedMessageRequest() => makeFutureOfUnit case InternalServerExceptionMessageRequest() => makeInternalServerException case other => handleUnexpectedMessage(other, log, this.getClass.getName) @@ -405,10 +406,13 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo * @param userProfile the profile of the user making the request. * @return a [[ResourceInfoResponseV1]] containing a representation of the resource. */ - private def getResourceInfoResponseV1(resourceIri: IRI, userProfile: UserADM): Future[ResourceInfoResponseV1] = { + private def getResourceInfoResponseV1(resourceIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[ResourceInfoResponseV1] = { for { (userPermissions, resInfo) <- getResourceInfoV1( resourceIri = resourceIri, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile, queryOntology = true ) @@ -432,7 +436,10 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo * @param getIncoming if `true` (the default), queries the resource's inconing references. * @return a [[ResourceFullResponseV1]]. */ - private def getFullResponseV1(resourceIri: IRI, userProfile: UserADM, getIncoming: Boolean = true): Future[ResourceFullResponseV1] = { + private def getFullResponseV1(resourceIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM, + getIncoming: Boolean = true): Future[ResourceFullResponseV1] = { val userProfileV1 = userProfile.asUserProfileV1 // Query resource info, resource properties, and incoming references in parallel. @@ -444,6 +451,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo // Get a resource info containing basic information about the resource. Do not query the ontology here, because we will query it below. val resourceInfoFuture = getResourceInfoV1( resourceIri = resourceIri, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile, queryOntology = false ) @@ -503,7 +511,13 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo val rowsForResInfo = rows.filterNot(row => stringFormatter.optionStringToBoolean(row.rowMap.get("isLinkValue"), throw InconsistentTriplestoreDataException(s"Invalid boolean for isLinkValue: ${row.rowMap.get("isLinkValue")}"))) for { - (incomingResPermission, incomingResInfo) <- makeResourceInfoV1(incomingIri, rowsForResInfo, userProfile, queryOntology = false) + (incomingResPermission, incomingResInfo) <- makeResourceInfoV1( + resourceIri = incomingIri, + resInfoResponseRows = rowsForResInfo, + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile, + queryOntology = false + ) // Does the user have permission to see the referring resource? incomingV1s: Vector[IncomingV1] <- incomingResPermission match { @@ -529,6 +543,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo valueProps = linkValueProps, projectShortcode = resInfoWithoutQueryingOntology.project_shortcode, responderManager = responderManager, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) @@ -653,6 +668,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo propertyInfoMap = entityInfoResponse.propertyInfoMap, resourceEntityInfoMap = entityInfoResponse.resourceClassInfoMap, propsAndCardinalities = propsAndCardinalities, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) @@ -738,12 +754,16 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo /** * Returns an instance of [[ResourceContextResponseV1]] describing the context of a resource, in Knora API v1 format. * - * @param resourceIri the IRI of the resource to be queried. - * @param userProfile the profile of the user making the request. - * @param resinfo a flag if resinfo should be retrieved or not. + * @param resourceIri the IRI of the resource to be queried. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. + * @param resinfo a flag if resinfo should be retrieved or not. * @return a [[ResourceContextResponseV1]] describing the context of the resource. */ - private def getContextResponseV1(resourceIri: IRI, userProfile: UserADM, resinfo: Boolean): Future[ResourceContextResponseV1] = { + private def getContextResponseV1(resourceIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM, + resinfo: Boolean): Future[ResourceContextResponseV1] = { val userProfileV1 = userProfile.asUserProfileV1 /** @@ -862,6 +882,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo // Get the resource info even if the user didn't ask for it, so we can check its permissions. (userPermission, resInfoV1) <- getResourceInfoV1( resourceIri = resourceIri, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile, queryOntology = true ) @@ -886,6 +907,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo for { (containingResourcePermissionCode, resInfoV1) <- getResourceInfoV1( resourceIri = containingResourceIri, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile, queryOntology = true ) @@ -997,6 +1019,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo propsV1: Seq[PropertyV1] <- getResourceProperties( resourceIri = regionIri, maybeResourceTypeIri = Some(resClass), + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) @@ -1087,9 +1110,16 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo * @param userProfile the profile of the user making the request. * @return a [[ResourceRightsResponseV1]] describing the permissions on the resource. */ - private def getRightsResponseV1(resourceIri: IRI, userProfile: UserADM): Future[ResourceRightsResponseV1] = { + private def getRightsResponseV1(resourceIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[ResourceRightsResponseV1] = { for { - (userPermission, _) <- getResourceInfoV1(resourceIri, userProfile, queryOntology = false) + (userPermission, _) <- getResourceInfoV1( + resourceIri = resourceIri, + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile, + queryOntology = false + ) // Construct an API response. rightsResponse = ResourceRightsResponseV1(rights = userPermission) @@ -1218,14 +1248,16 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo /** * Create multiple resources and attach the given values to them. * - * @param resourcesToCreate collection of ResourceRequests . - * @param projectIri IRI of the project . - * @param apiRequestID the the ID of the API request. - * @param requestingUser the user making the request. + * @param resourcesToCreate collection of ResourceRequests . + * @param projectIri IRI of the project . + * @param apiRequestID the the ID of the API request. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return a [[MultipleResourceCreateResponseV1]] informing the client about the new resources. */ private def createMultipleNewResources(resourcesToCreate: Seq[OneOfMultipleResourceCreateRequestV1], projectIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID): Future[MultipleResourceCreateResponseV1] = { // Convert all the image metadata in the request to FileValueContentV2 instances, so we @@ -1248,6 +1280,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo projectInfoResponse <- { responderManager ? ProjectGetRequestADM( identifier = ProjectIdentifierADM(maybeIri = Some(projectIri)), + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) }.mapTo[ProjectGetResponseADM] @@ -1398,6 +1431,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo values = resourceCreateRequest.values, convertedFile = resourceCreateRequest.file, clientResourceIDsToResourceClasses = clientResourceIDsToResourceClasses, + featureFactoryConfig = featureFactoryConfig, userProfile = requestingUser ) @@ -1431,6 +1465,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo clientResourceIDsToResourceIris = clientResourceIDsToResourceIris, creationDate = creationDate, fileValues = fileValues, + featureFactoryConfig = featureFactoryConfig, userProfile = requestingUser, apiRequestID = apiRequestID ) @@ -1521,6 +1556,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo * be generated for links to missing resources. * @param convertedFile an already converted file to be attached to the resource. * @param clientResourceIDsToResourceClasses for each client resource ID, the IRI of the resource's class. Used only if `linkTargetsAlreadyExist` is false. + * @param featureFactoryConfig the feature factory configuration. * @param userProfile the profile of the user making the request. * @return a tuple (IRI, Vector[CreateValueV1WithComment]) containing the IRI of the resource and a collection of holders of [[UpdateValueV1]] and comment. */ @@ -1534,6 +1570,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo errorTemplateFun = { key => s"Resource $key is the target of a link, but was not provided in the request" }, errorFun = { errorMsg => throw BadRequestException(errorMsg) } ), + featureFactoryConfig: FeatureFactoryConfig, userProfile: UserADM): Future[Option[(IRI, Vector[CreateValueV1WithComment])]] = { for { // Check that each submitted value is consistent with the knora-base:objectClassConstraint of the property that is supposed to @@ -1574,6 +1611,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo checkTargetClassResponse <- checkResourceClass( resourceIri = linkUpdate.targetResourceIri, owlClass = propertyObjectClassConstraint, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ).mapTo[ResourceCheckClassResponseV1] @@ -1652,6 +1690,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo * @param clientResourceIDsToResourceIris a map of client resource IDs (which may appear in standoff link tags * in values passed to this method) to the IRIs that will be used for * those resources. + * @param featureFactoryConfig the feature factory configuration. * @param userProfile the profile of the user making the request. * @param apiRequestID the the ID of the API request. * @return a [[GenerateSparqlToCreateMultipleValuesResponseV1]] returns response of generation of SPARQL for multiple values. @@ -1664,6 +1703,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo fileValues: Option[(IRI, Vector[CreateValueV1WithComment])], clientResourceIDsToResourceIris: Map[String, IRI], creationDate: Instant, + featureFactoryConfig: FeatureFactoryConfig, userProfile: UserADM, apiRequestID: UUID): Future[GenerateSparqlToCreateMultipleValuesResponseV1] = { for { @@ -1676,6 +1716,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo values = values ++ fileValues, clientResourceIDsToResourceIris = clientResourceIDsToResourceIris, creationDate = creationDate, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile, apiRequestID = apiRequestID )) @@ -1712,6 +1753,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo * @param createNewResourceSparql Sparql query to create the resource . * @param generateSparqlForValuesResponse Sparql statement for creation of values of resource. * @param projectADM the project in which the resource was created. + * @param featureFactoryConfig the feature factory configuration. * @param userProfile the profile of the user making the request. * @return a [[ResourceCreateResponseV1]] containing information about the created resource . */ @@ -1720,6 +1762,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo createNewResourceSparql: String, generateSparqlForValuesResponse: GenerateSparqlToCreateMultipleValuesResponseV1, projectADM: ProjectADM, + featureFactoryConfig: FeatureFactoryConfig, userProfile: UserADM): Future[ResourceCreateResponseV1] = { // Verify that the resource was created. for { @@ -1739,6 +1782,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo verifyCreateValuesRequest = VerifyMultipleValueCreationRequestV1( resourceIri = resourceIri, unverifiedValues = generateSparqlForValuesResponse.unverifiedValues, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) @@ -1767,16 +1811,17 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo /** * Does pre-update checks, creates a resource, and verifies that it was created. * - * @param resourceClassIri the IRI of the resource class. - * @param projectADM the project in which the resource should be created. - * @param label the `rdfs:label` of the resource to be created. - * @param resourceIri the IRI of the resource to be created. - * @param values the values to be attached to the resource. - * @param file a file that has been uploaded to Sipi's temporary storage and should be attached to the resource. - * @param creatorIri the creator of the resource to be created. - * @param namedGraph the named graph the resource belongs to. - * @param requestingUser the user making the request. - * @param apiRequestID the request ID used for locking the resource. + * @param resourceClassIri the IRI of the resource class. + * @param projectADM the project in which the resource should be created. + * @param label the `rdfs:label` of the resource to be created. + * @param resourceIri the IRI of the resource to be created. + * @param values the values to be attached to the resource. + * @param file a file that has been uploaded to Sipi's temporary storage and should be attached to the resource. + * @param creatorIri the creator of the resource to be created. + * @param namedGraph the named graph the resource belongs to. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. + * @param apiRequestID the request ID used for locking the resource. * @return a [[ResourceCreateResponseV1]] containing information about the created resource. */ def createResourceAndCheck(resourceClassIri: IRI, @@ -1787,6 +1832,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo file: Option[FileValueV1], creatorIri: IRI, namedGraph: IRI, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM, apiRequestID: UUID): Future[ResourceCreateResponseV1] = { val fileValueContent: Option[FileValueContentV2] = file.map(_.toFileValueContentV2) @@ -1846,6 +1892,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo propertyInfoMap = propertyInfoMap, values = values, convertedFile = file, + featureFactoryConfig = featureFactoryConfig, userProfile = requestingUser ) @@ -1863,6 +1910,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo fileValues = fileValues, clientResourceIDsToResourceIris = Map.empty[String, IRI], creationDate = creationDate, + featureFactoryConfig = featureFactoryConfig, userProfile = requestingUser, apiRequestID = apiRequestID ) @@ -1894,6 +1942,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo createNewResourceSparql = createNewResourceSparql, generateSparqlForValuesResponse = generateSparqlForValuesResponse, projectADM = projectADM, + featureFactoryConfig = featureFactoryConfig, userProfile = requestingUser ) } yield apiResponse @@ -1908,12 +1957,13 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo /** * Creates a new resource and attaches the given values to it. * - * @param resourceClassIri the resource type of the resource to be created. - * @param values the values to be attached to the resource. - * @param file a file that has been uploaded to Sipi's temporary storage and should be attached to the resource. - * @param projectIri the project the resource belongs to. - * @param userProfile the user that is creating the resource - * @param apiRequestID the ID of this API request. + * @param resourceClassIri the resource type of the resource to be created. + * @param values the values to be attached to the resource. + * @param file a file that has been uploaded to Sipi's temporary storage and should be attached to the resource. + * @param projectIri the project the resource belongs to. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the user that is creating the resource + * @param apiRequestID the ID of this API request. * @return a [[ResourceCreateResponseV1]] informing the client about the new resource. */ private def createNewResource(resourceClassIri: IRI, @@ -1921,6 +1971,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo values: Map[IRI, Seq[CreateValueV1WithComment]], file: Option[FileValueV1] = None, projectIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, userProfile: UserADM, apiRequestID: UUID): Future[ResourceCreateResponseV1] = { for { @@ -1942,6 +1993,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo projectResponse <- { responderManager ? ProjectGetRequestADM( identifier = ProjectIdentifierADM(maybeIri = Some(projectIri)), + featureFactoryConfig = featureFactoryConfig, requestingUser = userProfile ) }.mapTo[ProjectGetResponseADM] @@ -1986,6 +2038,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo file = file, creatorIri = userIri, namedGraph = namedGraph, + featureFactoryConfig = featureFactoryConfig, requestingUser = userProfile, apiRequestID = apiRequestID ) @@ -2004,7 +2057,12 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo def makeTaskFuture(userIri: IRI): Future[ResourceDeleteResponseV1] = { for { // Check that the user has permission to delete the resource. - (permissionCode, resourceInfo) <- getResourceInfoV1(resourceIri = resourceDeleteRequest.resourceIri, userProfile = resourceDeleteRequest.userADM, queryOntology = false) + (permissionCode, resourceInfo) <- getResourceInfoV1( + resourceIri = resourceDeleteRequest.resourceIri, + featureFactoryConfig = resourceDeleteRequest.featureFactoryConfig, + userProfile = resourceDeleteRequest.userADM, + queryOntology = false + ) _ = if (!PermissionUtilADM.impliesPermissionCodeV1(userHasPermissionCode = permissionCode, userNeedsPermission = OntologyConstants.KnoraBase.DeletePermission)) { throw ForbiddenException(s"User $userIri does not have permission to mark resource ${resourceDeleteRequest.resourceIri} as deleted") @@ -2012,8 +2070,9 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo projectInfoResponse <- { responderManager ? ProjectInfoByIRIGetRequestV1( - resourceInfo.project_id, - None + iri = resourceInfo.project_id, + featureFactoryConfig = resourceDeleteRequest.featureFactoryConfig, + userProfileV1 = None ) }.mapTo[ProjectInfoResponseV1] @@ -2069,16 +2128,25 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo /** * Checks whether a resource belongs to a certain OWL class or to a subclass of that class. * - * @param resourceIri the IRI of the resource to be checked. - * @param owlClass the IRI of the OWL class to compare the resource's class to. - * @param userProfile the profile of the user making the request. + * @param resourceIri the IRI of the resource to be checked. + * @param owlClass the IRI of the OWL class to compare the resource's class to. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. * @return a [[ResourceCheckClassResponseV1]]. */ - private def checkResourceClass(resourceIri: IRI, owlClass: IRI, userProfile: UserADM): Future[ResourceCheckClassResponseV1] = { + private def checkResourceClass(resourceIri: IRI, + owlClass: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[ResourceCheckClassResponseV1] = { for { // Check that the user has permission to view the resource. - (permissionCode, resourceInfo) <- getResourceInfoV1(resourceIri = resourceIri, userProfile = userProfile, queryOntology = false) + (permissionCode, resourceInfo) <- getResourceInfoV1( + resourceIri = resourceIri, + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile, + queryOntology = false + ) _ = if (!PermissionUtilADM.impliesPermissionCodeV1(userHasPermissionCode = permissionCode, userNeedsPermission = OntologyConstants.KnoraBase.RestrictedViewPermission)) { throw ForbiddenException(s"User ${userProfile.id} does not have permission to view resource $resourceIri") @@ -2104,13 +2172,22 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo * @param userProfile the profile of the user making the request. * @return a [[ChangeResourceLabelResponseV1]]. */ - private def changeResourceLabelV1(resourceIri: IRI, label: String, apiRequestID: UUID, userProfile: UserADM): Future[ChangeResourceLabelResponseV1] = { + private def changeResourceLabelV1(resourceIri: IRI, + label: String, + apiRequestID: UUID, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[ChangeResourceLabelResponseV1] = { def makeTaskFuture(userIri: IRI): Future[ChangeResourceLabelResponseV1] = { for { // get the resource's permissions - (permissionCode, resourceInfo) <- getResourceInfoV1(resourceIri = resourceIri, userProfile = userProfile, queryOntology = false) + (permissionCode, resourceInfo) <- getResourceInfoV1( + resourceIri = resourceIri, + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile, + queryOntology = false + ) // check if the given user may change its label _ = if (!PermissionUtilADM.impliesPermissionCodeV1(userHasPermissionCode = permissionCode, userNeedsPermission = OntologyConstants.KnoraBase.ModifyPermission)) { @@ -2119,8 +2196,9 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo projectInfoResponse <- { responderManager ? ProjectInfoByIRIGetRequestV1( - resourceInfo.project_id, - None + iri = resourceInfo.project_id, + featureFactoryConfig = featureFactoryConfig, + userProfileV1 = None ) }.mapTo[ProjectInfoResponseV1] @@ -2188,14 +2266,18 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo /** * Returns a [[ResourceInfoV1]] describing a resource. * - * @param resourceIri the IRI of the resource to be queried. - * @param userProfile the user that is making the request. - * @param queryOntology if `true`, the ontology will be queried for information about the resource type, and the [[ResourceInfoV1]] - * will include `restype_label`, `restype_description`, and `restype_iconsrc`. Otherwise, those member variables - * will be empty. + * @param resourceIri the IRI of the resource to be queried. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the user that is making the request. + * @param queryOntology if `true`, the ontology will be queried for information about the resource type, and the [[ResourceInfoV1]] + * will include `restype_label`, `restype_description`, and `restype_iconsrc`. Otherwise, those member variables + * will be empty. * @return a tuple (permission, [[ResourceInfoV1]]) describing the resource. */ - private def getResourceInfoV1(resourceIri: IRI, userProfile: UserADM, queryOntology: Boolean): Future[(Option[Int], ResourceInfoV1)] = { + private def getResourceInfoV1(resourceIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM, + queryOntology: Boolean): Future[(Option[Int], ResourceInfoV1)] = { for { sparqlQuery <- Future(org.knora.webapi.messages.twirl.queries.sparql.v1.txt.getResourceInfo( triplestore = settings.triplestoreType, @@ -2203,7 +2285,14 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo ).toString()) resInfoResponse <- (storeManager ? SparqlSelectRequest(sparqlQuery)).mapTo[SparqlSelectResponse] resInfoResponseRows = resInfoResponse.results.bindings - resInfo: (Option[Int], ResourceInfoV1) <- makeResourceInfoV1(resourceIri, resInfoResponseRows, userProfile, queryOntology) + + resInfo: (Option[Int], ResourceInfoV1) <- makeResourceInfoV1( + resourceIri = resourceIri, + resInfoResponseRows = resInfoResponseRows, + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile, + queryOntology = queryOntology + ) } yield resInfo } @@ -2211,11 +2300,14 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo * * Queries the properties for the given resource. * - * @param resourceIri the IRI of the given resource. - * @param userProfile the profile of the user making the request. + * @param resourceIri the IRI of the given resource. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. * @return a [[PropertiesGetResponseV1]] representing the properties of the given resource. */ - private def getPropertiesV1(resourceIri: IRI, userProfile: UserADM): Future[PropertiesGetResponseV1] = { + private def getPropertiesV1(resourceIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[PropertiesGetResponseV1] = { for { // get resource class of the specified resource @@ -2228,7 +2320,12 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo resclassQueryResponse: SparqlSelectResponse <- (storeManager ? SparqlSelectRequest(resclassSparqlQuery)).mapTo[SparqlSelectResponse] resclass = resclassQueryResponse.results.bindings.headOption.getOrElse(throw InconsistentTriplestoreDataException(s"No resource class given for $resourceIri")) - properties: Seq[PropertyV1] <- getResourceProperties(resourceIri = resourceIri, maybeResourceTypeIri = Some(resclass.rowMap("resourceClass")), userProfile = userProfile) + properties: Seq[PropertyV1] <- getResourceProperties( + resourceIri = resourceIri, + maybeResourceTypeIri = Some(resclass.rowMap("resourceClass")), + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) propertiesGetV1: Seq[PropertyGetV1] = properties.map { prop => convertPropertyV1toPropertyGetV1(prop) @@ -2246,10 +2343,14 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo * @param maybeResourceTypeIri an optional IRI representing the resource's class. If provided, an additional query will be done * to get ontology-based information, such as labels and cardinalities, which will be included in * the returned [[PropertyV1]] objects. + * @param featureFactoryConfig the feature factory configuration. * @param userProfile the profile of the user making the request. * @return a [[Seq]] of [[PropertyV1]] objects representing the properties that have values for the resource. */ - private def getResourceProperties(resourceIri: IRI, maybeResourceTypeIri: Option[IRI], userProfile: UserADM): Future[Seq[PropertyV1]] = { + private def getResourceProperties(resourceIri: IRI, + maybeResourceTypeIri: Option[IRI], + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[Seq[PropertyV1]] = { for { groupedPropsByType: GroupedPropertiesByType <- getGroupedProperties(resourceIri) @@ -2287,6 +2388,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo propertyInfoMap = propertyInfoMap, resourceEntityInfoMap = resourceEntityInfoMap, propsAndCardinalities = propsAndCardinalities, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) } yield queryResult @@ -2296,15 +2398,20 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo * Converts a SPARQL query result into a [[ResourceInfoV1]]. Expects the query result to contain columns called `p` (predicate), * `o` (object), `objPred` (file value predicate, if `o` is a file value), and `objObj` (file value object). * - * @param resourceIri the IRI of the resource. - * @param resInfoResponseRows the SPARQL query result. - * @param userProfile the user that is making the request. - * @param queryOntology if `true`, the ontology will be queried for information about the resource type, and the [[ResourceInfoV1]] - * will include `restype_label`, `restype_description`, and `restype_iconsrc`. Otherwise, those member variables - * will be empty. + * @param resourceIri the IRI of the resource. + * @param resInfoResponseRows the SPARQL query result. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the user that is making the request. + * @param queryOntology if `true`, the ontology will be queried for information about the resource type, and the [[ResourceInfoV1]] + * will include `restype_label`, `restype_description`, and `restype_iconsrc`. Otherwise, those member variables + * will be empty. * @return a tuple (permission, [[ResourceInfoV1]]) describing the resource. */ - private def makeResourceInfoV1(resourceIri: IRI, resInfoResponseRows: Seq[VariableResultsRow], userProfile: UserADM, queryOntology: Boolean): Future[(Option[Int], ResourceInfoV1)] = { + private def makeResourceInfoV1(resourceIri: IRI, + resInfoResponseRows: Seq[VariableResultsRow], + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM, + queryOntology: Boolean): Future[(Option[Int], ResourceInfoV1)] = { val userProfileV1 = userProfile.asUserProfileV1 if (resInfoResponseRows.isEmpty) { @@ -2347,6 +2454,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo valueProps = fileValueProps, projectShortcode = projectShortcode, responderManager = responderManager, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) @@ -2465,6 +2573,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo * ontology-based information for linking properties in the returned [[PropertyV1]] objects. * @param propsAndCardinalities a [[Map]] of property IRIs to their cardinalities in the class of the queried resource. If this [[Map]] is not * empty, it will be used to include cardinalities in the returned [[PropertyV1]] objects. + * @param featureFactoryConfig the feature factory configuration. * @param userProfile the profile of the user making the request. * @return a [[Seq]] of [[PropertyV1]] objects. */ @@ -2474,6 +2583,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo propertyInfoMap: Map[IRI, PropertyInfoV1], resourceEntityInfoMap: Map[IRI, ClassInfoV1], propsAndCardinalities: Map[IRI, KnoraCardinalityInfo], + featureFactoryConfig: FeatureFactoryConfig, userProfile: UserADM): Future[Seq[PropertyV1]] = { val userProfileV1 = userProfile.asUserProfileV1 @@ -2551,6 +2661,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo valueProps = valueProps, projectShortcode = projectShortcode, responderManager = responderManager, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) @@ -2669,6 +2780,7 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo valueProps = linkValueProps, projectShortcode = projectShortcode, responderManager = responderManager, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) diff --git a/webapi/src/main/scala/org/knora/webapi/responders/v1/StandoffResponderV1.scala b/webapi/src/main/scala/org/knora/webapi/responders/v1/StandoffResponderV1.scala index 62c7b9ccc9..1228865194 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/v1/StandoffResponderV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/v1/StandoffResponderV1.scala @@ -23,6 +23,7 @@ import java.util.UUID import akka.pattern._ import org.knora.webapi._ +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.StringFormatter import org.knora.webapi.messages.admin.responder.usersmessages.UserADM @@ -46,9 +47,9 @@ class StandoffResponderV1(responderData: ResponderData) extends Responder(respon * Receives a message of type [[StandoffResponderRequestV1]], and returns an appropriate response message. */ def receive(msg: StandoffResponderRequestV1) = msg match { - case CreateMappingRequestV1(xml, label, projectIri, mappingName, userProfile, uuid) => createMappingV1(xml, label, projectIri, mappingName, userProfile, uuid) - case GetMappingRequestV1(mappingIri, userProfile) => getMappingV1(mappingIri, userProfile) - case GetXSLTransformationRequestV1(xsltTextReprIri, userProfile) => getXSLTransformation(xsltTextReprIri, userProfile) + case CreateMappingRequestV1(xml, label, projectIri, mappingName, featureFactoryConfig, userProfile, uuid) => createMappingV1(xml, label, projectIri, mappingName, featureFactoryConfig, userProfile, uuid) + case GetMappingRequestV1(mappingIri, featureFactoryConfig, userProfile) => getMappingV1(mappingIri, featureFactoryConfig, userProfile) + case GetXSLTransformationRequestV1(xsltTextReprIri, featureFactoryConfig, userProfile) => getXSLTransformation(xsltTextReprIri, featureFactoryConfig, userProfile) case other => handleUnexpectedMessage(other, log, this.getClass.getName) } @@ -59,13 +60,20 @@ class StandoffResponderV1(responderData: ResponderData) extends Responder(respon * Retrieves a `knora-base:XSLTransformation` in the triplestore and requests the corresponding XSL file from Sipi. * * @param xslTransformationIri The IRI of the resource representing the XSL Transformation (a [[org.knora.webapi.messages.OntologyConstants.KnoraBase.XSLTransformation]]). + * @param featureFactoryConfig the feature factory configuration. * @param userProfile The client making the request. * @return a [[GetXSLTransformationResponseV1]]. */ - private def getXSLTransformation(xslTransformationIri: IRI, userProfile: UserADM): Future[GetXSLTransformationResponseV1] = { + private def getXSLTransformation(xslTransformationIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[GetXSLTransformationResponseV1] = { for { - xsltTransformation <- (responderManager ? GetXSLTransformationRequestV2(xsltTextRepresentationIri = xslTransformationIri, requestingUser = userProfile)).mapTo[GetXSLTransformationResponseV2] + xsltTransformation <- (responderManager ? GetXSLTransformationRequestV2( + xsltTextRepresentationIri = xslTransformationIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = userProfile + )).mapTo[GetXSLTransformationResponseV2] } yield GetXSLTransformationResponseV1( xslt = xsltTransformation.xslt ) @@ -75,10 +83,17 @@ class StandoffResponderV1(responderData: ResponderData) extends Responder(respon * Creates a mapping between XML elements and attributes to standoff classes and properties. * The mapping is used to convert XML documents to [[TextValueV1]] and back. * - * @param xml the provided mapping. - * @param userProfile the client that made the request. + * @param xml the provided mapping. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the client that made the request. */ - private def createMappingV1(xml: String, label: String, projectIri: IRI, mappingName: String, userProfile: UserADM, apiRequestID: UUID): Future[CreateMappingResponseV1] = { + private def createMappingV1(xml: String, + label: String, + projectIri: IRI, + mappingName: String, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM, + apiRequestID: UUID): Future[CreateMappingResponseV1] = { implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance @@ -86,12 +101,13 @@ class StandoffResponderV1(responderData: ResponderData) extends Responder(respon metadata = CreateMappingRequestMetadataV2( label = label, projectIri = projectIri.toSmartIri, - mappingName = mappingName), - xml = CreateMappingRequestXMLV2( - xml = xml + mappingName = mappingName ), + xml = CreateMappingRequestXMLV2(xml), + featureFactoryConfig = featureFactoryConfig, requestingUser = userProfile, - apiRequestID = apiRequestID) + apiRequestID = apiRequestID + ) for { mappingResponse <- (responderManager ? createMappingRequest).mapTo[CreateMappingResponseV2] @@ -110,15 +126,20 @@ class StandoffResponderV1(responderData: ResponderData) extends Responder(respon * Gets a mapping either from the cache or by making a request to the triplestore. * * @param mappingIri the IRI of the mapping to retrieve. + * @param featureFactoryConfig the feature factory configuration. * @param userProfile the user making the request. * @return a [[MappingXMLtoStandoff]]. */ - private def getMappingV1(mappingIri: IRI, userProfile: UserADM): Future[GetMappingResponseV1] = { + private def getMappingV1(mappingIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[GetMappingResponseV1] = { for { - mappingResponse: GetMappingResponseV2 <- (responderManager ? GetMappingRequestV2(mappingIri = mappingIri, requestingUser = userProfile)).mapTo[GetMappingResponseV2] - - + mappingResponse: GetMappingResponseV2 <- (responderManager ? GetMappingRequestV2( + mappingIri = mappingIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = userProfile + )).mapTo[GetMappingResponseV2] } yield GetMappingResponseV1( mappingIri = mappingResponse.mappingIri, mapping = mappingResponse.mapping, diff --git a/webapi/src/main/scala/org/knora/webapi/responders/v1/UsersResponderV1.scala b/webapi/src/main/scala/org/knora/webapi/responders/v1/UsersResponderV1.scala index 11a42a65b9..20a7c1ddf0 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/v1/UsersResponderV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/v1/UsersResponderV1.scala @@ -25,6 +25,7 @@ import akka.http.scaladsl.util.FastFuture import akka.pattern._ import org.knora.webapi._ import org.knora.webapi.exceptions.{ApplicationCacheException, ForbiddenException, NotFoundException} +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.OntologyConstants import org.knora.webapi.messages.admin.responder.permissionsmessages.{PermissionDataGetADM, PermissionsDataADM} import org.knora.webapi.messages.store.triplestoremessages._ @@ -55,10 +56,10 @@ class UsersResponderV1(responderData: ResponderData) extends Responder(responder case UsersGetV1(userProfile) => usersGetV1(userProfile) case UsersGetRequestV1(userProfileV1) => usersGetRequestV1(userProfileV1) case UserDataByIriGetV1(userIri, short) => userDataByIriGetV1(userIri, short) - case UserProfileByIRIGetV1(userIri, profileType) => userProfileByIRIGetV1(userIri, profileType) - case UserProfileByIRIGetRequestV1(userIri, profileType, userProfile) => userProfileByIRIGetRequestV1(userIri, profileType, userProfile) - case UserProfileByEmailGetV1(email, profileType) => userProfileByEmailGetV1(email, profileType) - case UserProfileByEmailGetRequestV1(email, profileType, userProfile) => userProfileByEmailGetRequestV1(email, profileType, userProfile) + case UserProfileByIRIGetV1(userIri, profileType, featureFactoryConfig) => userProfileByIRIGetV1(userIri, profileType, featureFactoryConfig) + case UserProfileByIRIGetRequestV1(userIri, profileType, featureFactoryConfig, userProfile) => userProfileByIRIGetRequestV1(userIri, profileType, featureFactoryConfig, userProfile) + case UserProfileByEmailGetV1(email, profileType, featureFactoryConfig) => userProfileByEmailGetV1(email, profileType, featureFactoryConfig) + case UserProfileByEmailGetRequestV1(email, profileType, featureFactoryConfig, userProfile) => userProfileByEmailGetRequestV1(email, profileType, featureFactoryConfig, userProfile) case UserProjectMembershipsGetRequestV1(userIri, userProfile, apiRequestID) => userProjectMembershipsGetRequestV1(userIri, userProfile, apiRequestID) case UserProjectAdminMembershipsGetRequestV1(userIri, userProfile, apiRequestID) => userProjectAdminMembershipsGetRequestV1(userIri, userProfile, apiRequestID) case UserGroupMembershipsGetRequestV1(userIri, userProfile, apiRequestID) => userGroupMembershipsGetRequestV1(userIri, userProfile, apiRequestID) @@ -160,11 +161,14 @@ class UsersResponderV1(responderData: ResponderData) extends Responder(responder * Gets information about a Knora user, and returns it in a [[UserProfileV1]]. If possible, tries to retrieve the * user profile from cache. If not, it retrieves it from the triplestore and writes it to the cache. * - * @param userIri the IRI of the user. - * @param profileType the type of the requested profile (restricted of full). + * @param userIri the IRI of the user. + * @param profileType the type of the requested profile (restricted of full). + * @param featureFactoryConfig the feature factory configuration. * @return a [[UserProfileV1]] describing the user. */ - private def userProfileByIRIGetV1(userIri: IRI, profileType: UserProfileType): Future[Option[UserProfileV1]] = { + private def userProfileByIRIGetV1(userIri: IRI, + profileType: UserProfileType, + featureFactoryConfig: FeatureFactoryConfig): Future[Option[UserProfileV1]] = { // log.debug(s"userProfileByIRIGetV1: userIri = $userIRI', clean = '$profileType'") CacheUtil.get[UserProfileV1](USER_PROFILE_CACHE_NAME, userIri) match { @@ -184,7 +188,10 @@ class UsersResponderV1(responderData: ResponderData) extends Responder(responder userDataQueryResponse <- (storeManager ? SparqlSelectRequest(sparqlQueryString)).mapTo[SparqlSelectResponse] - maybeUserProfileV1 <- userDataQueryResponse2UserProfileV1(userDataQueryResponse) + maybeUserProfileV1 <- userDataQueryResponse2UserProfileV1( + userDataQueryResponse = userDataQueryResponse, + featureFactoryConfig = featureFactoryConfig + ) _ = if (maybeUserProfileV1.nonEmpty) { writeUserProfileV1ToCache(maybeUserProfileV1.get) @@ -200,19 +207,28 @@ class UsersResponderV1(responderData: ResponderData) extends Responder(responder /** * Gets information about a Knora user, and returns it as a [[UserProfileResponseV1]]. * - * @param userIRI the IRI of the user. - * @param profileType the type of the requested profile (restriced or full). - * @param userProfile the requesting user's profile. + * @param userIRI the IRI of the user. + * @param profileType the type of the requested profile (restriced or full). + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the requesting user's profile. * @return a [[UserProfileResponseV1]] */ - private def userProfileByIRIGetRequestV1(userIRI: IRI, profileType: UserProfileType, userProfile: UserProfileV1): Future[UserProfileResponseV1] = { + private def userProfileByIRIGetRequestV1(userIRI: IRI, + profileType: UserProfileType, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserProfileV1): Future[UserProfileResponseV1] = { for { _ <- Future( if (!userProfile.permissionData.isSystemAdmin && !userProfile.userData.user_id.contains(userIRI)) { throw ForbiddenException("SystemAdmin permissions are required.") } ) - maybeUserProfileToReturn <- userProfileByIRIGetV1(userIRI, profileType) + maybeUserProfileToReturn <- userProfileByIRIGetV1( + userIri = userIRI, + profileType = profileType, + featureFactoryConfig = featureFactoryConfig + ) + result = maybeUserProfileToReturn match { case Some(up) => UserProfileResponseV1(up) case None => throw NotFoundException(s"User '$userIRI' not found") @@ -224,11 +240,14 @@ class UsersResponderV1(responderData: ResponderData) extends Responder(responder * Gets information about a Knora user, and returns it in a [[UserProfileV1]]. If possible, tries to retrieve the user profile * from cache. If not, it retrieves it from the triplestore and writes it to the cache. * - * @param email the email of the user. - * @param profileType the type of the requested profile (restricted or full). + * @param email the email of the user. + * @param profileType the type of the requested profile (restricted or full). + * @param featureFactoryConfig the feature factory configuration. * @return a [[UserProfileV1]] describing the user. */ - private def userProfileByEmailGetV1(email: String, profileType: UserProfileType): Future[Option[UserProfileV1]] = { + private def userProfileByEmailGetV1(email: String, + profileType: UserProfileType, + featureFactoryConfig: FeatureFactoryConfig): Future[Option[UserProfileV1]] = { // log.debug(s"userProfileByEmailGetV1: username = '{}', type = '{}'", email, profileType) CacheUtil.get[UserProfileV1](USER_PROFILE_CACHE_NAME, email) match { @@ -248,7 +267,10 @@ class UsersResponderV1(responderData: ResponderData) extends Responder(responder userDataQueryResponse <- (storeManager ? SparqlSelectRequest(sparqlQueryString)).mapTo[SparqlSelectResponse] //_ = log.debug(MessageUtil.toSource(userDataQueryResponse)) - maybeUserProfileV1 <- userDataQueryResponse2UserProfileV1(userDataQueryResponse) + maybeUserProfileV1 <- userDataQueryResponse2UserProfileV1( + userDataQueryResponse = userDataQueryResponse, + featureFactoryConfig = featureFactoryConfig + ) _ = if (maybeUserProfileV1.nonEmpty) { writeUserProfileV1ToCache(maybeUserProfileV1.get) @@ -267,15 +289,24 @@ class UsersResponderV1(responderData: ResponderData) extends Responder(responder /** * Gets information about a Knora user, and returns it as a [[UserProfileResponseV1]]. * - * @param email the email of the user. - * @param profileType the type of the requested profile (restricted or full). - * @param userProfile the requesting user's profile. + * @param email the email of the user. + * @param profileType the type of the requested profile (restricted or full). + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the requesting user's profile. * @return a [[UserProfileResponseV1]] * @throws NotFoundException if the user with the supplied email is not found. */ - private def userProfileByEmailGetRequestV1(email: String, profileType: UserProfileType, userProfile: UserProfileV1): Future[UserProfileResponseV1] = { + private def userProfileByEmailGetRequestV1(email: String, + profileType: UserProfileType, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserProfileV1): Future[UserProfileResponseV1] = { for { - maybeUserProfileToReturn <- userProfileByEmailGetV1(email, profileType) + maybeUserProfileToReturn <- userProfileByEmailGetV1( + email = email, + profileType = profileType, + featureFactoryConfig = featureFactoryConfig + ) + result = maybeUserProfileToReturn match { case Some(up: UserProfileV1) => UserProfileResponseV1(up) case None => throw NotFoundException(s"User '$email' not found") @@ -434,9 +465,11 @@ class UsersResponderV1(responderData: ResponderData) extends Responder(responder * Helper method used to create a [[UserProfileV1]] from the [[SparqlSelectResponse]] containing user data. * * @param userDataQueryResponse a [[SparqlSelectResponse]] containing user data. + * @param featureFactoryConfig the feature factory configuration. * @return a [[UserProfileV1]] containing the user's data. */ - private def userDataQueryResponse2UserProfileV1(userDataQueryResponse: SparqlSelectResponse): Future[Option[UserProfileV1]] = { + private def userDataQueryResponse2UserProfileV1(userDataQueryResponse: SparqlSelectResponse, + featureFactoryConfig: FeatureFactoryConfig): Future[Option[UserProfileV1]] = { // log.debug("userDataQueryResponse2UserProfileV1 - userDataQueryResponse: {}", MessageUtil.toSource(userDataQueryResponse)) @@ -494,11 +527,17 @@ class UsersResponderV1(responderData: ResponderData) extends Responder(responder groupIris = groupIris, isInProjectAdminGroups = isInProjectAdminGroups, isInSystemAdminGroup = isInSystemAdminGroup, + featureFactoryConfig = featureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser )).mapTo[PermissionsDataADM] maybeProjectInfoFutures: Seq[Future[Option[ProjectInfoV1]]] = projectIris.map { - projectIri => (responderManager ? ProjectInfoByIRIGetV1(iri = projectIri, userProfileV1 = None)).mapTo[Option[ProjectInfoV1]] + projectIri => + (responderManager ? ProjectInfoByIRIGetV1( + iri = projectIri, + featureFactoryConfig = featureFactoryConfig, + userProfileV1 = None + )).mapTo[Option[ProjectInfoV1]] } maybeProjectInfos: Seq[Option[ProjectInfoV1]] <- Future.sequence(maybeProjectInfoFutures) diff --git a/webapi/src/main/scala/org/knora/webapi/responders/v1/ValuesResponderV1.scala b/webapi/src/main/scala/org/knora/webapi/responders/v1/ValuesResponderV1.scala index f8be4f2e58..ebbe19ce85 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/v1/ValuesResponderV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/v1/ValuesResponderV1.scala @@ -24,6 +24,7 @@ import java.time.Instant import akka.pattern._ import org.knora.webapi._ import org.knora.webapi.exceptions._ +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.admin.responder.permissionsmessages.{DefaultObjectAccessPermissionsStringForPropertyGetADM, DefaultObjectAccessPermissionsStringResponseADM, PermissionADM, PermissionType} import org.knora.webapi.messages.admin.responder.projectsmessages.{ProjectADM, ProjectGetRequestADM, ProjectGetResponseADM, ProjectIdentifierADM} @@ -60,8 +61,8 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde * Receives a message of type [[ValuesResponderRequestV1]], and returns an appropriate response message. */ def receive(msg: ValuesResponderRequestV1) = msg match { - case ValueGetRequestV1(valueIri, userProfile) => getValueResponseV1(valueIri, userProfile) - case LinkValueGetRequestV1(subjectIri, predicateIri, objectIri, userProfile) => getLinkValue(subjectIri, predicateIri, objectIri, userProfile) + case ValueGetRequestV1(valueIri, featureFactoryConfig, userProfile) => getValueResponseV1(valueIri, featureFactoryConfig, userProfile) + case LinkValueGetRequestV1(subjectIri, predicateIri, objectIri, featureFactoryConfig, userProfile) => getLinkValue(subjectIri, predicateIri, objectIri, featureFactoryConfig, userProfile) case versionHistoryRequest: ValueVersionHistoryGetRequestV1 => getValueVersionHistoryResponseV1(versionHistoryRequest) case createValueRequest: CreateValueRequestV1 => createValueV1(createValueRequest) case changeValueRequest: ChangeValueRequestV1 => changeValueV1(changeValueRequest) @@ -79,18 +80,30 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde /** * Queries a `knora-base:Value` and returns a [[ValueGetResponseV1]] describing it. * - * @param valueIri the IRI of the value to be queried. - * @param userProfile the profile of the user making the request. + * @param valueIri the IRI of the value to be queried. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. * @return a [[ValueGetResponseV1]]. */ - private def getValueResponseV1(valueIri: IRI, userProfile: UserADM): Future[ValueGetResponseV1] = { + private def getValueResponseV1(valueIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[ValueGetResponseV1] = { for { - maybeValueQueryResult <- findValue(valueIri, userProfile) + maybeValueQueryResult <- findValue( + valueIri = valueIri, + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) response <- maybeValueQueryResult match { case Some(valueQueryResult) => for { - maybeValueCreatorProfile <- (responderManager ? UserProfileByIRIGetV1(valueQueryResult.creatorIri, UserProfileTypeV1.RESTRICTED)).mapTo[Option[UserProfileV1]] + maybeValueCreatorProfile <- (responderManager ? UserProfileByIRIGetV1( + userIri = valueQueryResult.creatorIri, + userProfileType = UserProfileTypeV1.RESTRICTED, + featureFactoryConfig = featureFactoryConfig + )).mapTo[Option[UserProfileV1]] + valueCreatorProfile = maybeValueCreatorProfile match { case Some(up) => up case None => throw NotFoundException(s"User ${valueQueryResult.creatorIri} not found") @@ -144,6 +157,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde propertyIri = createValueRequest.propertyIri, propertyObjectClassConstraint = propertyObjectClassConstraint, updateValueV1 = createValueRequest.value, + featureFactoryConfig = createValueRequest.featureFactoryConfig, userProfile = createValueRequest.userProfile ) @@ -152,6 +166,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde resourceFullResponse <- (responderManager ? ResourceFullGetRequestV1( iri = createValueRequest.resourceIri, + featureFactoryConfig = createValueRequest.featureFactoryConfig, userADM = createValueRequest.userProfile, getIncoming = false )).mapTo[ResourceFullResponseV1] @@ -207,6 +222,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde maybeProjectInfo <- { responderManager ? ProjectInfoByIRIGetV1( iri = projectIri, + featureFactoryConfig = createValueRequest.featureFactoryConfig, userProfileV1 = Some(createValueRequest.userProfile.asUserProfileV1) ) }.mapTo[Option[ProjectInfoV1]] @@ -227,13 +243,16 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde comment = createValueRequest.comment, valueCreator = userIri, valuePermissions = defaultObjectAccessPermissions.permissionLiteral, - userProfile = createValueRequest.userProfile) + featureFactoryConfig = createValueRequest.featureFactoryConfig, + userProfile = createValueRequest.userProfile + ) // Verify that it was created. apiResponse <- verifyValueCreation( resourceIri = createValueRequest.resourceIri, propertyIri = createValueRequest.propertyIri, unverifiedValue = unverifiedValue, + featureFactoryConfig = createValueRequest.featureFactoryConfig, userProfile = createValueRequest.userProfile ) } yield apiResponse @@ -359,7 +378,12 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde // So now we can get the set of standoff link targets that are ordinary IRIs, and check that each of // them exists in the triplestore and is a knora-base:Resource. targetIrisThatAlreadyExist: Set[IRI] = targetIris.keySet.filterNot(iri => stringFormatter.isStandoffLinkReferenceToClientIDForResource(iri)) - targetIriCheckResult <- checkStandoffResourceReferenceTargets(targetIris = targetIrisThatAlreadyExist, userProfile = createMultipleValuesRequest.userProfile) + + targetIriCheckResult <- checkStandoffResourceReferenceTargets( + targetIris = targetIrisThatAlreadyExist, + featureFactoryConfig = createMultipleValuesRequest.featureFactoryConfig, + userProfile = createMultipleValuesRequest.userProfile + ) // For each target IRI, construct a SparqlTemplateLinkUpdate to create a hasStandoffLinkTo property and one LinkValue, // with the associated count as the LinkValue's initial reference count. @@ -586,6 +610,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde resourceIri = verifyRequest.resourceIri, propertyIri = propertyIri, unverifiedValue = unverifiedValue, + featureFactoryConfig = verifyRequest.featureFactoryConfig, userProfile = verifyRequest.userProfile ) } @@ -660,6 +685,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde response: ChangeValueResponseV1 <- changeValueV1(ChangeValueRequestV1( valueIri = fileValues.head.valueObjectIri, value = changeFileValueRequest.file, + featureFactoryConfig = changeFileValueRequest.featureFactoryConfig, userProfile = changeFileValueRequest.userProfile, apiRequestID = changeFileValueRequest.apiRequestID // re-use the same id )) @@ -684,12 +710,17 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde } for { - resourceInfoResponse <- (responderManager ? ResourceInfoGetRequestV1(iri = changeFileValueRequest.resourceIri, userProfile = changeFileValueRequest.userProfile)).mapTo[ResourceInfoResponseV1] + resourceInfoResponse <- (responderManager ? ResourceInfoGetRequestV1( + iri = changeFileValueRequest.resourceIri, + featureFactoryConfig = changeFileValueRequest.featureFactoryConfig, + userProfile = changeFileValueRequest.userProfile + )).mapTo[ResourceInfoResponseV1] // Get project info projectResponse <- { responderManager ? ProjectGetRequestADM( identifier = ProjectIdentifierADM(maybeIri = Some(resourceInfoResponse.resource_info.get.project_id)), + featureFactoryConfig = changeFileValueRequest.featureFactoryConfig, requestingUser = changeFileValueRequest.userProfile ) }.mapTo[ProjectGetResponseADM] @@ -749,12 +780,17 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde predicateIri = propertyIri, objectIri = None, linkValueIri = changeValueRequest.valueIri, + featureFactoryConfig = changeValueRequest.featureFactoryConfig, userProfile = changeValueRequest.userProfile ) case otherValueV1 => // We're being asked to update an ordinary value. - findValue(changeValueRequest.valueIri, changeValueRequest.userProfile) + findValue( + valueIri = changeValueRequest.valueIri, + featureFactoryConfig = changeValueRequest.featureFactoryConfig, + userProfile = changeValueRequest.userProfile + ) } currentValueQueryResult = maybeCurrentValueQueryResult.getOrElse(throw NotFoundException(s"Value ${changeValueRequest.valueIri} not found (it may have been deleted)")) @@ -781,6 +817,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde propertyIri = propertyIri, propertyObjectClassConstraint = propertyObjectClassConstraint, updateValueV1 = changeValueRequest.value, + featureFactoryConfig = changeValueRequest.featureFactoryConfig, userProfile = changeValueRequest.userProfile ) @@ -798,6 +835,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde // and there's no point in doing it if the other checks fail.) resourceFullResponse <- (responderManager ? ResourceFullGetRequestV1( iri = findResourceWithValueResult.resourceIri, + featureFactoryConfig = changeValueRequest.featureFactoryConfig, userADM = changeValueRequest.userProfile, getIncoming = false )).mapTo[ResourceFullResponseV1] @@ -842,6 +880,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde maybeProjectInfo <- { responderManager ? ProjectInfoByIRIGetV1( iri = resourceFullResponse.resinfo.get.project_id, + featureFactoryConfig = changeValueRequest.featureFactoryConfig, userProfileV1 = Some(changeValueRequest.userProfile.asUserProfileV1) ) }.mapTo[Option[ProjectInfoV1]] @@ -863,7 +902,8 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde // We'll need to create a new LinkValue. - changeLinkValueV1AfterChecks(projectIri = currentValueQueryResult.projectIri, + changeLinkValueV1AfterChecks( + projectIri = currentValueQueryResult.projectIri, dataNamedGraph = StringFormatter.getGeneralInstance.projectDataNamedGraphV1(projectInfo), resourceIri = findResourceWithValueResult.resourceIri, propertyIri = propertyIri, @@ -872,7 +912,9 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde comment = changeValueRequest.comment, valueCreator = userIri, valuePermissions = defaultObjectAccessPermissions.permissionLiteral, - userProfile = changeValueRequest.userProfile) + featureFactoryConfig = changeValueRequest.featureFactoryConfig, + userProfile = changeValueRequest.userProfile + ) case _ => // We're updating an ordinary value. Generate an IRI for the new version of the value. @@ -884,7 +926,8 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde case (p, o) => p == OntologyConstants.KnoraBase.HasPermissions }.map(_._2).getOrElse(throw InconsistentTriplestoreDataException(s"Value ${changeValueRequest.valueIri} has no permissions")) - changeOrdinaryValueV1AfterChecks(projectIri = currentValueQueryResult.projectIri, + changeOrdinaryValueV1AfterChecks( + projectIri = currentValueQueryResult.projectIri, resourceIri = findResourceWithValueResult.resourceIri, propertyIri = propertyIri, currentValueIri = changeValueRequest.valueIri, @@ -894,7 +937,9 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde comment = changeValueRequest.comment, valueCreator = userIri, valuePermissions = valuePermissions, - userProfile = changeValueRequest.userProfile) + featureFactoryConfig = changeValueRequest.featureFactoryConfig, + userProfile = changeValueRequest.userProfile + ) } } yield apiResponse } @@ -933,7 +978,11 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde for { // Ensure that the user has permission to modify the value. - maybeCurrentValueQueryResult: Option[ValueQueryResult] <- findValue(changeCommentRequest.valueIri, changeCommentRequest.userProfile) + maybeCurrentValueQueryResult: Option[ValueQueryResult] <- findValue( + valueIri = changeCommentRequest.valueIri, + featureFactoryConfig = changeCommentRequest.featureFactoryConfig, + userProfile = changeCommentRequest.userProfile + ) currentValueQueryResult = maybeCurrentValueQueryResult.getOrElse(throw NotFoundException(s"Value ${changeCommentRequest.valueIri} not found (it may have been deleted)")) @@ -953,6 +1002,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde maybeProjectInfo <- { responderManager ? ProjectInfoByIRIGetV1( findResourceWithValueResult.projectIri, + featureFactoryConfig = changeCommentRequest.featureFactoryConfig, None ) }.mapTo[Option[ProjectInfoV1]] @@ -985,6 +1035,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde resourceIri = findResourceWithValueResult.resourceIri, propertyIri = findResourceWithValueResult.propertyIri, searchValueIri = newValueIri, + featureFactoryConfig = changeCommentRequest.featureFactoryConfig, userProfile = changeCommentRequest.userProfile ) } yield ChangeValueResponseV1( @@ -1036,7 +1087,12 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde */ def makeTaskFuture(userIri: IRI, findResourceWithValueResult: FindResourceWithValueResult): Future[DeleteValueResponseV1] = for { // Ensure that the user has permission to mark the value as deleted. - maybeCurrentValueQueryResult <- findValue(deleteValueRequest.valueIri, deleteValueRequest.userProfile) + maybeCurrentValueQueryResult <- findValue( + valueIri = deleteValueRequest.valueIri, + featureFactoryConfig = deleteValueRequest.featureFactoryConfig, + userProfile = deleteValueRequest.userProfile + ) + currentValueQueryResult = maybeCurrentValueQueryResult.getOrElse(throw NotFoundException(s"Value ${deleteValueRequest.valueIri} not found (it may have been deleted)")) _ = if (!PermissionUtilADM.impliesPermissionCodeV1(userHasPermissionCode = Some(currentValueQueryResult.permissionCode), userNeedsPermission = OntologyConstants.KnoraBase.DeletePermission)) { @@ -1065,8 +1121,9 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde // Get project info maybeProjectInfo <- { responderManager ? ProjectInfoByIRIGetV1( - findResourceWithValueResult.projectIri, - None + iri = findResourceWithValueResult.projectIri, + featureFactoryConfig = deleteValueRequest.featureFactoryConfig, + userProfileV1 = None ) }.mapTo[Option[ProjectInfoV1]] @@ -1081,6 +1138,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde targetResourceIri = linkValue.objectIri, valueCreator = userIri, valuePermissions = valuePermissions, + featureFactoryConfig = deleteValueRequest.featureFactoryConfig, userProfile = deleteValueRequest.userProfile ) @@ -1110,6 +1168,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde targetResourceIri = targetResourceIri, valueCreator = OntologyConstants.KnoraAdmin.SystemUser, valuePermissions = standoffLinkValuePermissions, + featureFactoryConfig = deleteValueRequest.featureFactoryConfig, userProfile = deleteValueRequest.userProfile ) }.toVector @@ -1125,8 +1184,9 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde // Get project info maybeProjectInfo <- { responderManager ? ProjectInfoByIRIGetV1( - findResourceWithValueResult.projectIri, - None + iri = findResourceWithValueResult.projectIri, + featureFactoryConfig = deleteValueRequest.featureFactoryConfig, + userProfileV1 = None ) }.mapTo[Option[ProjectInfoV1]] @@ -1300,26 +1360,37 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde * a [[ValueGetResponseV1]] containing a [[LinkValueV1]] describing the `LinkValue`. Throws [[NotFoundException]] * if no such `LinkValue` is found. * - * @param subjectIri the IRI of the resource that is the source of the link. - * @param predicateIri the IRI of the property that links the two resources. - * @param objectIri the IRI of the resource that is the target of the link. - * @param userProfile the profile of the user making the request. + * @param subjectIri the IRI of the resource that is the source of the link. + * @param predicateIri the IRI of the property that links the two resources. + * @param objectIri the IRI of the resource that is the target of the link. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. * @return a [[ValueGetResponseV1]] containing a [[LinkValueV1]]. */ @throws(classOf[NotFoundException]) - private def getLinkValue(subjectIri: IRI, predicateIri: IRI, objectIri: IRI, userProfile: UserADM): Future[ValueGetResponseV1] = { + private def getLinkValue(subjectIri: IRI, + predicateIri: IRI, + objectIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[ValueGetResponseV1] = { for { maybeValueQueryResult <- findLinkValueByLinkTriple( subjectIri = subjectIri, predicateIri = predicateIri, objectIri = objectIri, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) linkValueResponse <- maybeValueQueryResult match { case Some(valueQueryResult) => for { - maybeValueCreatorProfile <- (responderManager ? UserProfileByIRIGetV1(valueQueryResult.creatorIri, UserProfileTypeV1.RESTRICTED)).mapTo[Option[UserProfileV1]] + maybeValueCreatorProfile <- (responderManager ? UserProfileByIRIGetV1( + userIri = valueQueryResult.creatorIri, + userProfileType = UserProfileTypeV1.RESTRICTED, + featureFactoryConfig = featureFactoryConfig + )).mapTo[Option[UserProfileV1]] + valueCreatorProfile = maybeValueCreatorProfile match { case Some(up) => up case None => throw NotFoundException(s"User ${valueQueryResult.creatorIri} not found") @@ -1415,11 +1486,14 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde /** * Queries a `knora-base:Value` and returns a [[ValueQueryResult]] describing it. * - * @param valueIri the IRI of the value to be queried. - * @param userProfile the profile of the user making the request. + * @param valueIri the IRI of the value to be queried. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. * @return a [[ValueQueryResult]], or `None` if the value is not found. */ - private def findValue(valueIri: IRI, userProfile: UserADM): Future[Option[ValueQueryResult]] = { + private def findValue(valueIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[Option[ValueQueryResult]] = { for { sparqlQuery <- Future(org.knora.webapi.messages.twirl.queries.sparql.v1.txt.getValue( triplestore = settings.triplestoreType, @@ -1429,7 +1503,12 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde response <- (storeManager ? SparqlSelectRequest(sparqlQuery)).mapTo[SparqlSelectResponse] rows: Seq[VariableResultsRow] = response.results.bindings - maybeValueQueryResult <- sparqlQueryResults2ValueQueryResult(valueIri, rows, userProfile) + maybeValueQueryResult <- sparqlQueryResults2ValueQueryResult( + valueIri = valueIri, + rows = rows, + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) // If it's a link value, check that the user has permission to see the source and target resources. _ = maybeValueQueryResult match { @@ -1496,14 +1575,20 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde * Looks for `knora-base:LinkValue` given its IRI, and returns a [[ValueGetResponseV1]] containing a * [[LinkValueV1]] describing the `LinkValue`, or `None` if no such `LinkValue` is found. * - * @param subjectIri the IRI of the resource that is the source of the link. - * @param predicateIri the IRI of the property that links the two resources. - * @param objectIri if provided, the IRI of the target resource. - * @param linkValueIri the IRI of the `LinkValue`. - * @param userProfile the profile of the user making the request. + * @param subjectIri the IRI of the resource that is the source of the link. + * @param predicateIri the IRI of the property that links the two resources. + * @param objectIri if provided, the IRI of the target resource. + * @param linkValueIri the IRI of the `LinkValue`. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. * @return an optional [[ValueGetResponseV1]] containing a [[LinkValueV1]]. */ - private def findLinkValueByIri(subjectIri: IRI, predicateIri: IRI, objectIri: Option[IRI], linkValueIri: IRI, userProfile: UserADM): Future[Option[LinkValueQueryResult]] = { + private def findLinkValueByIri(subjectIri: IRI, + predicateIri: IRI, + objectIri: Option[IRI], + linkValueIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[Option[LinkValueQueryResult]] = { for { sparqlQuery <- Future { org.knora.webapi.messages.twirl.queries.sparql.v1.txt.findLinkValueByIri( @@ -1517,7 +1602,12 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde response <- (storeManager ? SparqlSelectRequest(sparqlQuery)).mapTo[SparqlSelectResponse] rows: Seq[VariableResultsRow] = response.results.bindings - maybeLinkValueQueryResult <- sparqlQueryResults2LinkValueQueryResult(rows, userProfile) + + maybeLinkValueQueryResult <- sparqlQueryResults2LinkValueQueryResult( + rows = rows, + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) // Check that the user has permission to see the source and target resources. _ = if (maybeLinkValueQueryResult.nonEmpty) { @@ -1531,13 +1621,18 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde * a [[ValueGetResponseV1]] containing a [[LinkValueV1]] describing the `LinkValue`, or `None` if no such * `LinkValue` is found. * - * @param subjectIri the IRI of the resource that is the source of the link. - * @param predicateIri the IRI of the property that links the two resources. - * @param objectIri the IRI of the target resource. - * @param userProfile the profile of the user making the request. + * @param subjectIri the IRI of the resource that is the source of the link. + * @param predicateIri the IRI of the property that links the two resources. + * @param objectIri the IRI of the target resource. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. * @return an optional [[ValueGetResponseV1]] containing a [[LinkValueV1]]. */ - private def findLinkValueByLinkTriple(subjectIri: IRI, predicateIri: IRI, objectIri: IRI, userProfile: UserADM): Future[Option[LinkValueQueryResult]] = { + private def findLinkValueByLinkTriple(subjectIri: IRI, + predicateIri: IRI, + objectIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[Option[LinkValueQueryResult]] = { for { sparqlQuery <- Future { org.knora.webapi.messages.twirl.queries.sparql.v1.txt.findLinkValueByObject( @@ -1550,7 +1645,12 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde response <- (storeManager ? SparqlSelectRequest(sparqlQuery)).mapTo[SparqlSelectResponse] rows: Seq[VariableResultsRow] = response.results.bindings - maybeLinkValueQueryResult <- sparqlQueryResults2LinkValueQueryResult(rows, userProfile) + + maybeLinkValueQueryResult <- sparqlQueryResults2LinkValueQueryResult( + rows = rows, + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) // Check that the user has permission to see the source and target resources. _ = maybeLinkValueQueryResult match { @@ -1565,13 +1665,17 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde * If the value is a link value, the caller of this method is responsible for ensuring that the user has permission to * view the source and target resources. * - * @param valueIri the IRI of the value that was queried. - * @param rows the query result rows. - * @param userProfile the profile of the user making the request. + * @param valueIri the IRI of the value that was queried. + * @param rows the query result rows. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. * @return a [[ValueQueryResult]]. */ @throws(classOf[ForbiddenException]) - private def sparqlQueryResults2ValueQueryResult(valueIri: IRI, rows: Seq[VariableResultsRow], userProfile: UserADM): Future[Option[BasicValueQueryResult]] = { + private def sparqlQueryResults2ValueQueryResult(valueIri: IRI, + rows: Seq[VariableResultsRow], + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[Option[BasicValueQueryResult]] = { val userProfileV1 = userProfile.asUserProfileV1 if (rows.nonEmpty) { @@ -1585,6 +1689,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde valueProps = valueProps, projectShortcode = projectShortcode, responderManager = responderManager, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) @@ -1654,11 +1759,14 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde /** * Converts SPARQL query results about a `knora-base:LinkValue` into a [[LinkValueQueryResult]]. * - * @param rows SPARQL query results about a `knora-base:LinkValue`. - * @param userProfile the profile of the user making the request. + * @param rows SPARQL query results about a `knora-base:LinkValue`. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. * @return a [[LinkValueQueryResult]]. */ - private def sparqlQueryResults2LinkValueQueryResult(rows: Seq[VariableResultsRow], userProfile: UserADM): Future[Option[LinkValueQueryResult]] = { + private def sparqlQueryResults2LinkValueQueryResult(rows: Seq[VariableResultsRow], + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[Option[LinkValueQueryResult]] = { val userProfileV1 = userProfile.asUserProfileV1 if (rows.nonEmpty) { @@ -1675,6 +1783,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde valueProps = valueProps, projectShortcode = projectShortcode, responderManager = responderManager, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) @@ -1733,16 +1842,18 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde /** * Verifies that a value was created. * - * @param resourceIri the IRI of the resource in which the value should have been created. - * @param propertyIri the IRI of the property that should point from the resource to the value. - * @param unverifiedValue the value that should have been created. - * @param userProfile the profile of the user making the request. + * @param resourceIri the IRI of the resource in which the value should have been created. + * @param propertyIri the IRI of the property that should point from the resource to the value. + * @param unverifiedValue the value that should have been created. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. * @return a [[CreateValueResponseV1]], or a failed [[Future]] if the value could not be found in * the resource's version history. */ private def verifyValueCreation(resourceIri: IRI, propertyIri: IRI, unverifiedValue: UnverifiedValueV1, + featureFactoryConfig: FeatureFactoryConfig, userProfile: UserADM): Future[CreateValueResponseV1] = { unverifiedValue.value match { case linkUpdateV1: LinkUpdateV1 => @@ -1752,6 +1863,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde linkPropertyIri = propertyIri, linkTargetIri = linkUpdateV1.targetResourceIri, linkValueIri = unverifiedValue.newValueIri, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) @@ -1772,6 +1884,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde resourceIri = resourceIri, propertyIri = propertyIri, searchValueIri = unverifiedValue.newValueIri, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) @@ -1788,15 +1901,20 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde * Given the IRI of a value that should have been created, looks for the value in the resource's version history, * and returns details about it. If the value is not found, throws [[UpdateNotPerformedException]]. * - * @param resourceIri the IRI of the resource that may have the value. - * @param propertyIri the IRI of the property that may have have the value. - * @param searchValueIri the IRI of the value. - * @param userProfile the profile of the user making the request. + * @param resourceIri the IRI of the resource that may have the value. + * @param propertyIri the IRI of the property that may have have the value. + * @param searchValueIri the IRI of the value. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. * @return a [[ValueQueryResult]]. */ @throws(classOf[UpdateNotPerformedException]) @throws(classOf[ForbiddenException]) - private def verifyOrdinaryValueUpdate(resourceIri: IRI, propertyIri: IRI, searchValueIri: IRI, userProfile: UserADM): Future[ValueQueryResult] = { + private def verifyOrdinaryValueUpdate(resourceIri: IRI, + propertyIri: IRI, + searchValueIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[ValueQueryResult] = { for { // Do a SPARQL query to look for the value in the resource's version history. sparqlQuery <- Future { @@ -1811,7 +1929,13 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde updateVerificationResponse: SparqlSelectResponse <- (storeManager ? SparqlSelectRequest(sparqlQuery)).mapTo[SparqlSelectResponse] rows = updateVerificationResponse.results.bindings - resultOption <- sparqlQueryResults2ValueQueryResult(valueIri = searchValueIri, rows = rows, userProfile = userProfile) + + resultOption <- sparqlQueryResults2ValueQueryResult( + valueIri = searchValueIri, + rows = rows, + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) } yield resultOption.getOrElse(throw UpdateNotPerformedException(s"The update to value $searchValueIri for property $propertyIri in resource $resourceIri was not performed. Please report this as a possible bug.")) } @@ -1820,22 +1944,29 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde * Given information about a link that should have been created, verifies that the link exists, and returns * details about it. If the link has not been created, throws [[UpdateNotPerformedException]]. * - * @param linkSourceIri the IRI of the resource that should be the source of the link. - * @param linkPropertyIri the IRI of the link property. - * @param linkTargetIri the IRI of the resource that should be the target of the link. - * @param linkValueIri the IRI of the `knora-base:LinkValue` that should have been created. - * @param userProfile the profile of the user making the request. + * @param linkSourceIri the IRI of the resource that should be the source of the link. + * @param linkPropertyIri the IRI of the link property. + * @param linkTargetIri the IRI of the resource that should be the target of the link. + * @param linkValueIri the IRI of the `knora-base:LinkValue` that should have been created. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. * @return a [[LinkValueQueryResult]]. */ @throws(classOf[UpdateNotPerformedException]) @throws(classOf[ForbiddenException]) - private def verifyLinkUpdate(linkSourceIri: IRI, linkPropertyIri: IRI, linkTargetIri: IRI, linkValueIri: IRI, userProfile: UserADM): Future[LinkValueQueryResult] = { + private def verifyLinkUpdate(linkSourceIri: IRI, + linkPropertyIri: IRI, + linkTargetIri: IRI, + linkValueIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[LinkValueQueryResult] = { for { maybeLinkValueQueryResult <- findLinkValueByIri( subjectIri = linkSourceIri, predicateIri = linkPropertyIri, objectIri = Some(linkTargetIri), linkValueIri = linkValueIri, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) @@ -1907,14 +2038,15 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde * Creates a new value (either an ordinary value or a link), using an existing transaction, assuming that * pre-update checks have already been done. * - * @param dataNamedGraph the named graph in which the value is to be created. - * @param projectIri the IRI of the project in which to create the value. - * @param resourceIri the IRI of the resource in which to create the value. - * @param propertyIri the IRI of the property that will point from the resource to the value. - * @param value the value to create. - * @param valueCreator the IRI of the new value's owner. - * @param valuePermissions the literal that should be used as the object of the new value's `knora-base:hasPermissions` predicate. - * @param userProfile the profile of the user making the request. + * @param dataNamedGraph the named graph in which the value is to be created. + * @param projectIri the IRI of the project in which to create the value. + * @param resourceIri the IRI of the resource in which to create the value. + * @param propertyIri the IRI of the property that will point from the resource to the value. + * @param value the value to create. + * @param valueCreator the IRI of the new value's owner. + * @param valuePermissions the literal that should be used as the object of the new value's `knora-base:hasPermissions` predicate. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. * @return an [[UnverifiedValueV1]]. */ private def createValueV1AfterChecks(dataNamedGraph: IRI, @@ -1925,6 +2057,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde comment: Option[String], valueCreator: IRI, valuePermissions: String, + featureFactoryConfig: FeatureFactoryConfig, userProfile: UserADM): Future[UnverifiedValueV1] = { value match { case linkUpdateV1: LinkUpdateV1 => @@ -1936,6 +2069,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde comment = comment, valueCreator = valueCreator, valuePermissions = valuePermissions, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) @@ -1948,6 +2082,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde comment = comment, valueCreator = valueCreator, valuePermissions = valuePermissions, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) } @@ -1956,13 +2091,14 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde /** * Creates a link, using an existing transaction, assuming that pre-update checks have already been done. * - * @param dataNamedGraph the named graph in which the link is to be created. - * @param resourceIri the resource in which the link is to be created. - * @param propertyIri the link property. - * @param linkUpdateV1 a [[LinkUpdateV1]] specifying the target resource. - * @param valueCreator the IRI of the new link value's owner. - * @param valuePermissions the literal that should be used as the object of the new link value's `knora-base:hasPermissions` predicate. - * @param userProfile the profile of the user making the request. + * @param dataNamedGraph the named graph in which the link is to be created. + * @param resourceIri the resource in which the link is to be created. + * @param propertyIri the link property. + * @param linkUpdateV1 a [[LinkUpdateV1]] specifying the target resource. + * @param valueCreator the IRI of the new link value's owner. + * @param valuePermissions the literal that should be used as the object of the new link value's `knora-base:hasPermissions` predicate. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. * @return an [[UnverifiedValueV1]]. */ private def createLinkValueV1AfterChecks(dataNamedGraph: IRI, @@ -1972,6 +2108,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde comment: Option[String], valueCreator: IRI, valuePermissions: String, + featureFactoryConfig: FeatureFactoryConfig, userProfile: UserADM): Future[UnverifiedValueV1] = { for { sparqlTemplateLinkUpdate <- incrementLinkValue( @@ -1980,6 +2117,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde targetResourceIri = linkUpdateV1.targetResourceIri, valueCreator = valueCreator, valuePermissions = valuePermissions, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) @@ -2013,12 +2151,13 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde /** * Creates an ordinary value (i.e. not a link), using an existing transaction, assuming that pre-update checks have already been done. * - * @param resourceIri the resource in which the value is to be created. - * @param propertyIri the property that should point to the value. - * @param value an [[UpdateValueV1]] describing the value. - * @param valueCreator the IRI of the new value's owner. - * @param valuePermissions the literal that should be used as the object of the new value's `knora-base:hasPermissions` predicate. - * @param userProfile the profile of the user making the request. + * @param resourceIri the resource in which the value is to be created. + * @param propertyIri the property that should point to the value. + * @param value an [[UpdateValueV1]] describing the value. + * @param valueCreator the IRI of the new value's owner. + * @param valuePermissions the literal that should be used as the object of the new value's `knora-base:hasPermissions` predicate. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. * @return an [[UnverifiedValueV1]]. */ private def createOrdinaryValueV1AfterChecks(dataNamedGraph: IRI, @@ -2028,6 +2167,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde comment: Option[String], valueCreator: IRI, valuePermissions: String, + featureFactoryConfig: FeatureFactoryConfig, userProfile: UserADM): Future[UnverifiedValueV1] = { // Generate an IRI for the new value. val newValueIri = stringFormatter.makeRandomValueIri(resourceIri) @@ -2050,6 +2190,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde targetResourceIri = targetResourceIri, valueCreator = OntologyConstants.KnoraAdmin.SystemUser, valuePermissions = standoffLinkValuePermissions, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) }.toVector @@ -2093,16 +2234,17 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde /** * Changes a link, assuming that pre-update checks have already been done. * - * @param dataNamedGraph the IRI of the named graph containing the link. - * @param projectIri the IRI of the project containing the link. - * @param resourceIri the IRI of the resource containing the link. - * @param propertyIri the IRI of the link property. - * @param currentLinkValueV1 a [[LinkValueV1]] representing the `knora-base:LinkValue` for the existing link. - * @param linkUpdateV1 a [[LinkUpdateV1]] indicating the new target resource. - * @param comment an optional comment on the new link value. - * @param valueCreator the IRI of the new link value's owner. - * @param valuePermissions the literal that should be used as the object of the new link value's `knora-base:hasPermissions` predicate. - * @param userProfile the profile of the user making the request. + * @param dataNamedGraph the IRI of the named graph containing the link. + * @param projectIri the IRI of the project containing the link. + * @param resourceIri the IRI of the resource containing the link. + * @param propertyIri the IRI of the link property. + * @param currentLinkValueV1 a [[LinkValueV1]] representing the `knora-base:LinkValue` for the existing link. + * @param linkUpdateV1 a [[LinkUpdateV1]] indicating the new target resource. + * @param comment an optional comment on the new link value. + * @param valueCreator the IRI of the new link value's owner. + * @param valuePermissions the literal that should be used as the object of the new link value's `knora-base:hasPermissions` predicate. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. * @return a [[ChangeValueResponseV1]]. */ private def changeLinkValueV1AfterChecks(dataNamedGraph: IRI, @@ -2114,6 +2256,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde comment: Option[String], valueCreator: IRI, valuePermissions: String, + featureFactoryConfig: FeatureFactoryConfig, userProfile: UserADM): Future[ChangeValueResponseV1] = { for { // Delete the existing link and decrement its LinkValue's reference count. @@ -2123,6 +2266,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde targetResourceIri = currentLinkValueV1.objectIri, valueCreator = valueCreator, valuePermissions = valuePermissions, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) @@ -2133,14 +2277,16 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde targetResourceIri = linkUpdateV1.targetResourceIri, valueCreator = valueCreator, valuePermissions = valuePermissions, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) // Get project info maybeProjectInfo <- { responderManager ? ProjectInfoByIRIGetV1( - projectIri, - None + iri = projectIri, + featureFactoryConfig = featureFactoryConfig, + userProfileV1 = None ) }.mapTo[Option[ProjectInfoV1]] @@ -2180,6 +2326,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde linkPropertyIri = propertyIri, linkTargetIri = linkUpdateV1.targetResourceIri, linkValueIri = sparqlTemplateLinkUpdateForNewLink.newLinkValueIri, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) @@ -2222,6 +2369,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde comment: Option[String], valueCreator: IRI, valuePermissions: String, + featureFactoryConfig: FeatureFactoryConfig, userProfile: UserADM): Future[ChangeValueResponseV1] = { for { // If we're adding a text value, update direct links and LinkValues for any resource references in Standoff. @@ -2261,6 +2409,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde targetResourceIri = targetResourceIri, valueCreator = OntologyConstants.KnoraAdmin.SystemUser, valuePermissions = standoffLinkValuePermissions, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) } @@ -2274,6 +2423,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde targetResourceIri = removedTargetResource, valueCreator = OntologyConstants.KnoraAdmin.SystemUser, valuePermissions = standoffLinkValuePermissions, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) } @@ -2286,8 +2436,9 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde // Get project info maybeProjectInfo <- { responderManager ? ProjectInfoByIRIGetV1( - projectIri, - None + iri = projectIri, + featureFactoryConfig = featureFactoryConfig, + userProfileV1 = None ) }.mapTo[Option[ProjectInfoV1]] @@ -2332,6 +2483,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde resourceIri = resourceIri, propertyIri = propertyIri, searchValueIri = newValueIri, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) } yield ChangeValueResponseV1( @@ -2356,12 +2508,13 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde * - If that link and `LinkValue` don't yet exist, they will be created, and the `LinkValue` will be given * a reference count of 1. * - * @param sourceResourceIri the IRI of the source resource. - * @param linkPropertyIri the IRI of the property that links the source resource to the target resource. - * @param targetResourceIri the IRI of the target resource. - * @param valueCreator the IRI of the new link value's owner. - * @param valuePermissions the literal that should be used as the object of the new link value's `knora-base:hasPermissions` predicate. - * @param userProfile the profile of the user making the request. + * @param sourceResourceIri the IRI of the source resource. + * @param linkPropertyIri the IRI of the property that links the source resource to the target resource. + * @param targetResourceIri the IRI of the target resource. + * @param valueCreator the IRI of the new link value's owner. + * @param valuePermissions the literal that should be used as the object of the new link value's `knora-base:hasPermissions` predicate. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. * @return a [[SparqlTemplateLinkUpdate]] that can be passed to a SPARQL update template. */ private def incrementLinkValue(sourceResourceIri: IRI, @@ -2369,6 +2522,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde targetResourceIri: IRI, valueCreator: IRI, valuePermissions: String, + featureFactoryConfig: FeatureFactoryConfig, userProfile: UserADM): Future[SparqlTemplateLinkUpdate] = { for { // Check whether a LinkValue already exists for this link. @@ -2376,11 +2530,16 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde subjectIri = sourceResourceIri, predicateIri = linkPropertyIri, objectIri = targetResourceIri, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) // Check that the target resource actually exists and is a knora-base:Resource. - targetIriCheckResult <- checkStandoffResourceReferenceTargets(targetIris = Set(targetResourceIri), userProfile = userProfile) + targetIriCheckResult <- checkStandoffResourceReferenceTargets( + targetIris = Set(targetResourceIri), + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) // Generate an IRI for the new LinkValue. newLinkValueIri = stringFormatter.makeRandomValueIri(sourceResourceIri) @@ -2441,12 +2600,13 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde * made, with a decremented reference count. If the new reference count is 0, the link will be removed and the * `LinkValue` will be marked as deleted. * - * @param sourceResourceIri the IRI of the source resource. - * @param linkPropertyIri the IRI of the property that links the source resource to the target resource. - * @param targetResourceIri the IRI of the target resource. - * @param valueCreator the IRI of the new link value's owner. - * @param valuePermissions the literal that should be used as the object of the new link value's `knora-base:hasPermissions` predicate. - * @param userProfile the profile of the user making the request. + * @param sourceResourceIri the IRI of the source resource. + * @param linkPropertyIri the IRI of the property that links the source resource to the target resource. + * @param targetResourceIri the IRI of the target resource. + * @param valueCreator the IRI of the new link value's owner. + * @param valuePermissions the literal that should be used as the object of the new link value's `knora-base:hasPermissions` predicate. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. * @return a [[SparqlTemplateLinkUpdate]] that can be passed to a SPARQL update template. */ private def decrementLinkValue(sourceResourceIri: IRI, @@ -2454,6 +2614,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde targetResourceIri: IRI, valueCreator: IRI, valuePermissions: String, + featureFactoryConfig: FeatureFactoryConfig, userProfile: UserADM): Future[SparqlTemplateLinkUpdate] = { for { // Query the LinkValue to ensure that it exists and to get its contents. @@ -2461,6 +2622,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde subjectIri = sourceResourceIri, predicateIri = linkPropertyIri, objectIri = targetResourceIri, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile ) @@ -2534,12 +2696,15 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde /** * Given a set of IRIs of standoff resource reference targets, checks that each one actually refers to a `knora-base:Resource`. * - * @param targetIris the IRIs to check. - * @param userProfile the profile of the user making the request. + * @param targetIris the IRIs to check. + * @param featureFactoryConfig the feature factory configuration. + * @param userProfile the profile of the user making the request. * @return a `Future[Unit]` on success, otherwise a `Future` containing an exception ([[NotFoundException]] if the target resource is not found, * or [[BadRequestException]] if the target IRI isn't a `knora-base:Resource`). */ - private def checkStandoffResourceReferenceTargets(targetIris: Set[IRI], userProfile: UserADM): Future[Unit] = { + private def checkStandoffResourceReferenceTargets(targetIris: Set[IRI], + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[Unit] = { if (targetIris.isEmpty) { Future(()) } else { @@ -2549,6 +2714,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde checkTargetClassResponse <- (responderManager ? ResourceCheckClassRequestV1( resourceIri = targetIri, owlClass = OntologyConstants.KnoraBase.Resource, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile )).mapTo[ResourceCheckClassResponseV1] @@ -2569,10 +2735,15 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde * @param propertyIri the IRI of the property. * @param propertyObjectClassConstraint the IRI of the `knora-base:objectClassConstraint` of the property. * @param updateValueV1 the value to be updated. + * @param featureFactoryConfig the feature factory configuration. * @param userProfile the profile of the user making the request. * @return an empty [[Future]] on success, or a failed [[Future]] if the value has the wrong type. */ - private def checkPropertyObjectClassConstraintForValue(propertyIri: IRI, propertyObjectClassConstraint: IRI, updateValueV1: UpdateValueV1, userProfile: UserADM): Future[Unit] = { + private def checkPropertyObjectClassConstraintForValue(propertyIri: IRI, + propertyObjectClassConstraint: IRI, + updateValueV1: UpdateValueV1, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[Unit] = { for { result <- updateValueV1 match { case linkUpdate: LinkUpdateV1 => @@ -2581,6 +2752,7 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde checkTargetClassResponse <- (responderManager ? ResourceCheckClassRequestV1( resourceIri = linkUpdate.targetResourceIri, owlClass = propertyObjectClassConstraint, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile )).mapTo[ResourceCheckClassResponseV1] diff --git a/webapi/src/main/scala/org/knora/webapi/responders/v2/ListsResponderV2.scala b/webapi/src/main/scala/org/knora/webapi/responders/v2/ListsResponderV2.scala index 126b94ff25..e5cc131431 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/v2/ListsResponderV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/v2/ListsResponderV2.scala @@ -21,6 +21,7 @@ package org.knora.webapi.responders.v2 import akka.pattern._ import org.knora.webapi.IRI +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.admin.responder.listsmessages.{ListGetRequestADM, ListGetResponseADM, ListNodeInfoGetRequestADM, ListNodeInfoGetResponseADM} import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.util.ResponderData @@ -39,8 +40,8 @@ class ListsResponderV2(responderData: ResponderData) extends Responder(responder * Receives a message of type [[ListsResponderRequestV2]], and returns an appropriate response message inside a future. */ def receive(msg: ListsResponderRequestV2) = msg match { - case ListGetRequestV2(listIri, requestingUser) => getList(listIri, requestingUser) - case NodeGetRequestV2(nodeIri, requestingUser) => getNode(nodeIri, requestingUser) + case ListGetRequestV2(listIri, featureFactoryConfig, requestingUser) => getList(listIri, featureFactoryConfig, requestingUser) + case NodeGetRequestV2(nodeIri, featureFactoryConfig, requestingUser) => getNode(nodeIri, featureFactoryConfig, requestingUser) case other => handleUnexpectedMessage(other, log, this.getClass.getName) } @@ -51,10 +52,16 @@ class ListsResponderV2(responderData: ResponderData) extends Responder(responder * @param requestingUser the user making the request. * @return a [[ListGetResponseV2]]. */ - private def getList(listIri: IRI, requestingUser: UserADM): Future[ListGetResponseV2] = { + private def getList(listIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[ListGetResponseV2] = { for { - listResponseADM: ListGetResponseADM <- (responderManager ? ListGetRequestADM(iri = listIri, requestingUser = requestingUser)).mapTo[ListGetResponseADM] + listResponseADM: ListGetResponseADM <- (responderManager ? ListGetRequestADM( + iri = listIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + )).mapTo[ListGetResponseADM] } yield ListGetResponseV2(list = listResponseADM.list, requestingUser.lang, settings.fallbackLanguage) } @@ -62,14 +69,21 @@ class ListsResponderV2(responderData: ResponderData) extends Responder(responder /** * Gets a single list node from the triplestore. * - * @param nodeIri the Iri of the list node. - * @param requestingUser the user making the request. + * @param nodeIri the Iri of the list node. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return a [[NodeGetResponseV2]]. */ - private def getNode(nodeIri: IRI, requestingUser: UserADM): Future[NodeGetResponseV2] = { + private def getNode(nodeIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[NodeGetResponseV2] = { for { - nodeResponse: ListNodeInfoGetResponseADM <- (responderManager ? ListNodeInfoGetRequestADM(iri = nodeIri, requestingUser = requestingUser)).mapTo[ListNodeInfoGetResponseADM] + nodeResponse: ListNodeInfoGetResponseADM <- (responderManager ? ListNodeInfoGetRequestADM( + iri = nodeIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + )).mapTo[ListNodeInfoGetResponseADM] } yield NodeGetResponseV2(node = nodeResponse.nodeinfo, requestingUser.lang, settings.fallbackLanguage) } diff --git a/webapi/src/main/scala/org/knora/webapi/responders/v2/MetadataResponderV2.scala b/webapi/src/main/scala/org/knora/webapi/responders/v2/MetadataResponderV2.scala index fa62deb188..b58dd15456 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/v2/MetadataResponderV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/v2/MetadataResponderV2.scala @@ -20,17 +20,16 @@ package org.knora.webapi.responders.v2 import akka.pattern._ -import org.apache.jena.graph.Graph - +import org.knora.webapi.IRI import org.knora.webapi.exceptions.AssertionException import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectADM -import org.knora.webapi.messages.store.triplestoremessages.{InsertGraphDataContentRequest, InsertGraphDataContentResponse, NamedGraphDataRequest, NamedGraphDataResponse} -import org.knora.webapi.messages.util.{RdfFormatUtil, ResponderData} +import org.knora.webapi.messages.store.triplestoremessages._ +import org.knora.webapi.messages.util.ResponderData +import org.knora.webapi.messages.util.rdf.{RdfFeatureFactory, RdfFormatUtil, RdfModel, Turtle} import org.knora.webapi.messages.v2.responder.SuccessResponseV2 import org.knora.webapi.messages.v2.responder.metadatamessages._ import org.knora.webapi.responders.Responder.handleUnexpectedMessage import org.knora.webapi.responders.{IriLocker, Responder} -import org.knora.webapi.{IRI, RdfMediaTypes} import scala.concurrent.Future @@ -73,7 +72,7 @@ class MetadataResponderV2(responderData: ResponderData) extends Responder(respon */ private def putProjectMetadata(request: MetadataPutRequestV2): Future[SuccessResponseV2] = { val metadataGraphIRI: IRI = stringFormatter.projectMetadataNamedGraphV2(request.projectADM) - val graphContent = request.toTurtle + val graphContent: String = request.toTurtle(request.featureFactoryConfig) def makeTaskFuture: Future[SuccessResponseV2] = { for { @@ -88,12 +87,14 @@ class MetadataResponderV2(responderData: ResponderData) extends Responder(respon // Check if the created metadata graph has the same content as the one in the request. createdMetadata: MetadataGetResponseV2 <- getProjectMetadata(request.projectADM) - createdMetadataGraph: Graph = RdfFormatUtil.parseToJenaGraph( + rdfFormatUtil: RdfFormatUtil = RdfFeatureFactory.getRdfFormatUtil(request.featureFactoryConfig) + + savedModel: RdfModel = rdfFormatUtil.parseToRdfModel( rdfStr = createdMetadata.turtle, - mediaType = RdfMediaTypes.`text/turtle` + rdfFormat = Turtle ) - _ = if (!createdMetadataGraph.isIsomorphicWith(request.graph)) { + _ = if (!savedModel.isIsomorphicWith(request.rdfModel)) { throw AssertionException("Project metadata was stored, but is not correct. Please report this a bug.") } } yield SuccessResponseV2(s"Project metadata was stored for project <${request.projectIri}>.") diff --git a/webapi/src/main/scala/org/knora/webapi/responders/v2/OntologyResponderV2.scala b/webapi/src/main/scala/org/knora/webapi/responders/v2/OntologyResponderV2.scala index 9b908d02a9..01c38f7fe3 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/v2/OntologyResponderV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/v2/OntologyResponderV2.scala @@ -25,6 +25,7 @@ import akka.http.scaladsl.util.FastFuture import akka.pattern._ import org.knora.webapi._ import org.knora.webapi.exceptions._ +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.StringFormatter.{SalsahGuiAttribute, SalsahGuiAttributeDefinition} import org.knora.webapi.messages.admin.responder.projectsmessages.{ProjectGetRequestADM, ProjectGetResponseADM, ProjectIdentifierADM} @@ -97,7 +98,7 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon * Receives a message of type [[OntologiesResponderRequestV2]], and returns an appropriate response message. */ def receive(msg: OntologiesResponderRequestV2) = msg match { - case LoadOntologiesRequestV2(requestingUser) => loadOntologies(requestingUser) + case LoadOntologiesRequestV2(featureFactoryConfig, requestingUser) => loadOntologies(featureFactoryConfig, requestingUser) case EntityInfoGetRequestV2(classIris, propertyIris, requestingUser) => getEntityInfoResponseV2(classIris, propertyIris, requestingUser) case StandoffEntityInfoGetRequestV2(standoffClassIris, standoffPropertyIris, requestingUser) => getStandoffEntityInfoResponseV2(standoffClassIris, standoffPropertyIris, requestingUser) case StandoffClassesWithDataTypeGetRequestV2(requestingUser) => getStandoffStandoffClassesWithDataTypeV2(requestingUser) @@ -135,10 +136,12 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon /** * Loads and caches all ontology information. * - * @param requestingUser the user making the request. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return a [[SuccessResponseV2]]. */ - private def loadOntologies(requestingUser: UserADM): Future[SuccessResponseV2] = { + private def loadOntologies(featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[SuccessResponseV2] = { for { _ <- Future { if (!(requestingUser.id == KnoraSystemInstances.Users.SystemUser.id || requestingUser.permissions.isSystemAdmin)) { @@ -166,7 +169,10 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon ontologyGraph = ontologyIri ).toString - (storeManager ? SparqlExtendedConstructRequest(ontologyGraphConstructQuery)).mapTo[SparqlExtendedConstructResponse].map { + (storeManager ? SparqlExtendedConstructRequest( + sparql = ontologyGraphConstructQuery, + featureFactoryConfig = featureFactoryConfig + )).mapTo[SparqlExtendedConstructResponse].map { response => OntologyGraph(ontologyIri = ontologyIri, constructResponse = response) } } @@ -1604,10 +1610,12 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon /** * Reads an ontology's metadata. * - * @param internalOntologyIri the ontology's internal IRI. + * @param internalOntologyIri the ontology's internal IRI. + * @param featureFactoryConfig the feature factory configuration. * @return an [[OntologyMetadataV2]], or [[None]] if the ontology is not found. */ - private def loadOntologyMetadata(internalOntologyIri: SmartIri): Future[Option[OntologyMetadataV2]] = { + private def loadOntologyMetadata(internalOntologyIri: SmartIri, + featureFactoryConfig: FeatureFactoryConfig): Future[Option[OntologyMetadataV2]] = { for { _ <- Future { if (!internalOntologyIri.getOntologySchema.contains(InternalSchema)) { @@ -1620,7 +1628,10 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon ontologyIri = internalOntologyIri ).toString() - getOntologyInfoResponse <- (storeManager ? SparqlConstructRequest(getOntologyInfoSparql)).mapTo[SparqlConstructResponse] + getOntologyInfoResponse <- (storeManager ? SparqlConstructRequest( + sparql = getOntologyInfoSparql, + featureFactoryConfig = featureFactoryConfig + )).mapTo[SparqlConstructResponse] metadata: Option[OntologyMetadataV2] = if (getOntologyInfoResponse.statements.isEmpty) { None @@ -1704,7 +1715,10 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon cacheData <- getCacheData // Make sure the ontology doesn't already exist. - existingOntologyMetadata: Option[OntologyMetadataV2] <- loadOntologyMetadata(internalOntologyIri) + existingOntologyMetadata: Option[OntologyMetadataV2] <- loadOntologyMetadata( + internalOntologyIri = internalOntologyIri, + featureFactoryConfig = createOntologyRequest.featureFactoryConfig + ) _ = if (existingOntologyMetadata.nonEmpty) { throw BadRequestException(s"Ontology ${internalOntologyIri.toOntologySchema(ApiV2Complex)} cannot be created, because it already exists") @@ -1747,7 +1761,10 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon lastModificationDate = Some(currentTime) ).unescape - maybeLoadedOntologyMetadata: Option[OntologyMetadataV2] <- loadOntologyMetadata(internalOntologyIri) + maybeLoadedOntologyMetadata: Option[OntologyMetadataV2] <- loadOntologyMetadata( + internalOntologyIri = internalOntologyIri, + featureFactoryConfig = createOntologyRequest.featureFactoryConfig + ) _ = maybeLoadedOntologyMetadata match { case Some(loadedOntologyMetadata) => @@ -1779,7 +1796,11 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon } // Get project info for the shortcode. - projectInfo: ProjectGetResponseADM <- (responderManager ? ProjectGetRequestADM(ProjectIdentifierADM(maybeIri = Some(projectIri.toString)), requestingUser = requestingUser)).mapTo[ProjectGetResponseADM] + projectInfo: ProjectGetResponseADM <- (responderManager ? ProjectGetRequestADM( + identifier = ProjectIdentifierADM(maybeIri = Some(projectIri.toString)), + featureFactoryConfig = createOntologyRequest.featureFactoryConfig, + requestingUser = requestingUser + )).mapTo[ProjectGetResponseADM] // Check that the ontology name is valid. validOntologyName = stringFormatter.validateProjectSpecificOntologyName(createOntologyRequest.ontologyName, throw BadRequestException(s"Invalid project-specific ontology name: ${createOntologyRequest.ontologyName}")) @@ -1814,7 +1835,11 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon ) // Check that the ontology exists and has not been updated by another user since the client last read its metadata. - _ <- checkOntologyLastModificationDateBeforeUpdate(internalOntologyIri = internalOntologyIri, expectedLastModificationDate = changeOntologyMetadataRequest.lastModificationDate) + _ <- checkOntologyLastModificationDateBeforeUpdate( + internalOntologyIri = internalOntologyIri, + expectedLastModificationDate = changeOntologyMetadataRequest.lastModificationDate, + featureFactoryConfig = changeOntologyMetadataRequest.featureFactoryConfig + ) // get the metadata of the ontology. oldMetadata: OntologyMetadataV2 = cacheData.ontologies(internalOntologyIri).ontologyMetadata @@ -1857,7 +1882,10 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon lastModificationDate = Some(currentTime) ).unescape - maybeLoadedOntologyMetadata: Option[OntologyMetadataV2] <- loadOntologyMetadata(internalOntologyIri) + maybeLoadedOntologyMetadata: Option[OntologyMetadataV2] <- loadOntologyMetadata( + internalOntologyIri = internalOntologyIri, + featureFactoryConfig = changeOntologyMetadataRequest.featureFactoryConfig + ) _ = maybeLoadedOntologyMetadata match { case Some(loadedOntologyMetadata) => @@ -1905,7 +1933,8 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon // Check that the ontology exists and has not been updated by another user since the client last read it. _ <- checkOntologyLastModificationDateBeforeUpdate( internalOntologyIri = internalOntologyIri, - expectedLastModificationDate = createClassRequest.lastModificationDate + expectedLastModificationDate = createClassRequest.lastModificationDate, + featureFactoryConfig = createClassRequest.featureFactoryConfig ) // Check that the class's rdf:type is owl:Class. @@ -2007,11 +2036,18 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon // Check that the ontology's last modification date was updated. - _ <- checkOntologyLastModificationDateAfterUpdate(internalOntologyIri = internalOntologyIri, expectedLastModificationDate = currentTime) + _ <- checkOntologyLastModificationDateAfterUpdate( + internalOntologyIri = internalOntologyIri, + expectedLastModificationDate = currentTime, + featureFactoryConfig = createClassRequest.featureFactoryConfig + ) // Check that the data that was saved corresponds to the data that was submitted. - loadedClassDef <- loadClassDefinition(internalClassIri) + loadedClassDef <- loadClassDefinition( + classIri = internalClassIri, + featureFactoryConfig = createClassRequest.featureFactoryConfig + ) _ = if (loadedClassDef != unescapedClassDefWithLinkValueProps) { throw InconsistentTriplestoreDataException(s"Attempted to save class definition $unescapedClassDefWithLinkValueProps, but $loadedClassDef was saved") @@ -2266,7 +2302,8 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon // Check that the ontology exists and has not been updated by another user since the client last read it. _ <- checkOntologyLastModificationDateBeforeUpdate( internalOntologyIri = internalOntologyIri, - expectedLastModificationDate = addCardinalitiesRequest.lastModificationDate + expectedLastModificationDate = addCardinalitiesRequest.lastModificationDate, + featureFactoryConfig = addCardinalitiesRequest.featureFactoryConfig ) // Check that the class's rdf:type is owl:Class. @@ -2374,11 +2411,18 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon // Check that the ontology's last modification date was updated. - _ <- checkOntologyLastModificationDateAfterUpdate(internalOntologyIri = internalOntologyIri, expectedLastModificationDate = currentTime) + _ <- checkOntologyLastModificationDateAfterUpdate( + internalOntologyIri = internalOntologyIri, + expectedLastModificationDate = currentTime, + featureFactoryConfig = addCardinalitiesRequest.featureFactoryConfig + ) // Check that the data that was saved corresponds to the data that was submitted. - loadedClassDef <- loadClassDefinition(internalClassIri) + loadedClassDef <- loadClassDefinition( + classIri = internalClassIri, + featureFactoryConfig = addCardinalitiesRequest.featureFactoryConfig + ) _ = if (loadedClassDef != newInternalClassDefWithLinkValueProps) { throw InconsistentTriplestoreDataException(s"Attempted to save class definition $newInternalClassDefWithLinkValueProps, but $loadedClassDef was saved") @@ -2449,7 +2493,8 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon // Check that the ontology exists and has not been updated by another user since the client last read it. _ <- checkOntologyLastModificationDateBeforeUpdate( internalOntologyIri = internalOntologyIri, - expectedLastModificationDate = changeCardinalitiesRequest.lastModificationDate + expectedLastModificationDate = changeCardinalitiesRequest.lastModificationDate, + featureFactoryConfig = changeCardinalitiesRequest.featureFactoryConfig ) // Check that the class's rdf:type is owl:Class. @@ -2541,11 +2586,18 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon // Check that the ontology's last modification date was updated. - _ <- checkOntologyLastModificationDateAfterUpdate(internalOntologyIri = internalOntologyIri, expectedLastModificationDate = currentTime) + _ <- checkOntologyLastModificationDateAfterUpdate( + internalOntologyIri = internalOntologyIri, + expectedLastModificationDate = currentTime, + featureFactoryConfig = changeCardinalitiesRequest.featureFactoryConfig + ) // Check that the data that was saved corresponds to the data that was submitted. - loadedClassDef <- loadClassDefinition(internalClassIri) + loadedClassDef <- loadClassDefinition( + classIri = internalClassIri, + featureFactoryConfig = changeCardinalitiesRequest.featureFactoryConfig + ) _ = if (loadedClassDef != newInternalClassDefWithLinkValueProps) { throw InconsistentTriplestoreDataException(s"Attempted to save class definition $newInternalClassDefWithLinkValueProps, but $loadedClassDef was saved") @@ -2615,7 +2667,8 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon // Check that the ontology exists and has not been updated by another user since the client last read it. _ <- checkOntologyLastModificationDateBeforeUpdate( internalOntologyIri = internalOntologyIri, - expectedLastModificationDate = deleteClassRequest.lastModificationDate + expectedLastModificationDate = deleteClassRequest.lastModificationDate, + featureFactoryConfig = deleteClassRequest.featureFactoryConfig ) // Check that the class exists. @@ -2650,7 +2703,11 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon // Check that the ontology's last modification date was updated. - _ <- checkOntologyLastModificationDateAfterUpdate(internalOntologyIri = internalOntologyIri, expectedLastModificationDate = currentTime) + _ <- checkOntologyLastModificationDateAfterUpdate( + internalOntologyIri = internalOntologyIri, + expectedLastModificationDate = currentTime, + featureFactoryConfig = deleteClassRequest.featureFactoryConfig + ) // Update the cache. @@ -2716,7 +2773,8 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon // Check that the ontology exists and has not been updated by another user since the client last read it. _ <- checkOntologyLastModificationDateBeforeUpdate( internalOntologyIri = internalOntologyIri, - expectedLastModificationDate = deletePropertyRequest.lastModificationDate + expectedLastModificationDate = deletePropertyRequest.lastModificationDate, + featureFactoryConfig = deletePropertyRequest.featureFactoryConfig ) // Check that the property exists. @@ -2769,7 +2827,11 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon // Check that the ontology's last modification date was updated. - _ <- checkOntologyLastModificationDateAfterUpdate(internalOntologyIri = internalOntologyIri, expectedLastModificationDate = currentTime) + _ <- checkOntologyLastModificationDateAfterUpdate( + internalOntologyIri = internalOntologyIri, + expectedLastModificationDate = currentTime, + featureFactoryConfig = deletePropertyRequest.featureFactoryConfig + ) // Update the cache. @@ -2834,7 +2896,8 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon // Check that the ontology exists and has not been updated by another user since the client last read it. _ <- checkOntologyLastModificationDateBeforeUpdate( internalOntologyIri = internalOntologyIri, - expectedLastModificationDate = deleteOntologyRequest.lastModificationDate + expectedLastModificationDate = deleteOntologyRequest.lastModificationDate, + featureFactoryConfig = deleteOntologyRequest.featureFactoryConfig ) // Check that none of the entities in the ontology are used in data or in other ontologies. @@ -2869,7 +2932,10 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon // Check that the ontology has been deleted. - maybeOntologyMetadata <- loadOntologyMetadata(internalOntologyIri) + maybeOntologyMetadata <- loadOntologyMetadata( + internalOntologyIri = internalOntologyIri, + featureFactoryConfig = deleteOntologyRequest.featureFactoryConfig + ) _ = if (maybeOntologyMetadata.nonEmpty) { throw UpdateNotPerformedException(s"Ontology ${internalOntologyIri.toOntologySchema(ApiV2Complex)} was not deleted. Please report this as a possible bug.") @@ -2933,7 +2999,11 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon internalPropertyDef = createPropertyRequest.propertyInfoContent.toOntologySchema(InternalSchema) // Check that the ontology exists and has not been updated by another user since the client last read it. - _ <- checkOntologyLastModificationDateBeforeUpdate(internalOntologyIri = internalOntologyIri, expectedLastModificationDate = createPropertyRequest.lastModificationDate) + _ <- checkOntologyLastModificationDateBeforeUpdate( + internalOntologyIri = internalOntologyIri, + expectedLastModificationDate = createPropertyRequest.lastModificationDate, + featureFactoryConfig = createPropertyRequest.featureFactoryConfig + ) // Check that the property's rdf:type is owl:ObjectProperty. @@ -3102,19 +3172,34 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon // Check that the ontology's last modification date was updated. - _ <- checkOntologyLastModificationDateAfterUpdate(internalOntologyIri = internalOntologyIri, expectedLastModificationDate = currentTime) + _ <- checkOntologyLastModificationDateAfterUpdate( + internalOntologyIri = internalOntologyIri, + expectedLastModificationDate = currentTime, + featureFactoryConfig = createPropertyRequest.featureFactoryConfig + ) // Check that the data that was saved corresponds to the data that was submitted. To make this comparison, // we have to undo the SPARQL-escaping of the input. - loadedPropertyDef <- loadPropertyDefinition(internalPropertyIri) + loadedPropertyDef <- loadPropertyDefinition( + propertyIri = internalPropertyIri, + featureFactoryConfig = createPropertyRequest.featureFactoryConfig + ) + unescapedInputPropertyDef = internalPropertyDef.unescape _ = if (loadedPropertyDef != unescapedInputPropertyDef) { throw InconsistentTriplestoreDataException(s"Attempted to save property definition $unescapedInputPropertyDef, but $loadedPropertyDef was saved") } - maybeLoadedLinkValuePropertyDefFuture: Option[Future[PropertyInfoContentV2]] = maybeLinkValuePropertyDef.map(linkValuePropertyDef => loadPropertyDefinition(linkValuePropertyDef.propertyIri)) + maybeLoadedLinkValuePropertyDefFuture: Option[Future[PropertyInfoContentV2]] = maybeLinkValuePropertyDef.map { + linkValuePropertyDef => + loadPropertyDefinition( + propertyIri = linkValuePropertyDef.propertyIri, + featureFactoryConfig = createPropertyRequest.featureFactoryConfig + ) + } + maybeLoadedLinkValuePropertyDef: Option[PropertyInfoContentV2] <- ActorUtil.optionFuture2FutureOption(maybeLoadedLinkValuePropertyDefFuture) maybeUnescapedNewLinkValuePropertyDef = maybeLinkValuePropertyDef.map(_.unescape) @@ -3212,7 +3297,11 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon currentReadPropertyInfo: ReadPropertyInfoV2 = ontology.properties.getOrElse(internalPropertyIri, throw NotFoundException(s"Property ${changePropertyLabelsOrCommentsRequest.propertyIri} not found")) // Check that the ontology exists and has not been updated by another user since the client last read it. - _ <- checkOntologyLastModificationDateBeforeUpdate(internalOntologyIri = internalOntologyIri, expectedLastModificationDate = changePropertyLabelsOrCommentsRequest.lastModificationDate) + _ <- checkOntologyLastModificationDateBeforeUpdate( + internalOntologyIri = internalOntologyIri, + expectedLastModificationDate = changePropertyLabelsOrCommentsRequest.lastModificationDate, + featureFactoryConfig = changePropertyLabelsOrCommentsRequest.featureFactoryConfig + ) // Check that the new labels/comments are different from the current ones. @@ -3254,12 +3343,19 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon // Check that the ontology's last modification date was updated. - _ <- checkOntologyLastModificationDateAfterUpdate(internalOntologyIri = internalOntologyIri, expectedLastModificationDate = currentTime) + _ <- checkOntologyLastModificationDateAfterUpdate( + internalOntologyIri = internalOntologyIri, + expectedLastModificationDate = currentTime, + featureFactoryConfig = changePropertyLabelsOrCommentsRequest.featureFactoryConfig + ) // Check that the data that was saved corresponds to the data that was submitted. To make this comparison, // we have to undo the SPARQL-escaping of the input. - loadedPropertyDef <- loadPropertyDefinition(internalPropertyIri) + loadedPropertyDef <- loadPropertyDefinition( + propertyIri = internalPropertyIri, + featureFactoryConfig = changePropertyLabelsOrCommentsRequest.featureFactoryConfig + ) unescapedNewLabelOrCommentPredicate: PredicateInfoV2 = PredicateInfoV2( predicateIri = changePropertyLabelsOrCommentsRequest.predicateToUpdate, @@ -3275,7 +3371,11 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon } maybeLoadedLinkValuePropertyDefFuture: Option[Future[PropertyInfoContentV2]] = maybeCurrentLinkValueReadPropertyInfo.map { - linkValueReadPropertyInfo => loadPropertyDefinition(linkValueReadPropertyInfo.entityInfoContent.propertyIri) + linkValueReadPropertyInfo => + loadPropertyDefinition( + propertyIri = linkValueReadPropertyInfo.entityInfoContent.propertyIri, + featureFactoryConfig = changePropertyLabelsOrCommentsRequest.featureFactoryConfig + ) } maybeLoadedLinkValuePropertyDef: Option[PropertyInfoContentV2] <- ActorUtil.optionFuture2FutureOption(maybeLoadedLinkValuePropertyDefFuture) @@ -3373,7 +3473,11 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon currentReadClassInfo: ReadClassInfoV2 = ontology.classes.getOrElse(internalClassIri, throw NotFoundException(s"Class ${changeClassLabelsOrCommentsRequest.classIri} not found")) // Check that the ontology exists and has not been updated by another user since the client last read it. - _ <- checkOntologyLastModificationDateBeforeUpdate(internalOntologyIri = internalOntologyIri, expectedLastModificationDate = changeClassLabelsOrCommentsRequest.lastModificationDate) + _ <- checkOntologyLastModificationDateBeforeUpdate( + internalOntologyIri = internalOntologyIri, + expectedLastModificationDate = changeClassLabelsOrCommentsRequest.lastModificationDate, + featureFactoryConfig = changeClassLabelsOrCommentsRequest.featureFactoryConfig + ) // Check that the new labels/comments are different from the current ones. @@ -3405,12 +3509,19 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon // Check that the ontology's last modification date was updated. - _ <- checkOntologyLastModificationDateAfterUpdate(internalOntologyIri = internalOntologyIri, expectedLastModificationDate = currentTime) + _ <- checkOntologyLastModificationDateAfterUpdate( + internalOntologyIri = internalOntologyIri, + expectedLastModificationDate = currentTime, + featureFactoryConfig = changeClassLabelsOrCommentsRequest.featureFactoryConfig + ) // Check that the data that was saved corresponds to the data that was submitted. To make this comparison, // we have to undo the SPARQL-escaping of the input. - loadedClassDef: ClassInfoContentV2 <- loadClassDefinition(internalClassIri) + loadedClassDef: ClassInfoContentV2 <- loadClassDefinition( + classIri = internalClassIri, + featureFactoryConfig = changeClassLabelsOrCommentsRequest.featureFactoryConfig + ) unescapedNewLabelOrCommentPredicate = PredicateInfoV2( predicateIri = changeClassLabelsOrCommentsRequest.predicateToUpdate, @@ -3504,16 +3615,21 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon * Loads a property definition from the triplestore and converts it to a [[PropertyInfoContentV2]]. * * @param propertyIri the IRI of the property to be loaded. + * @param featureFactoryConfig the feature factory configuration. * @return a [[PropertyInfoContentV2]] representing the property definition. */ - private def loadPropertyDefinition(propertyIri: SmartIri): Future[PropertyInfoContentV2] = { + private def loadPropertyDefinition(propertyIri: SmartIri, + featureFactoryConfig: FeatureFactoryConfig): Future[PropertyInfoContentV2] = { for { sparql <- Future(org.knora.webapi.messages.twirl.queries.sparql.v2.txt.getPropertyDefinition( triplestore = settings.triplestoreType, propertyIri = propertyIri ).toString()) - constructResponse <- (storeManager ? SparqlExtendedConstructRequest(sparql)).mapTo[SparqlExtendedConstructResponse] + constructResponse <- (storeManager ? SparqlExtendedConstructRequest( + sparql = sparql, + featureFactoryConfig = featureFactoryConfig + )).mapTo[SparqlExtendedConstructResponse] } yield constructResponseToPropertyDefinition( propertyIri = propertyIri, constructResponse = constructResponse @@ -3664,16 +3780,21 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon * Loads a class definition from the triplestore and converts it to a [[ClassInfoContentV2]]. * * @param classIri the IRI of the class to be loaded. + * @param featureFactoryConfig the feature factory configuration. * @return a [[ClassInfoContentV2]] representing the class definition. */ - private def loadClassDefinition(classIri: SmartIri): Future[ClassInfoContentV2] = { + private def loadClassDefinition(classIri: SmartIri, + featureFactoryConfig: FeatureFactoryConfig): Future[ClassInfoContentV2] = { for { sparql <- Future(org.knora.webapi.messages.twirl.queries.sparql.v2.txt.getClassDefinition( triplestore = settings.triplestoreType, classIri = classIri ).toString()) - constructResponse <- (storeManager ? SparqlExtendedConstructRequest(sparql)).mapTo[SparqlExtendedConstructResponse] + constructResponse <- (storeManager ? SparqlExtendedConstructRequest( + sparql = sparql, + featureFactoryConfig = featureFactoryConfig + )).mapTo[SparqlExtendedConstructResponse] } yield constructResponseToClassDefinition( classIri = classIri, constructResponse = constructResponse @@ -3871,12 +3992,16 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon * * @param internalOntologyIri the internal IRI of the ontology. * @param expectedLastModificationDate the last modification date that should now be attached to the ontology. + * @param featureFactoryConfig the feature factory configuration. * @return a failed Future if the expected last modification date is not found. */ - private def checkOntologyLastModificationDateBeforeUpdate(internalOntologyIri: SmartIri, expectedLastModificationDate: Instant): Future[Unit] = { + private def checkOntologyLastModificationDateBeforeUpdate(internalOntologyIri: SmartIri, + expectedLastModificationDate: Instant, + featureFactoryConfig: FeatureFactoryConfig): Future[Unit] = { checkOntologyLastModificationDate( internalOntologyIri = internalOntologyIri, expectedLastModificationDate = expectedLastModificationDate, + featureFactoryConfig = featureFactoryConfig, errorFun = throw EditConflictException(s"Ontology ${internalOntologyIri.toOntologySchema(ApiV2Complex)} has been modified by another user, please reload it and try again.") ) } @@ -3886,12 +4011,16 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon * * @param internalOntologyIri the internal IRI of the ontology. * @param expectedLastModificationDate the last modification date that should now be attached to the ontology. + * @param featureFactoryConfig the feature factory configuration. * @return a failed Future if the expected last modification date is not found. */ - private def checkOntologyLastModificationDateAfterUpdate(internalOntologyIri: SmartIri, expectedLastModificationDate: Instant): Future[Unit] = { + private def checkOntologyLastModificationDateAfterUpdate(internalOntologyIri: SmartIri, + expectedLastModificationDate: Instant, + featureFactoryConfig: FeatureFactoryConfig): Future[Unit] = { checkOntologyLastModificationDate( internalOntologyIri = internalOntologyIri, expectedLastModificationDate = expectedLastModificationDate, + featureFactoryConfig = featureFactoryConfig, errorFun = throw UpdateNotPerformedException(s"Ontology ${internalOntologyIri.toOntologySchema(ApiV2Complex)} was not updated. Please report this as a possible bug.") ) } @@ -3901,12 +4030,19 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon * * @param internalOntologyIri the internal IRI of the ontology. * @param expectedLastModificationDate the last modification date that the ontology is expected to have. + * @param featureFactoryConfig the feature factory configuration. * @param errorFun a function that throws an exception. It will be called if the expected last modification date is not found. * @return a failed Future if the expected last modification date is not found. */ - private def checkOntologyLastModificationDate(internalOntologyIri: SmartIri, expectedLastModificationDate: Instant, errorFun: => Nothing): Future[Unit] = { + private def checkOntologyLastModificationDate(internalOntologyIri: SmartIri, + expectedLastModificationDate: Instant, + featureFactoryConfig: FeatureFactoryConfig, + errorFun: => Nothing): Future[Unit] = { for { - existingOntologyMetadata: Option[OntologyMetadataV2] <- loadOntologyMetadata(internalOntologyIri) + existingOntologyMetadata: Option[OntologyMetadataV2] <- loadOntologyMetadata( + internalOntologyIri = internalOntologyIri, + featureFactoryConfig = featureFactoryConfig + ) _ = existingOntologyMetadata match { case Some(metadata) => 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 04ef7e54a4..0cd4d6f222 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 @@ -27,6 +27,7 @@ import akka.pattern._ import akka.stream.Materializer import org.knora.webapi._ import org.knora.webapi.exceptions._ +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.admin.responder.permissionsmessages.{DefaultObjectAccessPermissionsStringForResourceClassGetADM, DefaultObjectAccessPermissionsStringResponseADM, ResourceCreateOperation} import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectADM @@ -75,9 +76,9 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt * Receives a message of type [[ResourcesResponderRequestV2]], and returns an appropriate response message. */ def receive(msg: ResourcesResponderRequestV2) = msg match { - case ResourcesGetRequestV2(resIris, propertyIri, valueUuid, versionDate, targetSchema, schemaOptions, requestingUser) => getResourcesV2(resIris, propertyIri, valueUuid, versionDate, targetSchema, schemaOptions, requestingUser) - case ResourcesPreviewGetRequestV2(resIris, targetSchema, requestingUser) => getResourcePreviewV2(resIris, targetSchema, requestingUser) - case ResourceTEIGetRequestV2(resIri, textProperty, mappingIri, gravsearchTemplateIri, headerXSLTIri, requestingUser) => getResourceAsTeiV2(resIri, textProperty, mappingIri, gravsearchTemplateIri, headerXSLTIri, requestingUser) + case ResourcesGetRequestV2(resIris, propertyIri, valueUuid, versionDate, targetSchema, schemaOptions, featureFactoryConfig, requestingUser) => getResourcesV2(resIris, propertyIri, valueUuid, versionDate, targetSchema, schemaOptions, featureFactoryConfig, requestingUser) + case ResourcesPreviewGetRequestV2(resIris, targetSchema, featureFactoryConfig, requestingUser) => getResourcePreviewV2(resIris, targetSchema, featureFactoryConfig, requestingUser) + case ResourceTEIGetRequestV2(resIri, textProperty, mappingIri, gravsearchTemplateIri, headerXSLTIri, featureFactoryConfig, requestingUser) => getResourceAsTeiV2(resIri, textProperty, mappingIri, gravsearchTemplateIri, headerXSLTIri, featureFactoryConfig, requestingUser) case createResourceRequestV2: CreateResourceRequestV2 => createResourceV2(createResourceRequestV2) case updateResourceMetadataRequestV2: UpdateResourceMetadataRequestV2 => updateResourceMetadataV2(updateResourceMetadataRequestV2) case deleteOrEraseResourceRequestV2: DeleteOrEraseResourceRequestV2 => deleteOrEraseResourceV2(deleteOrEraseResourceRequestV2) @@ -108,13 +109,19 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt // Check link targets and list nodes that should exist. - _ <- checkStandoffLinkTargets(internalCreateResource.flatValues, createResourceRequestV2.requestingUser) + _ <- checkStandoffLinkTargets( + values = internalCreateResource.flatValues, + featureFactoryConfig = createResourceRequestV2.featureFactoryConfig, + requestingUser = createResourceRequestV2.requestingUser + ) + _ <- checkListNodes(internalCreateResource.flatValues, createResourceRequestV2.requestingUser) // Get the class IRIs of all the link targets in the request. linkTargetClasses: Map[IRI, SmartIri] <- getLinkTargetClasses( resourceIri: IRI, internalCreateResources = Seq(internalCreateResource), + featureFactoryConfig = createResourceRequestV2.featureFactoryConfig, requestingUser = createResourceRequestV2.requestingUser ) @@ -172,6 +179,7 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt defaultResourcePermissions = defaultResourcePermissions, defaultPropertyPermissions = defaultPropertyPermissions, creationDate = creationDate, + featureFactoryConfig = createResourceRequestV2.featureFactoryConfig, requestingUser = createResourceRequestV2.requestingUser ) @@ -194,6 +202,7 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt previewOfCreatedResource: ReadResourcesSequenceV2 <- verifyResource( resourceReadyToCreate = resourceReadyToCreate, projectIri = createResourceRequestV2.createResource.projectADM.id, + featureFactoryConfig = createResourceRequestV2.featureFactoryConfig, requestingUser = createResourceRequestV2.requestingUser ) } yield previewOfCreatedResource @@ -270,6 +279,7 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt resourcesSeq: ReadResourcesSequenceV2 <- getResourcePreviewV2( resourceIris = Seq(updateResourceMetadataRequestV2.resourceIri), targetSchema = ApiV2Complex, + featureFactoryConfig = updateResourceMetadataRequestV2.featureFactoryConfig, requestingUser = updateResourceMetadataRequestV2.requestingUser ) @@ -326,6 +336,7 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt updatedResourcesSeq: ReadResourcesSequenceV2 <- getResourcePreviewV2( resourceIris = Seq(updateResourceMetadataRequestV2.resourceIri), targetSchema = ApiV2Complex, + featureFactoryConfig = updateResourceMetadataRequestV2.featureFactoryConfig, requestingUser = updateResourceMetadataRequestV2.requestingUser ) @@ -405,6 +416,7 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt resourcesSeq: ReadResourcesSequenceV2 <- getResourcePreviewV2( resourceIris = Seq(deleteResourceV2.resourceIri), targetSchema = ApiV2Complex, + featureFactoryConfig = deleteResourceV2.featureFactoryConfig, requestingUser = deleteResourceV2.requestingUser ) @@ -492,6 +504,7 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt resourcesSeq: ReadResourcesSequenceV2 <- getResourcePreviewV2( resourceIris = Seq(eraseResourceV2.resourceIri), targetSchema = ApiV2Complex, + featureFactoryConfig = eraseResourceV2.featureFactoryConfig, requestingUser = eraseResourceV2.requestingUser ) @@ -583,6 +596,7 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt * @param defaultPropertyPermissions the default permissions to be given to the resource's values, if they do not * have custom permissions. This is a map of property IRIs to permission strings. * @param creationDate the versionDate to be attached to the resource and its values. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the user making the request. * @return a [[ResourceReadyToCreate]]. */ @@ -594,6 +608,7 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt defaultResourcePermissions: String, defaultPropertyPermissions: Map[SmartIri, String], creationDate: Instant, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM): Future[ResourceReadyToCreate] = { val resourceIDForErrorMsg: String = clientResourceIDs.get(resourceIri).map(resourceID => s"In resource '$resourceID': ").getOrElse("") @@ -653,7 +668,11 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt resourcePermissions: String <- internalCreateResource.permissions match { case Some(permissionStr) => for { - validatedCustomPermissions: String <- PermissionUtilADM.validatePermissions(permissionLiteral = permissionStr, responderManager = responderManager) + validatedCustomPermissions: String <- PermissionUtilADM.validatePermissions( + permissionLiteral = permissionStr, + featureFactoryConfig = featureFactoryConfig, + responderManager = responderManager + ) // Is the requesting user a system admin, or an admin of this project? _ = if (!(requestingUser.permissions.isProjectAdmin(internalCreateResource.projectADM.id) || requestingUser.permissions.isSystemAdmin)) { @@ -683,6 +702,7 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt values = internalCreateResource.values, defaultPropertyPermissions = defaultPropertyPermissions, resourceIDForErrorMsg = resourceIDForErrorMsg, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) @@ -714,10 +734,14 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt * to be created. * * @param internalCreateResources the resources to be created. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the user making the request. * @return a map of resource IRIs to class IRIs. */ - private def getLinkTargetClasses(resourceIri: IRI, internalCreateResources: Seq[CreateResourceV2], requestingUser: UserADM): Future[Map[IRI, SmartIri]] = { + private def getLinkTargetClasses(resourceIri: IRI, + internalCreateResources: Seq[CreateResourceV2], + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[Map[IRI, SmartIri]] = { // Get the IRIs of the new and existing resources that are targets of links. val (existingTargetIris: Set[IRI], newTargets: Set[IRI]) = internalCreateResources.flatMap(_.flatValues).foldLeft((Set.empty[IRI], Set.empty[IRI])) { case ((accExisting: Set[IRI], accNew: Set[IRI]), valueToCreate: CreateValueInNewResourceV2) => @@ -743,6 +767,7 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt existingTargets: ReadResourcesSequenceV2 <- getResourcePreviewV2( resourceIris = existingTargetIris.toSeq, targetSchema = ApiV2Complex, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) @@ -863,10 +888,13 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt * values. For each link, if the target is expected to exist, checks that it exists and that the user has * permission to see it. * - * @param values the values to be checked. - * @param requestingUser the user making the request. + * @param values the values to be checked. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ - private def checkStandoffLinkTargets(values: Iterable[CreateValueInNewResourceV2], requestingUser: UserADM): Future[Unit] = { + private def checkStandoffLinkTargets(values: Iterable[CreateValueInNewResourceV2], + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[Unit] = { val standoffLinkTargetsThatShouldExist: Set[IRI] = values.foldLeft(Set.empty[IRI]) { case (acc: Set[IRI], valueToCreate: CreateValueInNewResourceV2) => valueToCreate.valueContent match { @@ -875,7 +903,12 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt } } - getResourcePreviewV2(standoffLinkTargetsThatShouldExist.toSeq, targetSchema = ApiV2Complex, requestingUser).map(_ => ()) + getResourcePreviewV2( + resourceIris = standoffLinkTargetsThatShouldExist.toSeq, + targetSchema = ApiV2Complex, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ).map(_ => ()) } /** @@ -914,6 +947,7 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt values: Map[SmartIri, Seq[CreateValueInNewResourceV2]], defaultPropertyPermissions: Map[SmartIri, String], resourceIDForErrorMsg: String, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM): Future[Map[SmartIri, Seq[GenerateSparqlForValueInNewResourceV2]]] = { val propertyValuesWithValidatedPermissionsFutures: Map[SmartIri, Seq[Future[GenerateSparqlForValueInNewResourceV2]]] = values.map { case (propertyIri: SmartIri, valuesToCreate: Seq[CreateValueInNewResourceV2]) => @@ -924,7 +958,11 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt case Some(permissionStr: String) => // Yes. Validate and reformat them. for { - validatedCustomPermissions <- PermissionUtilADM.validatePermissions(permissionLiteral = permissionStr, responderManager = responderManager) + validatedCustomPermissions <- PermissionUtilADM.validatePermissions( + permissionLiteral = permissionStr, + featureFactoryConfig = featureFactoryConfig, + responderManager = responderManager + ) // Is the requesting user a system admin, or an admin of this project? _ = if (!(requestingUser.permissions.isProjectAdmin(project.id) || requestingUser.permissions.isSystemAdmin)) { @@ -1028,11 +1066,13 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt * * @param resourceReadyToCreate the resource that should have been created. * @param projectIri the IRI of the project in which the resource should have been created. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the user that attempted to create the resource. * @return a preview of the resource that was created. */ private def verifyResource(resourceReadyToCreate: ResourceReadyToCreate, projectIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM): Future[ReadResourcesSequenceV2] = { val resourceIri = resourceReadyToCreate.sparqlTemplateResourceToCreate.resourceIri @@ -1041,6 +1081,7 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt resourceIris = Seq(resourceIri), requestingUser = requestingUser, targetSchema = ApiV2Complex, + featureFactoryConfig = featureFactoryConfig, schemaOptions = SchemaOptions.ForStandoffWithTextValues ) @@ -1145,13 +1186,14 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt /** * Gets the requested resources from the triplestore. * - * @param resourceIris the Iris of the requested resources. - * @param preview `true` if a preview of the resource is requested. - * @param propertyIri if defined, requests only the values of the specified explicit property. - * @param valueUuid if defined, requests only the value with the specified UUID. - * @param versionDate if defined, requests the state of the resources at the specified time in the past. - * Cannot be used in conjunction with `preview`. - * @param queryStandoff `true` if standoff should be queried. + * @param resourceIris the Iris of the requested resources. + * @param preview `true` if a preview of the resource is requested. + * @param propertyIri if defined, requests only the values of the specified explicit property. + * @param valueUuid if defined, requests only the value with the specified UUID. + * @param versionDate if defined, requests the state of the resources at the specified time in the past. + * Cannot be used in conjunction with `preview`. + * @param queryStandoff `true` if standoff should be queried. + * @param featureFactoryConfig the feature factory configuration. * @return a map of resource IRIs to RDF data. */ private def getResourcesFromTriplestore(resourceIris: Seq[IRI], @@ -1160,6 +1202,7 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt valueUuid: Option[UUID], versionDate: Option[Instant], queryStandoff: Boolean, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM): Future[ConstructResponseUtilV2.MainResourcesAndValueRdfData] = { // eliminate duplicate Iris val resourceIrisDistinct: Seq[IRI] = resourceIris.distinct @@ -1187,7 +1230,10 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt // _ = println(resourceRequestSparql) - resourceRequestResponse: SparqlExtendedConstructResponse <- (storeManager ? SparqlExtendedConstructRequest(resourceRequestSparql)).mapTo[SparqlExtendedConstructResponse] + resourceRequestResponse: SparqlExtendedConstructResponse <- (storeManager ? SparqlExtendedConstructRequest( + sparql = resourceRequestSparql, + featureFactoryConfig = featureFactoryConfig + )).mapTo[SparqlExtendedConstructResponse] // separate resources and values mainResourcesAndValueRdfData: ConstructResponseUtilV2.MainResourcesAndValueRdfData = ConstructResponseUtilV2.splitMainResourcesAndValueRdfData( @@ -1201,13 +1247,14 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt /** * Get one or several resources and return them as a sequence. * - * @param resourceIris the IRIs of the resources to be queried. - * @param propertyIri if defined, requests only the values of the specified explicit property. - * @param valueUuid if defined, requests only the value with the specified UUID. - * @param versionDate if defined, requests the state of the resources at the specified time in the past. - * @param targetSchema the target API schema. - * @param schemaOptions the schema options submitted with the request. - * @param requestingUser the user making the request. + * @param resourceIris the IRIs of the resources to be queried. + * @param propertyIri if defined, requests only the values of the specified explicit property. + * @param valueUuid if defined, requests only the value with the specified UUID. + * @param versionDate if defined, requests the state of the resources at the specified time in the past. + * @param targetSchema the target API schema. + * @param schemaOptions the schema options submitted with the request. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return a [[ReadResourcesSequenceV2]]. */ private def getResourcesV2(resourceIris: Seq[IRI], @@ -1216,6 +1263,7 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt versionDate: Option[Instant] = None, targetSchema: ApiV2Schema, schemaOptions: Set[SchemaOption], + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM): Future[ReadResourcesSequenceV2] = { // eliminate duplicate Iris val resourceIrisDistinct: Seq[IRI] = resourceIris.distinct @@ -1233,12 +1281,17 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt valueUuid = valueUuid, versionDate = versionDate, queryStandoff = queryStandoff, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) // If we're querying standoff, get XML-to standoff mappings. mappingsAsMap: Map[IRI, MappingAndXSLTransformation] <- if (queryStandoff) { - getMappingsFromQueryResultsSeparated(mainResourcesAndValueRdfData.resources, requestingUser) + getMappingsFromQueryResultsSeparated( + queryResultsSeparated = mainResourcesAndValueRdfData.resources, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) } else { FastFuture.successful(Map.empty[IRI, MappingAndXSLTransformation]) } @@ -1254,6 +1307,7 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt responderManager = responderManager, targetSchema = targetSchema, settings = settings, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) @@ -1278,11 +1332,15 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt /** * Get the preview of a resource. * - * @param resourceIris the resource to query for. - * @param requestingUser the the client making the request. + * @param resourceIris the resource to query for. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the the user making the request. * @return a [[ReadResourcesSequenceV2]]. */ - private def getResourcePreviewV2(resourceIris: Seq[IRI], targetSchema: ApiV2Schema, requestingUser: UserADM): Future[ReadResourcesSequenceV2] = { + private def getResourcePreviewV2(resourceIris: Seq[IRI], + targetSchema: ApiV2Schema, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[ReadResourcesSequenceV2] = { // eliminate duplicate Iris val resourceIrisDistinct: Seq[IRI] = resourceIris.distinct @@ -1295,6 +1353,7 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt valueUuid = None, versionDate = None, queryStandoff = false, // This has no effect, because we are not querying values. + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) @@ -1309,6 +1368,7 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt responderManager = responderManager, targetSchema = targetSchema, settings = settings, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) @@ -1323,13 +1383,23 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt * Obtains a Gravsearch template from Sipi. * * @param gravsearchTemplateIri the Iri of the resource representing the Gravsearch template. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the user making the request. * @return the Gravsearch template. */ - private def getGravsearchTemplate(gravsearchTemplateIri: IRI, requestingUser: UserADM): Future[String] = { + private def getGravsearchTemplate(gravsearchTemplateIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[String] = { val gravsearchUrlFuture = for { - resources: ReadResourcesSequenceV2 <- getResourcesV2(resourceIris = Vector(gravsearchTemplateIri), targetSchema = ApiV2Complex, schemaOptions = Set(MarkupAsStandoff), requestingUser = requestingUser) + resources: ReadResourcesSequenceV2 <- getResourcesV2( + resourceIris = Vector(gravsearchTemplateIri), + targetSchema = ApiV2Complex, + schemaOptions = Set(MarkupAsStandoff), + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) + resource: ReadResourceV2 = resources.toResource(gravsearchTemplateIri) _ = if (resource.resourceClassIri.toString != OntologyConstants.KnoraBase.TextRepresentation) { @@ -1381,10 +1451,17 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt * @param mappingIri the Iri of the mapping to be used to convert standoff to XML, if a custom mapping is provided. The mapping is expected to contain an XSL transformation. * @param gravsearchTemplateIri the Iri of the Gravsearch template to query for the metadata for the TEI header. The resource Iri is expected to be represented by the placeholder '$resourceIri' in a BIND. * @param headerXSLTIri the Iri of the XSL template to convert the metadata properties to the TEI header. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the user making the request. * @return a [[ResourceTEIGetResponseV2]]. */ - private def getResourceAsTeiV2(resourceIri: IRI, textProperty: SmartIri, mappingIri: Option[IRI], gravsearchTemplateIri: Option[IRI], headerXSLTIri: Option[String], requestingUser: UserADM): Future[ResourceTEIGetResponseV2] = { + private def getResourceAsTeiV2(resourceIri: IRI, + textProperty: SmartIri, + mappingIri: Option[IRI], + gravsearchTemplateIri: Option[IRI], + headerXSLTIri: Option[String], + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[ResourceTEIGetResponseV2] = { /** * Extract the text value to be converted to TEI/XML. @@ -1469,7 +1546,11 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt for { // get the template - template <- getGravsearchTemplate(gravsearchTemplateIri.get, requestingUser) + template <- getGravsearchTemplate( + gravsearchTemplateIri = gravsearchTemplateIri.get, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) // insert actual resource Iri, replacing the placeholder gravsearchQuery = template.replace("$resourceIri", resourceIri) @@ -1482,7 +1563,9 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt constructQuery = constructQuery, targetSchema = ApiV2Complex, schemaOptions = SchemaOptions.ForStandoffWithTextValues, - requestingUser = requestingUser)).mapTo[ReadResourcesSequenceV2] + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + )).mapTo[ReadResourcesSequenceV2] } yield gravSearchResponse.toResource(resourceIri) } else { @@ -1497,8 +1580,9 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt resourceIris = Vector(resourceIri), targetSchema = ApiV2Complex, schemaOptions = SchemaOptions.ForStandoffWithTextValues, - requestingUser = requestingUser).map(_.toResource(resourceIri)) - + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ).map(_.toResource(resourceIri)) } yield resource } @@ -1516,7 +1600,11 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt // get the XSL transformation for the TEI header headerXSLT: Option[String] <- headerXSLTIri match { case Some(headerIri) => - val teiHeaderXsltRequest = GetXSLTransformationRequestV2(xsltTextRepresentationIri = headerIri, requestingUser = requestingUser) + val teiHeaderXsltRequest = GetXSLTransformationRequestV2( + xsltTextRepresentationIri = headerIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) for { xslTransformation: GetXSLTransformationResponseV2 <- (responderManager ? teiHeaderXsltRequest).mapTo[GetXSLTransformationResponseV2] @@ -1537,7 +1625,11 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt } // get mapping to convert standoff markup to TEI/XML - teiMapping: GetMappingResponseV2 <- (responderManager ? GetMappingRequestV2(mappingIri = mappingToBeApplied, requestingUser = requestingUser)).mapTo[GetMappingResponseV2] + teiMapping: GetMappingResponseV2 <- (responderManager ? GetMappingRequestV2( + mappingIri = mappingToBeApplied, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + )).mapTo[GetMappingResponseV2] // get XSLT from mapping for the TEI body bodyXslt: String <- teiMapping.mappingIri match { @@ -1555,7 +1647,11 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt case Some(xslTransformationIri) => // get XSLT for the TEI body. - val teiBodyXsltRequest = GetXSLTransformationRequestV2(xsltTextRepresentationIri = xslTransformationIri, requestingUser = requestingUser) + val teiBodyXsltRequest = GetXSLTransformationRequestV2( + xsltTextRepresentationIri = xslTransformationIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) for { xslTransformation: GetXSLTransformationResponseV2 <- (responderManager ? teiBodyXsltRequest).mapTo[GetXSLTransformationResponseV2] @@ -1894,6 +1990,7 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt resourcePreviewResponse: ReadResourcesSequenceV2 <- getResourcePreviewV2( resourceIris = Seq(resourceHistoryRequest.resourceIri), targetSchema = ApiV2Complex, + featureFactoryConfig = resourceHistoryRequest.featureFactoryConfig, requestingUser = resourceHistoryRequest.requestingUser ) diff --git a/webapi/src/main/scala/org/knora/webapi/responders/v2/ResponderWithStandoffV2.scala b/webapi/src/main/scala/org/knora/webapi/responders/v2/ResponderWithStandoffV2.scala index 8f1f2ecb1f..979f779c41 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/v2/ResponderWithStandoffV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/v2/ResponderWithStandoffV2.scala @@ -21,6 +21,7 @@ package org.knora.webapi.responders.v2 import akka.pattern._ import org.knora.webapi.IRI +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.util.ConstructResponseUtilV2.{MappingAndXSLTransformation, ResourceWithValueRdfData} import org.knora.webapi.messages.util.{ConstructResponseUtilV2, ResponderData} @@ -38,10 +39,13 @@ abstract class ResponderWithStandoffV2(responderData: ResponderData) extends Res * Gets mappings referred to in query results [[Map[IRI, ResourceWithValueRdfData]]]. * * @param queryResultsSeparated query results referring to mappings. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the user making the request. * @return the referred mappings. */ - protected def getMappingsFromQueryResultsSeparated(queryResultsSeparated: Map[IRI, ResourceWithValueRdfData], requestingUser: UserADM): Future[Map[IRI, MappingAndXSLTransformation]] = { + protected def getMappingsFromQueryResultsSeparated(queryResultsSeparated: Map[IRI, ResourceWithValueRdfData], + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[Map[IRI, MappingAndXSLTransformation]] = { // collect the Iris of the mappings referred to in the resources' text values val mappingIris: Set[IRI] = queryResultsSeparated.flatMap { @@ -53,7 +57,11 @@ abstract class ResponderWithStandoffV2(responderData: ResponderData) extends Res val mappingResponsesFuture: Vector[Future[GetMappingResponseV2]] = mappingIris.map { mappingIri: IRI => for { - mappingResponse: GetMappingResponseV2 <- (responderManager ? GetMappingRequestV2(mappingIri = mappingIri, requestingUser = requestingUser)).mapTo[GetMappingResponseV2] + mappingResponse: GetMappingResponseV2 <- (responderManager ? GetMappingRequestV2( + mappingIri = mappingIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + )).mapTo[GetMappingResponseV2] } yield mappingResponse }.toVector @@ -68,7 +76,11 @@ abstract class ResponderWithStandoffV2(responderData: ResponderData) extends Res // if given, get the default XSL transformation xsltOption: Option[String] <- if (mapping.mapping.defaultXSLTransformation.nonEmpty) { for { - xslTransformation: GetXSLTransformationResponseV2 <- (responderManager ? GetXSLTransformationRequestV2(mapping.mapping.defaultXSLTransformation.get, requestingUser = requestingUser)).mapTo[GetXSLTransformationResponseV2] + xslTransformation: GetXSLTransformationResponseV2 <- (responderManager ? GetXSLTransformationRequestV2( + mapping.mapping.defaultXSLTransformation.get, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + )).mapTo[GetXSLTransformationResponseV2] } yield Some(xslTransformation.xslt) } else { Future(None) 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 a147a1a863..ec5cb5bc96 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 @@ -23,6 +23,7 @@ import akka.http.scaladsl.util.FastFuture import akka.pattern._ import org.knora.webapi._ import org.knora.webapi.exceptions.{AssertionException, BadRequestException, GravsearchException, InconsistentTriplestoreDataException} +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.store.triplestoremessages._ @@ -52,12 +53,12 @@ class SearchResponderV2(responderData: ResponderData) extends ResponderWithStand * Receives a message of type [[SearchResponderRequestV2]], and returns an appropriate response message. */ def receive(msg: SearchResponderRequestV2): Future[KnoraJsonLDResponseV2] = msg match { - case FullTextSearchCountRequestV2(searchValue, limitToProject, limitToResourceClass, limitToStandoffClass, requestingUser) => fulltextSearchCountV2(searchValue, limitToProject, limitToResourceClass, limitToStandoffClass, requestingUser) - case FulltextSearchRequestV2(searchValue, offset, limitToProject, limitToResourceClass, limitToStandoffClass, targetSchema, schemaOptions, requestingUser) => fulltextSearchV2(searchValue, offset, limitToProject, limitToResourceClass, limitToStandoffClass, targetSchema, schemaOptions, requestingUser) - case GravsearchCountRequestV2(query, requestingUser) => gravsearchCountV2(inputQuery = query, requestingUser = requestingUser) - case GravsearchRequestV2(query, targetSchema, schemaOptions, requestingUser) => gravsearchV2(inputQuery = query, targetSchema = targetSchema, schemaOptions = schemaOptions, requestingUser = requestingUser) - case SearchResourceByLabelCountRequestV2(searchValue, limitToProject, limitToResourceClass, requestingUser) => searchResourcesByLabelCountV2(searchValue, limitToProject, limitToResourceClass, requestingUser) - case SearchResourceByLabelRequestV2(searchValue, offset, limitToProject, limitToResourceClass, targetSchema, requestingUser) => searchResourcesByLabelV2(searchValue, offset, limitToProject, limitToResourceClass, targetSchema, requestingUser) + case FullTextSearchCountRequestV2(searchValue, limitToProject, limitToResourceClass, limitToStandoffClass, featureFactoryConfig, requestingUser) => fulltextSearchCountV2(searchValue, limitToProject, limitToResourceClass, limitToStandoffClass, featureFactoryConfig, requestingUser) + case FulltextSearchRequestV2(searchValue, offset, limitToProject, limitToResourceClass, limitToStandoffClass, targetSchema, schemaOptions, featureFactoryConfig, requestingUser) => fulltextSearchV2(searchValue, offset, limitToProject, limitToResourceClass, limitToStandoffClass, targetSchema, schemaOptions, featureFactoryConfig, requestingUser) + case GravsearchCountRequestV2(query, featureFactoryConfig, requestingUser) => gravsearchCountV2(inputQuery = query, featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser) + case GravsearchRequestV2(query, targetSchema, schemaOptions, featureFactoryConfig, requestingUser) => gravsearchV2(inputQuery = query, targetSchema = targetSchema, schemaOptions = schemaOptions, featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser) + case SearchResourceByLabelCountRequestV2(searchValue, limitToProject, limitToResourceClass, featureFactoryConfig, requestingUser) => searchResourcesByLabelCountV2(searchValue, limitToProject, limitToResourceClass, featureFactoryConfig, requestingUser) + case SearchResourceByLabelRequestV2(searchValue, offset, limitToProject, limitToResourceClass, targetSchema, featureFactoryConfig, requestingUser) => searchResourcesByLabelV2(searchValue, offset, limitToProject, limitToResourceClass, targetSchema, featureFactoryConfig, requestingUser) case resourcesInProjectGetRequestV2: SearchResourcesByProjectAndClassRequestV2 => searchResourcesByProjectAndClassV2(resourcesInProjectGetRequestV2) case other => handleUnexpectedMessage(other, log, this.getClass.getName) } @@ -71,6 +72,7 @@ class SearchResponderV2(responderData: ResponderData) extends ResponderWithStand * @param searchValue the values to search for. * @param limitToProject limit search to given project. * @param limitToResourceClass limit search to given resource class. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the the client making the request. * @return a [[ResourceCountV2]] representing the number of resources that have been found. */ @@ -78,6 +80,7 @@ class SearchResponderV2(responderData: ResponderData) extends ResponderWithStand limitToProject: Option[IRI], limitToResourceClass: Option[SmartIri], limitToStandoffClass: Option[SmartIri], + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM): Future[ResourceCountV2] = { val searchTerms: LuceneQueryString = LuceneQueryString(searchValue) @@ -118,6 +121,7 @@ class SearchResponderV2(responderData: ResponderData) extends ResponderWithStand * @param limitToResourceClass limit search to given resource class. * @param targetSchema the target API schema. * @param schemaOptions the schema options submitted with the request. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the the client making the request. * @return a [[ReadResourcesSequenceV2]] representing the resources that have been found. */ @@ -128,6 +132,7 @@ class SearchResponderV2(responderData: ResponderData) extends ResponderWithStand limitToStandoffClass: Option[SmartIri], targetSchema: ApiV2Schema, schemaOptions: Set[SchemaOption], + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM): Future[ReadResourcesSequenceV2] = { import org.knora.webapi.messages.util.search.FullTextMainQueryGenerator.FullTextSearchConstants @@ -216,7 +221,10 @@ class SearchResponderV2(responderData: ResponderData) extends ResponderWithStand // println(triplestoreSpecificQuery.toSparql) for { - searchResponse: SparqlExtendedConstructResponse <- (storeManager ? SparqlExtendedConstructRequest(triplestoreSpecificQuery.toSparql)).mapTo[SparqlExtendedConstructResponse] + searchResponse: SparqlExtendedConstructResponse <- (storeManager ? SparqlExtendedConstructRequest( + sparql = triplestoreSpecificQuery.toSparql, + featureFactoryConfig = featureFactoryConfig + )).mapTo[SparqlExtendedConstructResponse] // separate resources and value objects queryResultsSep: ConstructResponseUtilV2.MainResourcesAndValueRdfData = ConstructResponseUtilV2.splitMainResourcesAndValueRdfData(constructQueryResults = searchResponse, requestingUser = requestingUser) @@ -235,7 +243,11 @@ class SearchResponderV2(responderData: ResponderData) extends ResponderWithStand // If we're querying standoff, get XML-to standoff mappings. mappingsAsMap: Map[IRI, MappingAndXSLTransformation] <- if (queryStandoff) { - getMappingsFromQueryResultsSeparated(mainResourcesAndValueRdfData.resources, requestingUser) + getMappingsFromQueryResultsSeparated( + queryResultsSeparated = mainResourcesAndValueRdfData.resources, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) } else { FastFuture.successful(Map.empty[IRI, MappingAndXSLTransformation]) } @@ -253,6 +265,7 @@ class SearchResponderV2(responderData: ResponderData) extends ResponderWithStand responderManager = responderManager, settings = settings, targetSchema = targetSchema, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) @@ -263,11 +276,15 @@ class SearchResponderV2(responderData: ResponderData) extends ResponderWithStand /** * Performs a count query for a Gravsearch query provided by the user. * - * @param inputQuery a Gravsearch query provided by the client. - * @param requestingUser the the client making the request. + * @param inputQuery a Gravsearch query provided by the client. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the the client making the request. * @return a [[ResourceCountV2]] representing the number of resources that have been found. */ - private def gravsearchCountV2(inputQuery: ConstructQuery, apiSchema: ApiV2Schema = ApiV2Simple, requestingUser: UserADM): Future[ResourceCountV2] = { + private def gravsearchCountV2(inputQuery: ConstructQuery, + apiSchema: ApiV2Schema = ApiV2Simple, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[ResourceCountV2] = { // make sure that OFFSET is 0 if (inputQuery.offset != 0) throw GravsearchException(s"OFFSET must be 0 for a count query, but ${inputQuery.offset} given") @@ -340,15 +357,17 @@ class SearchResponderV2(responderData: ResponderData) extends ResponderWithStand /** * Performs a search using a Gravsearch query provided by the client. * - * @param inputQuery a Gravsearch query provided by the client. - * @param targetSchema the target API schema. - * @param schemaOptions the schema options submitted with the request. - * @param requestingUser the the client making the request. + * @param inputQuery a Gravsearch query provided by the client. + * @param targetSchema the target API schema. + * @param schemaOptions the schema options submitted with the request. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the the client making the request. * @return a [[ReadResourcesSequenceV2]] representing the resources that have been found. */ private def gravsearchV2(inputQuery: ConstructQuery, targetSchema: ApiV2Schema, schemaOptions: Set[SchemaOption], + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM): Future[ReadResourcesSequenceV2] = { import org.knora.webapi.messages.util.search.gravsearch.mainquery.GravsearchMainQueryGenerator @@ -494,7 +513,10 @@ class SearchResponderV2(responderData: ResponderData) extends ResponderWithStand log.debug(triplestoreSpecificMainQuerySparql) for { - mainQueryResponse: SparqlExtendedConstructResponse <- (storeManager ? SparqlExtendedConstructRequest(triplestoreSpecificMainQuerySparql)).mapTo[SparqlExtendedConstructResponse] + mainQueryResponse: SparqlExtendedConstructResponse <- (storeManager ? SparqlExtendedConstructRequest( + sparql = triplestoreSpecificMainQuerySparql, + featureFactoryConfig = featureFactoryConfig, + )).mapTo[SparqlExtendedConstructResponse] // Filter out values that the user doesn't have permission to see. queryResultsFilteredForPermissions: ConstructResponseUtilV2.MainResourcesAndValueRdfData = ConstructResponseUtilV2.splitMainResourcesAndValueRdfData( @@ -527,7 +549,11 @@ class SearchResponderV2(responderData: ResponderData) extends ResponderWithStand // If we're querying standoff, get XML-to standoff mappings. mappingsAsMap: Map[IRI, MappingAndXSLTransformation] <- if (queryStandoff) { - getMappingsFromQueryResultsSeparated(mainQueryResults.resources, requestingUser) + getMappingsFromQueryResultsSeparated( + queryResultsSeparated = mainQueryResults.resources, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) } else { FastFuture.successful(Map.empty[IRI, MappingAndXSLTransformation]) } @@ -543,6 +569,7 @@ class SearchResponderV2(responderData: ResponderData) extends ResponderWithStand responderManager = responderManager, settings = settings, targetSchema = targetSchema, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) @@ -653,14 +680,21 @@ class SearchResponderV2(responderData: ResponderData) extends ResponderWithStand // _ = println(resourceRequestSparql) - resourceRequestResponse: SparqlExtendedConstructResponse <- (storeManager ? SparqlExtendedConstructRequest(resourceRequestSparql)).mapTo[SparqlExtendedConstructResponse] + resourceRequestResponse: SparqlExtendedConstructResponse <- (storeManager ? SparqlExtendedConstructRequest( + sparql = resourceRequestSparql, + featureFactoryConfig = resourcesInProjectGetRequestV2.featureFactoryConfig + )).mapTo[SparqlExtendedConstructResponse] // separate resources and values mainResourcesAndValueRdfData: ConstructResponseUtilV2.MainResourcesAndValueRdfData = ConstructResponseUtilV2.splitMainResourcesAndValueRdfData(constructQueryResults = resourceRequestResponse, requestingUser = resourcesInProjectGetRequestV2.requestingUser) // If we're querying standoff, get XML-to standoff mappings. mappings: Map[IRI, MappingAndXSLTransformation] <- if (queryStandoff) { - getMappingsFromQueryResultsSeparated(mainResourcesAndValueRdfData.resources, resourcesInProjectGetRequestV2.requestingUser) + getMappingsFromQueryResultsSeparated( + mainResourcesAndValueRdfData.resources, + featureFactoryConfig = resourcesInProjectGetRequestV2.featureFactoryConfig, + resourcesInProjectGetRequestV2.requestingUser + ) } else { FastFuture.successful(Map.empty[IRI, MappingAndXSLTransformation]) } @@ -677,6 +711,7 @@ class SearchResponderV2(responderData: ResponderData) extends ResponderWithStand responderManager = responderManager, targetSchema = resourcesInProjectGetRequestV2.targetSchema, settings = settings, + featureFactoryConfig = resourcesInProjectGetRequestV2.featureFactoryConfig, requestingUser = resourcesInProjectGetRequestV2.requestingUser ) } yield readResourcesSequence @@ -692,10 +727,15 @@ class SearchResponderV2(responderData: ResponderData) extends ResponderWithStand * @param searchValue the values to search for. * @param limitToProject limit search to given project. * @param limitToResourceClass limit search to given resource class. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the the client making the request. * @return a [[ReadResourcesSequenceV2]] representing the resources that have been found. */ - private def searchResourcesByLabelCountV2(searchValue: String, limitToProject: Option[IRI], limitToResourceClass: Option[SmartIri], requestingUser: UserADM): Future[ResourceCountV2] = { + private def searchResourcesByLabelCountV2(searchValue: String, + limitToProject: Option[IRI], + limitToResourceClass: Option[SmartIri], + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[ResourceCountV2] = { val searchPhrase: MatchStringWhileTyping = MatchStringWhileTyping(searchValue) for { @@ -735,6 +775,7 @@ class SearchResponderV2(responderData: ResponderData) extends ResponderWithStand * @param limitToProject limit search to given project. * @param limitToResourceClass limit search to given resource class. * @param targetSchema the schema of the response. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the the client making the request. * @return a [[ReadResourcesSequenceV2]] representing the resources that have been found. */ @@ -743,6 +784,7 @@ class SearchResponderV2(responderData: ResponderData) extends ResponderWithStand limitToProject: Option[IRI], limitToResourceClass: Option[SmartIri], targetSchema: ApiV2Schema, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM): Future[ReadResourcesSequenceV2] = { val searchPhrase: MatchStringWhileTyping = MatchStringWhileTyping(searchValue) @@ -760,7 +802,10 @@ class SearchResponderV2(responderData: ResponderData) extends ResponderWithStand // _ = println(searchResourceByLabelSparql) - searchResourceByLabelResponse: SparqlExtendedConstructResponse <- (storeManager ? SparqlExtendedConstructRequest(searchResourceByLabelSparql)).mapTo[SparqlExtendedConstructResponse] + searchResourceByLabelResponse: SparqlExtendedConstructResponse <- (storeManager ? SparqlExtendedConstructRequest( + sparql = searchResourceByLabelSparql, + featureFactoryConfig = featureFactoryConfig + )).mapTo[SparqlExtendedConstructResponse] // collect the IRIs of main resources returned mainResourceIris: Set[IRI] = searchResourceByLabelResponse.statements.foldLeft(Set.empty[IRI]) { @@ -800,6 +845,7 @@ class SearchResponderV2(responderData: ResponderData) extends ResponderWithStand responderManager = responderManager, targetSchema = targetSchema, settings = settings, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) diff --git a/webapi/src/main/scala/org/knora/webapi/responders/v2/StandoffResponderV2.scala b/webapi/src/main/scala/org/knora/webapi/responders/v2/StandoffResponderV2.scala index d28e8a7d3d..cc37ec0855 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/v2/StandoffResponderV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/v2/StandoffResponderV2.scala @@ -30,6 +30,7 @@ import javax.xml.transform.stream.StreamSource import javax.xml.validation.{Schema, SchemaFactory, Validator => JValidator} import org.knora.webapi._ import org.knora.webapi.exceptions._ +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.admin.responder.projectsmessages.{ProjectADM, ProjectGetADM, ProjectIdentifierADM} import org.knora.webapi.messages.admin.responder.usersmessages.UserADM @@ -73,9 +74,9 @@ class StandoffResponderV2(responderData: ResponderData) extends Responder(respon def receive(msg: StandoffResponderRequestV2) = msg match { case getStandoffPageRequestV2: GetStandoffPageRequestV2 => getStandoffV2(getStandoffPageRequestV2) case getRemainingStandoffFromTextValueRequestV2: GetRemainingStandoffFromTextValueRequestV2 => getRemainingStandoffFromTextValueV2(getRemainingStandoffFromTextValueRequestV2) - case CreateMappingRequestV2(metadata, xml, requestingUser, uuid) => createMappingV2(xml.xml, metadata.label, metadata.projectIri, metadata.mappingName, requestingUser, uuid) - case GetMappingRequestV2(mappingIri, requestingUser) => getMappingV2(mappingIri, requestingUser) - case GetXSLTransformationRequestV2(xsltTextReprIri, requestingUser) => getXSLTransformation(xsltTextReprIri, requestingUser) + case CreateMappingRequestV2(metadata, xml, featureFactoryConfig, requestingUser, uuid) => createMappingV2(xml.xml, metadata.label, metadata.projectIri, metadata.mappingName, featureFactoryConfig, requestingUser, uuid) + case GetMappingRequestV2(mappingIri, featureFactoryConfig, requestingUser) => getMappingV2(mappingIri, featureFactoryConfig, requestingUser) + case GetXSLTransformationRequestV2(xsltTextReprIri, featureFactoryConfig, requestingUser) => getXSLTransformation(xsltTextReprIri, featureFactoryConfig, requestingUser) case other => handleUnexpectedMessage(other, log, this.getClass.getName) } @@ -103,7 +104,10 @@ class StandoffResponderV2(responderData: ResponderData) extends Responder(respon // standoffPageStartTime = System.currentTimeMillis() - resourceRequestResponse: SparqlExtendedConstructResponse <- (storeManager ? SparqlExtendedConstructRequest(resourceRequestSparql)).mapTo[SparqlExtendedConstructResponse] + resourceRequestResponse: SparqlExtendedConstructResponse <- (storeManager ? SparqlExtendedConstructRequest( + sparql = resourceRequestSparql, + featureFactoryConfig = getStandoffRequestV2.featureFactoryConfig + )).mapTo[SparqlExtendedConstructResponse] // standoffPageEndTime = System.currentTimeMillis() @@ -123,6 +127,7 @@ class StandoffResponderV2(responderData: ResponderData) extends Responder(respon responderManager = responderManager, targetSchema = getStandoffRequestV2.targetSchema, settings = settings, + featureFactoryConfig = getStandoffRequestV2.featureFactoryConfig, requestingUser = getStandoffRequestV2.requestingUser ) @@ -156,17 +161,23 @@ class StandoffResponderV2(responderData: ResponderData) extends Responder(respon * If not already in the cache, retrieves a `knora-base:XSLTransformation` in the triplestore and requests the corresponding XSL transformation file from Sipi. * * @param xslTransformationIri the IRI of the resource representing the XSL Transformation (a [[OntologyConstants.KnoraBase.XSLTransformation]]). + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the user making the request. * @return a [[GetXSLTransformationResponseV2]]. */ - private def getXSLTransformation(xslTransformationIri: IRI, requestingUser: UserADM): Future[GetXSLTransformationResponseV2] = { + private def getXSLTransformation(xslTransformationIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[GetXSLTransformationResponseV2] = { val xsltUrlFuture = for { textRepresentationResponseV2: ReadResourcesSequenceV2 <- (responderManager ? ResourcesGetRequestV2( resourceIris = Vector(xslTransformationIri), targetSchema = ApiV2Complex, - requestingUser = requestingUser)).mapTo[ReadResourcesSequenceV2] + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + )).mapTo[ReadResourcesSequenceV2] + resource = textRepresentationResponseV2.toResource(xslTransformationIri) _ = if (resource.resourceClassIri.toString != OntologyConstants.KnoraBase.XSLTransformation) { @@ -227,10 +238,17 @@ class StandoffResponderV2(responderData: ResponderData) extends Responder(respon * Creates a mapping between XML elements and attributes to standoff classes and properties. * The mapping is used to convert XML documents to texts with standoff and back. * - * @param xml the provided mapping. - * @param requestingUser the client that made the request. + * @param xml the provided mapping. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the client that made the request. */ - private def createMappingV2(xml: String, label: String, projectIri: SmartIri, mappingName: String, requestingUser: UserADM, apiRequestID: UUID): Future[CreateMappingResponseV2] = { + private def createMappingV2(xml: String, + label: String, + projectIri: SmartIri, + mappingName: String, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM, + apiRequestID: UUID): Future[CreateMappingResponseV2] = { def createMappingAndCheck(xml: String, label: String, mappingIri: IRI, namedGraph: String, requestingUser: UserADM): Future[CreateMappingResponseV2] = { @@ -262,7 +280,11 @@ class StandoffResponderV2(responderData: ResponderData) extends Responder(respon // try to obtain the XSL transformation to make sure that it really exists for { - transform: GetXSLTransformationResponseV2 <- getXSLTransformation(transIri, requestingUser) + transform: GetXSLTransformationResponseV2 <- getXSLTransformation( + xslTransformationIri = transIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) } yield Some(transIri) case _ => Future(None) } @@ -363,7 +385,11 @@ class StandoffResponderV2(responderData: ResponderData) extends Responder(respon triplestore = settings.triplestoreType, mappingIri = mappingIri ).toString() - existingMappingResponse: SparqlConstructResponse <- (storeManager ? SparqlConstructRequest(getExistingMappingSparql)).mapTo[SparqlConstructResponse] + + existingMappingResponse: SparqlConstructResponse <- (storeManager ? SparqlConstructRequest( + sparql = getExistingMappingSparql, + featureFactoryConfig = featureFactoryConfig + )).mapTo[SparqlConstructResponse] _ = if (existingMappingResponse.statements.nonEmpty) { throw BadRequestException(s"mapping IRI $mappingIri already exists") @@ -382,7 +408,10 @@ class StandoffResponderV2(responderData: ResponderData) extends Responder(respon createResourceResponse: SparqlUpdateResponse <- (storeManager ? SparqlUpdateRequest(createNewMappingSparql)).mapTo[SparqlUpdateResponse] // check if the mapping has been created - newMappingResponse <- (storeManager ? SparqlConstructRequest(getExistingMappingSparql)).mapTo[SparqlConstructResponse] + newMappingResponse <- (storeManager ? SparqlConstructRequest( + sparql = getExistingMappingSparql, + featureFactoryConfig = featureFactoryConfig + )).mapTo[SparqlConstructResponse] _ = if (newMappingResponse.statements.isEmpty) { log.error(s"Attempted a SPARQL update to create a new resource, but it inserted no rows:\n\n$newMappingResponse") @@ -390,9 +419,11 @@ class StandoffResponderV2(responderData: ResponderData) extends Responder(respon } // get the mapping from the triplestore and cache it thereby - _ = getMappingFromTriplestore(mappingIri, requestingUser) - - + _ = getMappingFromTriplestore( + mappingIri = mappingIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) } yield { CreateMappingResponseV2( mappingIri = mappingIri, @@ -426,7 +457,8 @@ class StandoffResponderV2(responderData: ResponderData) extends Responder(respon // check if the given project IRI represents an actual project projectInfoMaybe: Option[ProjectADM] <- (responderManager ? ProjectGetADM( - ProjectIdentifierADM(maybeIri = Some(projectIri.toString)), + identifier = ProjectIdentifierADM(maybeIri = Some(projectIri.toString)), + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser )).mapTo[Option[ProjectADM]] @@ -579,11 +611,14 @@ class StandoffResponderV2(responderData: ResponderData) extends Responder(respon /** * Gets a mapping either from the cache or by making a request to the triplestore. * - * @param mappingIri the IRI of the mapping to retrieve. - * @param requestingUser the user making the request. + * @param mappingIri the IRI of the mapping to retrieve. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return a [[MappingXMLtoStandoff]]. */ - private def getMappingV2(mappingIri: IRI, requestingUser: UserADM): Future[GetMappingResponseV2] = { + private def getMappingV2(mappingIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[GetMappingResponseV2] = { val mappingFuture: Future[GetMappingResponseV2] = CacheUtil.get[MappingXMLtoStandoff](cacheName = mappingCacheName, key = mappingIri) match { case Some(mapping: MappingXMLtoStandoff) => @@ -601,7 +636,11 @@ class StandoffResponderV2(responderData: ResponderData) extends Responder(respon case None => for { - mapping: MappingXMLtoStandoff <- getMappingFromTriplestore(mappingIri, requestingUser) + mapping: MappingXMLtoStandoff <- getMappingFromTriplestore( + mappingIri = mappingIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) entities: StandoffEntityInfoGetResponseV2 <- getStandoffEntitiesFromMappingV2(mapping, requestingUser) @@ -627,11 +666,14 @@ class StandoffResponderV2(responderData: ResponderData) extends Responder(respon * * Gets a mapping from the triplestore. * - * @param mappingIri the IRI of the mapping to retrieve. - * @param requestingUser the user making the request. + * @param mappingIri the IRI of the mapping to retrieve. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return a [[MappingXMLtoStandoff]]. */ - private def getMappingFromTriplestore(mappingIri: IRI, requestingUser: UserADM): Future[MappingXMLtoStandoff] = { + private def getMappingFromTriplestore(mappingIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[MappingXMLtoStandoff] = { val getMappingSparql = org.knora.webapi.messages.twirl.queries.sparql.v2.txt.getMapping( triplestore = settings.triplestoreType, @@ -640,7 +682,10 @@ class StandoffResponderV2(responderData: ResponderData) extends Responder(respon for { - mappingResponse: SparqlConstructResponse <- (storeManager ? SparqlConstructRequest(getMappingSparql)).mapTo[SparqlConstructResponse] + mappingResponse: SparqlConstructResponse <- (storeManager ? SparqlConstructRequest( + sparql = getMappingSparql, + featureFactoryConfig = featureFactoryConfig, + )).mapTo[SparqlConstructResponse] // if the result is empty, the mapping does not exist _ = if (mappingResponse.statements.isEmpty) { @@ -849,14 +894,16 @@ class StandoffResponderV2(responderData: ResponderData) extends Responder(respon /** * A task that gets a page of standoff from a text value. * - * @param resourceIri the IRI of the resource containing the value. - * @param valueIri the IRI of the value. - * @param offset the start index of the first standoff tag to be returned. - * @param requestingUser the user making the request. + * @param resourceIri the IRI of the resource containing the value. + * @param valueIri the IRI of the value. + * @param offset the start index of the first standoff tag to be returned. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ case class GetStandoffTask(resourceIri: IRI, valueIri: IRI, offset: Int, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM) extends Task[StandoffTaskUnderlyingResult] { override def runTask(previousResult: Option[TaskResult[StandoffTaskUnderlyingResult]])(implicit timeout: Timeout, executionContext: ExecutionContext): Future[TaskResult[StandoffTaskUnderlyingResult]] = { for { @@ -867,7 +914,9 @@ class StandoffResponderV2(responderData: ResponderData) extends Responder(respon valueIri = valueIri, offset = offset, targetSchema = ApiV2Complex, - requestingUser = requestingUser) + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) ) // Add it to the standoff that has already been collected. @@ -904,6 +953,7 @@ class StandoffResponderV2(responderData: ResponderData) extends Responder(respon resourceIri = getRemainingStandoffFromTextValueRequestV2.resourceIri, valueIri = getRemainingStandoffFromTextValueRequestV2.valueIri, offset = settings.standoffPerPage, // the offset of the second page + featureFactoryConfig = getRemainingStandoffFromTextValueRequestV2.featureFactoryConfig, requestingUser = getRemainingStandoffFromTextValueRequestV2.requestingUser ) diff --git a/webapi/src/main/scala/org/knora/webapi/responders/v2/ValuesResponderV2.scala b/webapi/src/main/scala/org/knora/webapi/responders/v2/ValuesResponderV2.scala index bc419cced5..7c4cebd385 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/v2/ValuesResponderV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/v2/ValuesResponderV2.scala @@ -26,6 +26,7 @@ import akka.http.scaladsl.util.FastFuture import akka.pattern._ import org.knora.webapi._ import org.knora.webapi.exceptions._ +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.admin.responder.permissionsmessages.{PermissionADM, PermissionType} import org.knora.webapi.messages.admin.responder.usersmessages.UserADM @@ -124,6 +125,7 @@ class ValuesResponderV2(responderData: ResponderData) extends Responder(responde resourceInfo: ReadResourceV2 <- getResourceWithPropertyValues( resourceIri = createValueRequest.createValue.resourceIri, propertyInfo = adjustedInternalPropertyInfo, + featureFactoryConfig = createValueRequest.featureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser ) @@ -162,6 +164,7 @@ class ValuesResponderV2(responderData: ResponderData) extends Responder(responde _ <- checkPropertyObjectClassConstraint( propertyInfo = adjustedInternalPropertyInfo, valueContent = submittedInternalValueContent, + featureFactoryConfig = createValueRequest.featureFactoryConfig, requestingUser = createValueRequest.requestingUser ) @@ -197,7 +200,13 @@ class ValuesResponderV2(responderData: ResponderData) extends Responder(responde // and that the user has permission to see them. _ <- submittedInternalValueContent match { - case textValueContent: TextValueContentV2 => checkResourceIris(textValueContent.standoffLinkTagTargetResourceIris, createValueRequest.requestingUser) + case textValueContent: TextValueContentV2 => + checkResourceIris( + targetResourceIris = textValueContent.standoffLinkTagTargetResourceIris, + featureFactoryConfig = createValueRequest.featureFactoryConfig, + requestingUser = createValueRequest.requestingUser + ) + case _ => FastFuture.successful(()) } @@ -215,7 +224,11 @@ class ValuesResponderV2(responderData: ResponderData) extends Responder(responde case Some(permissions: String) => // Yes. Validate them. for { - validatedCustomPermissions <- PermissionUtilADM.validatePermissions(permissionLiteral = permissions, responderManager = responderManager) + validatedCustomPermissions <- PermissionUtilADM.validatePermissions( + permissionLiteral = permissions, + featureFactoryConfig = createValueRequest.featureFactoryConfig, + responderManager = responderManager + ) // Is the requesting user a system admin, or an admin of this project? _ = if (!(createValueRequest.requestingUser.permissions.isProjectAdmin(createValueRequest.requestingUser.id) || createValueRequest.requestingUser.permissions.isSystemAdmin)) { @@ -265,6 +278,7 @@ class ValuesResponderV2(responderData: ResponderData) extends Responder(responde resourceIri = createValueRequest.createValue.resourceIri, propertyIri = submittedInternalPropertyIri, unverifiedValue = unverifiedValue, + featureFactoryConfig = createValueRequest.featureFactoryConfig, requestingUser = createValueRequest.requestingUser ) } yield CreateValueResponseV2( @@ -842,6 +856,7 @@ class ValuesResponderV2(responderData: ResponderData) extends Responder(responde resourceInfo: ReadResourceV2 <- getResourceWithPropertyValues( resourceIri = resourceIri, propertyInfo = adjustedInternalPropertyInfo, + featureFactoryConfig = updateValueRequest.featureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser ) @@ -894,7 +909,11 @@ class ValuesResponderV2(responderData: ResponderData) extends Responder(responde // Validate and reformat the submitted permissions. - newValuePermissionLiteral: String <- PermissionUtilADM.validatePermissions(permissionLiteral = updateValuePermissionsV2.permissions, responderManager = responderManager) + newValuePermissionLiteral: String <- PermissionUtilADM.validatePermissions( + permissionLiteral = updateValuePermissionsV2.permissions, + featureFactoryConfig = updateValueRequest.featureFactoryConfig, + responderManager = responderManager + ) // Check that the user has ChangeRightsPermission on the value, and that the new permissions are // different from the current ones. @@ -948,6 +967,7 @@ class ValuesResponderV2(responderData: ResponderData) extends Responder(responde resourceIri = resourceInfo.resourceIri, propertyIri = submittedInternalPropertyIri, unverifiedValue = unverifiedValue, + featureFactoryConfig = updateValueRequest.featureFactoryConfig, requestingUser = updateValueRequest.requestingUser ) } yield UpdateValueResponseV2( @@ -984,7 +1004,11 @@ class ValuesResponderV2(responderData: ResponderData) extends Responder(responde newValueVersionPermissionLiteral <- updateValueContentV2.permissions match { case Some(permissions) => // Yes. Validate them. - PermissionUtilADM.validatePermissions(permissionLiteral = permissions, responderManager = responderManager) + PermissionUtilADM.validatePermissions( + permissionLiteral = permissions, + featureFactoryConfig = updateValueRequest.featureFactoryConfig, + responderManager = responderManager + ) case None => // No. Use the permissions on the current version of the value. @@ -1019,6 +1043,7 @@ class ValuesResponderV2(responderData: ResponderData) extends Responder(responde _ <- checkPropertyObjectClassConstraint( propertyInfo = adjustedInternalPropertyInfo, valueContent = submittedInternalValueContent, + featureFactoryConfig = updateValueRequest.featureFactoryConfig, requestingUser = updateValueRequest.requestingUser ) @@ -1049,7 +1074,11 @@ class ValuesResponderV2(responderData: ResponderData) extends Responder(responde case textValueContent: TextValueContentV2 => // This is a text value. Check that the resources pointed to by any standoff link tags exist // and that the user has permission to see them. - checkResourceIris(textValueContent.standoffLinkTagTargetResourceIris, updateValueRequest.requestingUser) + checkResourceIris( + textValueContent.standoffLinkTagTargetResourceIris, + featureFactoryConfig = updateValueRequest.featureFactoryConfig, + updateValueRequest.requestingUser + ) case _: LinkValueContentV2 => // We're updating a link. This means deleting an existing link and creating a new one, so @@ -1106,6 +1135,7 @@ class ValuesResponderV2(responderData: ResponderData) extends Responder(responde resourceIri = updateValueContentV2.resourceIri, propertyIri = submittedInternalPropertyIri, unverifiedValue = unverifiedValue, + featureFactoryConfig = updateValueRequest.featureFactoryConfig, requestingUser = updateValueRequest.requestingUser ) } yield UpdateValueResponseV2( @@ -1437,6 +1467,7 @@ class ValuesResponderV2(responderData: ResponderData) extends Responder(responde resourceInfo: ReadResourceV2 <- getResourceWithPropertyValues( resourceIri = deleteValueRequest.resourceIri, propertyInfo = adjustedInternalPropertyInfo, + featureFactoryConfig = deleteValueRequest.featureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser ) @@ -1762,10 +1793,13 @@ class ValuesResponderV2(responderData: ResponderData) extends Responder(responde * Given a set of resource IRIs, checks that they point to Knora resources. * If not, throws an exception. * - * @param targetResourceIris the IRIs to be checked. - * @param requestingUser the user making the request. + * @param targetResourceIris the IRIs to be checked. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ - private def checkResourceIris(targetResourceIris: Set[IRI], requestingUser: UserADM): Future[Unit] = { + private def checkResourceIris(targetResourceIris: Set[IRI], + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[Unit] = { if (targetResourceIris.isEmpty) { FastFuture.successful(()) } else { @@ -1774,6 +1808,7 @@ class ValuesResponderV2(responderData: ResponderData) extends Responder(responde ResourcesPreviewGetRequestV2( resourceIris = targetResourceIris.toSeq, targetSchema = ApiV2Complex, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) ) @@ -1791,13 +1826,17 @@ class ValuesResponderV2(responderData: ResponderData) extends Responder(responde * If the property's object type is `knora-base:TextValue`, the result will contain any objects of the property (text values), as well metadata * for any resources that are objects of `knora-base:hasStandoffLinkTo`. * - * @param resourceIri the resource IRI. - * @param propertyInfo the property definition (in the internal schema). If the caller wants to query a link, this must be the link property, - * not the link value property. - * @param requestingUser the user making the request. + * @param resourceIri the resource IRI. + * @param propertyInfo the property definition (in the internal schema). If the caller wants to query a link, this must be the link property, + * not the link value property. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return a [[ReadResourceV2]] containing only the resource's metadata and its values for the specified property. */ - private def getResourceWithPropertyValues(resourceIri: IRI, propertyInfo: ReadPropertyInfoV2, requestingUser: UserADM): Future[ReadResourceV2] = { + private def getResourceWithPropertyValues(resourceIri: IRI, + propertyInfo: ReadPropertyInfoV2, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[ReadResourceV2] = { for { // Get the property's object class constraint. objectClassConstraint: SmartIri <- Future(propertyInfo.entityInfoContent.requireIriObject(OntologyConstants.KnoraBase.ObjectClassConstraint.toSmartIri, throw InconsistentTriplestoreDataException(s"Property ${propertyInfo.entityInfoContent.propertyIri} has no knora-base:objectClassConstraint"))) @@ -1825,22 +1864,26 @@ class ValuesResponderV2(responderData: ResponderData) extends Responder(responde constructQuery = parsedGravsearchQuery, targetSchema = ApiV2Complex, schemaOptions = SchemaOptions.ForStandoffWithTextValues, - requestingUser = requestingUser)).mapTo[ReadResourcesSequenceV2] + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + )).mapTo[ReadResourcesSequenceV2] } yield searchResponse.toResource(resourceIri) } /** * Verifies that a value was written correctly to the triplestore. * - * @param resourceIri the IRI of the resource that the value belongs to. - * @param propertyIri the internal IRI of the property that points to the value. If the value is a link value, - * this is the link value property. - * @param unverifiedValue the value that should have been written to the triplestore. - * @param requestingUser the user making the request. + * @param resourceIri the IRI of the resource that the value belongs to. + * @param propertyIri the internal IRI of the property that points to the value. If the value is a link value, + * this is the link value property. + * @param unverifiedValue the value that should have been written to the triplestore. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ private def verifyValue(resourceIri: IRI, propertyIri: SmartIri, unverifiedValue: UnverifiedValueV2, + featureFactoryConfig: FeatureFactoryConfig, requestingUser: UserADM): Future[VerifiedValueV2] = { val verifiedValueFuture: Future[VerifiedValueV2] = for { resourcesRequest <- Future { @@ -1850,6 +1893,7 @@ class ValuesResponderV2(responderData: ResponderData) extends Responder(responde versionDate = Some(unverifiedValue.creationDate), targetSchema = ApiV2Complex, schemaOptions = SchemaOptions.ForStandoffWithTextValues, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) } @@ -1892,9 +1936,14 @@ class ValuesResponderV2(responderData: ResponderData) extends Responder(responde * @param linkPropertyIri the IRI of the link property. * @param objectClassConstraint the object class constraint of the link property. * @param linkValueContent the link value. + * @param featureFactoryConfig the feature factory configuration. * @param requestingUser the user making the request. */ - private def checkLinkPropertyObjectClassConstraint(linkPropertyIri: SmartIri, objectClassConstraint: SmartIri, linkValueContent: LinkValueContentV2, requestingUser: UserADM): Future[Unit] = { + private def checkLinkPropertyObjectClassConstraint(linkPropertyIri: SmartIri, + objectClassConstraint: SmartIri, + linkValueContent: LinkValueContentV2, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[Unit] = { for { // Get a preview of the target resource, because we only need to find out its class and whether the user has permission to view it. @@ -1902,6 +1951,7 @@ class ValuesResponderV2(responderData: ResponderData) extends Responder(responde ResourcesPreviewGetRequestV2( resourceIris = Seq(linkValueContent.referredResourceIri), targetSchema = ApiV2Complex, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) ) @@ -1965,11 +2015,15 @@ class ValuesResponderV2(responderData: ResponderData) extends Responder(responde * Checks that a value to be updated has the correct type for the `knora-base:objectClassConstraint` of * the property that is supposed to point to it. * - * @param propertyInfo the property whose object class constraint is to be checked. If the value is a link value, this is the link property. - * @param valueContent the value to be updated. - * @param requestingUser the user making the request. + * @param propertyInfo the property whose object class constraint is to be checked. If the value is a link value, this is the link property. + * @param valueContent the value to be updated. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. */ - private def checkPropertyObjectClassConstraint(propertyInfo: ReadPropertyInfoV2, valueContent: ValueContentV2, requestingUser: UserADM): Future[Unit] = { + private def checkPropertyObjectClassConstraint(propertyInfo: ReadPropertyInfoV2, + valueContent: ValueContentV2, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[Unit] = { for { objectClassConstraint: SmartIri <- Future(propertyInfo.entityInfoContent.requireIriObject(OntologyConstants.KnoraBase.ObjectClassConstraint.toSmartIri, throw InconsistentTriplestoreDataException(s"Property ${propertyInfo.entityInfoContent.propertyIri} has no knora-base:objectClassConstraint"))) @@ -1987,6 +2041,7 @@ class ValuesResponderV2(responderData: ResponderData) extends Responder(responde linkPropertyIri = propertyInfo.entityInfoContent.propertyIri, objectClassConstraint = objectClassConstraint, linkValueContent = linkValueContent, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) diff --git a/webapi/src/main/scala/org/knora/webapi/routing/Authenticator.scala b/webapi/src/main/scala/org/knora/webapi/routing/Authenticator.scala index 83237e1139..528ab30afd 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/Authenticator.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/Authenticator.scala @@ -31,6 +31,7 @@ import akka.util.{ByteString, Timeout} import com.typesafe.scalalogging.Logger import org.knora.webapi.IRI import org.knora.webapi.exceptions.{AuthenticationException, BadCredentialsException, BadRequestException} +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.admin.responder.usersmessages._ import org.knora.webapi.messages.v1.responder.usermessages._ import org.knora.webapi.messages.v2.routing.authenticationmessages._ @@ -65,19 +66,21 @@ trait Authenticator { * Checks if the credentials provided in [[RequestContext]] are valid, and if so returns a message and cookie header * with the generated session id for the client to save. * - * @param requestContext a [[RequestContext]] containing the http request - * @param system the current [[ActorSystem]] + * @param requestContext a [[RequestContext]] containing the http request + * @param featureFactoryConfig the feature factory configuration. + * @param system the current [[ActorSystem]] * @return a [[HttpResponse]] containing either a failure message or a message with a cookie header containing * the generated session id. */ - def doLoginV1(requestContext: RequestContext)(implicit system: ActorSystem, responderManager: ActorRef, executionContext: ExecutionContext): Future[HttpResponse] = { + def doLoginV1(requestContext: RequestContext, + featureFactoryConfig: FeatureFactoryConfig)(implicit system: ActorSystem, responderManager: ActorRef, executionContext: ExecutionContext): Future[HttpResponse] = { val settings = KnoraSettings(system) val credentials: Option[KnoraCredentialsV2] = extractCredentialsV2(requestContext) for { - userADM <- getUserADMThroughCredentialsV2(credentials) // will return or throw + userADM <- getUserADMThroughCredentialsV2(credentials = credentials, featureFactoryConfig = featureFactoryConfig) // will return or throw userProfile = userADM.asUserProfileV1 cookieDomain = Some(settings.cookieDomain) @@ -102,21 +105,30 @@ trait Authenticator { /** * Checks if the provided credentials are valid, and if so returns a JWT token for the client to save. * - * @param credentials the user supplied [[KnoraPasswordCredentialsV2]] containing the user's login information. - * @param system the current [[ActorSystem]] + * @param credentials the user supplied [[KnoraPasswordCredentialsV2]] containing the user's login information. + * @param featureFactoryConfig the feature factory configuration. + * @param system the current [[ActorSystem]] * @return a [[HttpResponse]] containing either a failure message or a message with a cookie header containing * the generated session id. */ - def doLoginV2(credentials: KnoraPasswordCredentialsV2)(implicit system: ActorSystem, responderManager: ActorRef, executionContext: ExecutionContext): Future[HttpResponse] = { + def doLoginV2(credentials: KnoraPasswordCredentialsV2, + featureFactoryConfig: FeatureFactoryConfig)(implicit system: ActorSystem, responderManager: ActorRef, executionContext: ExecutionContext): Future[HttpResponse] = { log.debug(s"doLoginV2 - credentials: $credentials") for { - authenticated <- authenticateCredentialsV2(Some(credentials)) // will throw exception if not valid and thus trigger the correct response + // will throw exception if not valid and thus trigger the correct response + authenticated <- authenticateCredentialsV2( + credentials = Some(credentials), + featureFactoryConfig = featureFactoryConfig + ) settings = KnoraSettings(system) - userADM <- getUserByIdentifier(credentials.identifier) + userADM <- getUserByIdentifier( + identifier = credentials.identifier, + featureFactoryConfig = featureFactoryConfig + ) cookieDomain = Some(settings.cookieDomain) token = JWTHelper.createToken(userADM.id, settings.jwtSecretKey, settings.jwtLongevity) @@ -189,16 +201,22 @@ trait Authenticator { * Checks if the credentials provided in [[RequestContext]] are valid, and if so returns a message. No session is * generated. * - * @param requestContext a [[RequestContext]] containing the http request - * @param system the current [[ActorSystem]] + * @param requestContext a [[RequestContext]] containing the http request + * @param featureFactoryConfig the feature factory configuration. + * @param system the current [[ActorSystem]] * @return a [[RequestContext]] */ - def doAuthenticateV1(requestContext: RequestContext)(implicit system: ActorSystem, responderManager: ActorRef, executionContext: ExecutionContext): Future[HttpResponse] = { + def doAuthenticateV1(requestContext: RequestContext, + featureFactoryConfig: FeatureFactoryConfig)(implicit system: ActorSystem, responderManager: ActorRef, executionContext: ExecutionContext): Future[HttpResponse] = { val credentials: Option[KnoraCredentialsV2] = extractCredentialsV2(requestContext) for { - userADM: UserADM <- getUserADMThroughCredentialsV2(credentials) // will authenticate and either return or throw + // will authenticate and either return or throw + userADM: UserADM <- getUserADMThroughCredentialsV2( + credentials = credentials, + featureFactoryConfig = featureFactoryConfig + ) userProfile: UserProfileV1 = userADM.asUserProfileV1 @@ -223,12 +241,17 @@ trait Authenticator { * @param system the current [[ActorSystem]] * @return a [[HttpResponse]] */ - def doAuthenticateV2(requestContext: RequestContext)(implicit system: ActorSystem, responderManager: ActorRef, executionContext: ExecutionContext): Future[HttpResponse] = { + def doAuthenticateV2(requestContext: RequestContext, + featureFactoryConfig: FeatureFactoryConfig)(implicit system: ActorSystem, responderManager: ActorRef, executionContext: ExecutionContext): Future[HttpResponse] = { val credentials: Option[KnoraCredentialsV2] = extractCredentialsV2(requestContext) for { - authenticated <- authenticateCredentialsV2(credentials) // will throw exception if not valid + // will throw exception if not valid + authenticated <- authenticateCredentialsV2( + credentials = credentials, + featureFactoryConfig = featureFactoryConfig + ) httpResponse = HttpResponse( status = StatusCodes.OK, @@ -324,7 +347,8 @@ trait Authenticator { * @return a [[UserProfileV1]] */ @deprecated("Please use: getUserADM()", "Knora v1.7.0") - def getUserProfileV1(requestContext: RequestContext)(implicit system: ActorSystem, responderManager: ActorRef, executionContext: ExecutionContext): Future[UserProfileV1] = { + def getUserProfileV1(requestContext: RequestContext, + featureFactoryConfig: FeatureFactoryConfig)(implicit system: ActorSystem, responderManager: ActorRef, executionContext: ExecutionContext): Future[UserProfileV1] = { val settings = KnoraSettings(system) @@ -339,7 +363,7 @@ trait Authenticator { FastFuture.successful(UserProfileV1()) } else { for { - userADM <- getUserADMThroughCredentialsV2(credentials) + userADM <- getUserADMThroughCredentialsV2(credentials = credentials, featureFactoryConfig = featureFactoryConfig) userProfile: UserProfileV1 = userADM.asUserProfileV1 _ = log.debug("Authenticator - getUserProfileV1 - userProfile: {}", userProfile) @@ -354,11 +378,13 @@ trait Authenticator { * credentials are found, then a default UserProfile is returned. If the credentials are not correct, then the * corresponding error is returned. * - * @param requestContext a [[RequestContext]] containing the http request - * @param system the current [[ActorSystem]] + * @param requestContext a [[RequestContext]] containing the http request + * @param featureFactoryConfig the feature factory configuration. + * @param system the current [[ActorSystem]] * @return a [[UserProfileV1]] */ - def getUserADM(requestContext: RequestContext)(implicit system: ActorSystem, responderManager: ActorRef, executionContext: ExecutionContext): Future[UserADM] = { + def getUserADM(requestContext: RequestContext, + featureFactoryConfig: FeatureFactoryConfig)(implicit system: ActorSystem, responderManager: ActorRef, executionContext: ExecutionContext): Future[UserADM] = { val settings = KnoraSettings(system) @@ -374,7 +400,7 @@ trait Authenticator { } else { for { - user: UserADM <- getUserADMThroughCredentialsV2(credentials) + user: UserADM <- getUserADMThroughCredentialsV2(credentials = credentials, featureFactoryConfig = featureFactoryConfig) _ = log.debug("Authenticator - getUserADM - user: {}", user) /* we return the complete UserADM */ @@ -412,14 +438,16 @@ object Authenticator { * user's profile. In the case of the token, the token itself is validated. If both are supplied, then both need * to be valid. * - * @param credentials the user supplied and extracted credentials. - * @param system the current [[ActorSystem]] + * @param credentials the user supplied and extracted credentials. + * @param featureFactoryConfig the feature factory configuration. + * @param system the current [[ActorSystem]] * @return true if the credentials are valid. If the credentials are invalid, then the corresponding exception * will be thrown. * @throws BadCredentialsException when no credentials are supplied; when user is not active; * when the password does not match; when the supplied token is not valid. */ - def authenticateCredentialsV2(credentials: Option[KnoraCredentialsV2])(implicit system: ActorSystem, responderManager: ActorRef, executionContext: ExecutionContext): Future[Boolean] = { + def authenticateCredentialsV2(credentials: Option[KnoraCredentialsV2], + featureFactoryConfig: FeatureFactoryConfig)(implicit system: ActorSystem, responderManager: ActorRef, executionContext: ExecutionContext): Future[Boolean] = { for { settings <- FastFuture.successful(KnoraSettings(system)) @@ -427,7 +455,10 @@ object Authenticator { result <- credentials match { case Some(passCreds: KnoraPasswordCredentialsV2) => { for { - user <- getUserByIdentifier(passCreds.identifier) + user <- getUserByIdentifier( + identifier = passCreds.identifier, + featureFactoryConfig = featureFactoryConfig + ) /* check if the user is active, if not, then no need to check the password */ _ = if (!user.isActive) { @@ -643,21 +674,26 @@ object Authenticator { * token are supplied, then the user profile for the session token is returned. This method should only be used * with authenticated credentials. * - * @param credentials the user supplied credentials. + * @param credentials the user supplied credentials. + * @param featureFactoryConfig the feature factory configuration. * @return a [[UserADM]] * @throws AuthenticationException when the IRI can not be found inside the token, which is probably a bug. */ - private def getUserADMThroughCredentialsV2(credentials: Option[KnoraCredentialsV2])(implicit system: ActorSystem, responderManager: ActorRef, executionContext: ExecutionContext): Future[UserADM] = { + private def getUserADMThroughCredentialsV2(credentials: Option[KnoraCredentialsV2], + featureFactoryConfig: FeatureFactoryConfig)(implicit system: ActorSystem, responderManager: ActorRef, executionContext: ExecutionContext): Future[UserADM] = { val settings = KnoraSettings(system) for { - authenticated <- authenticateCredentialsV2(credentials) + authenticated <- authenticateCredentialsV2(credentials = credentials, featureFactoryConfig = featureFactoryConfig) user: UserADM <- credentials match { case Some(passCreds: KnoraPasswordCredentialsV2) => { // log.debug("getUserADMThroughCredentialsV2 - used identifier: {}", passCreds.identifier) - getUserByIdentifier(passCreds.identifier) + getUserByIdentifier( + identifier = passCreds.identifier, + featureFactoryConfig = featureFactoryConfig + ) } case Some(tokenCreds: KnoraTokenCredentialsV2) => { val userIri: IRI = JWTHelper.extractUserIriFromToken(tokenCreds.token, settings.jwtSecretKey) match { @@ -668,7 +704,10 @@ object Authenticator { } } // log.debug("getUserADMThroughCredentialsV2 - used token") - getUserByIdentifier(UserIdentifierADM(maybeIri = Some(userIri))) + getUserByIdentifier( + identifier = UserIdentifierADM(maybeIri = Some(userIri)), + featureFactoryConfig = featureFactoryConfig + ) } case Some(sessionCreds: KnoraSessionCredentialsV2) => { val userIri: IRI = JWTHelper.extractUserIriFromToken(sessionCreds.token, settings.jwtSecretKey) match { @@ -679,7 +718,10 @@ object Authenticator { } } // log.debug("getUserADMThroughCredentialsV2 - used session token") - getUserByIdentifier(UserIdentifierADM(maybeIri = Some(userIri))) + getUserByIdentifier( + identifier = UserIdentifierADM(maybeIri = Some(userIri)), + featureFactoryConfig = featureFactoryConfig + ) } case None => { // log.debug("getUserADMThroughCredentialsV2 - no credentials supplied") @@ -697,17 +739,25 @@ object Authenticator { /** * Tries to get a [[UserADM]]. * - * @param identifier the IRI, email, or username of the user to be queried - * @param system the current akka actor system - * @param timeout the timeout of the query - * @param executionContext the current execution context + * @param identifier the IRI, email, or username of the user to be queried + * @param featureFactoryConfig the feature factory configuration. + * @param system the current akka actor system + * @param timeout the timeout of the query + * @param executionContext the current execution context * @return a [[UserADM]] * @throws BadCredentialsException when either the supplied email is empty or no user with such an email could be found. */ - private def getUserByIdentifier(identifier: UserIdentifierADM)(implicit system: ActorSystem, responderManager: ActorRef, timeout: Timeout, executionContext: ExecutionContext): Future[UserADM] = { + private def getUserByIdentifier(identifier: UserIdentifierADM, + featureFactoryConfig: FeatureFactoryConfig)(implicit system: ActorSystem, responderManager: ActorRef, timeout: Timeout, executionContext: ExecutionContext): Future[UserADM] = { val userADMFuture = for { - maybeUserADM <- (responderManager ? UserGetADM(identifier = identifier, userInformationTypeADM = UserInformationTypeADM.FULL, requestingUser = KnoraSystemInstances.Users.SystemUser)).mapTo[Option[UserADM]] + maybeUserADM <- (responderManager ? UserGetADM( + identifier = identifier, + userInformationTypeADM = UserInformationTypeADM.FULL, + featureFactoryConfig = featureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + )).mapTo[Option[UserADM]] + user = maybeUserADM match { case Some(u) => u case None => { diff --git a/webapi/src/main/scala/org/knora/webapi/routing/BUILD.bazel b/webapi/src/main/scala/org/knora/webapi/routing/BUILD.bazel index 9c16bfcd33..ba669433e9 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/BUILD.bazel +++ b/webapi/src/main/scala/org/knora/webapi/routing/BUILD.bazel @@ -8,9 +8,9 @@ scala_library( unused_dependency_checker_mode = "warn", deps = [ "//webapi/src/main/scala/org/knora/webapi", - "//webapi/src/main/scala/org/knora/webapi/feature", "//webapi/src/main/scala/org/knora/webapi/annotation", "//webapi/src/main/scala/org/knora/webapi/exceptions", + "//webapi/src/main/scala/org/knora/webapi/feature", "//webapi/src/main/scala/org/knora/webapi/http/status", "//webapi/src/main/scala/org/knora/webapi/http/version/versioninfo", "//webapi/src/main/scala/org/knora/webapi/instrumentation", @@ -37,7 +37,6 @@ scala_library( "@maven//:io_swagger_swagger_jaxrs", "@maven//:io_swagger_swagger_models", "@maven//:javax_ws_rs_jsr311_api", - "@maven//:org_apache_jena_apache_jena_libs", "@maven//:org_scala_lang_modules_scala_xml_2_12", "@maven//:org_slf4j_slf4j_api", ], diff --git a/webapi/src/main/scala/org/knora/webapi/routing/KnoraRoute.scala b/webapi/src/main/scala/org/knora/webapi/routing/KnoraRoute.scala index 82b49429af..a77078ca91 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/KnoraRoute.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/KnoraRoute.scala @@ -70,8 +70,8 @@ abstract class KnoraRouteFactory(routeData: KnoraRouteData) { * Constructs a route. This can be done: * * - by statically returning a routing function (if this is an ordinary route that - * doesn't use a feature factory, or if this is a route feature returned by - * a feature factory) + * doesn't use a feature factory, or if this is a route feature returned by + * a feature factory) * * - by asking a feature factory for a routing function (if this is a façade route) * @@ -125,11 +125,14 @@ abstract class KnoraRoute(routeData: KnoraRouteData) extends KnoraRouteFactory(r /** * Gets a [[ProjectADM]] corresponding to the specified project IRI. * - * @param projectIri the project IRI. - * @param requestingUser the user making the request. + * @param projectIri the project IRI. + * @param featureFactoryConfig the feature factory configuration. + * @param requestingUser the user making the request. * @return the corresponding [[ProjectADM]]. */ - protected def getProjectADM(projectIri: IRI, requestingUser: UserADM): Future[ProjectADM] = { + protected def getProjectADM(projectIri: IRI, + featureFactoryConfig: FeatureFactoryConfig, + requestingUser: UserADM): Future[ProjectADM] = { val checkedProjectIri = stringFormatter.validateAndEscapeProjectIri(projectIri, throw BadRequestException(s"Invalid project IRI: $projectIri")) if (stringFormatter.isKnoraBuiltInProjectIriStr(checkedProjectIri)) { @@ -138,7 +141,8 @@ abstract class KnoraRoute(routeData: KnoraRouteData) extends KnoraRouteFactory(r for { projectInfoResponse: ProjectGetResponseADM <- (responderManager ? ProjectGetRequestADM( - ProjectIdentifierADM(maybeIri = Some(checkedProjectIri)), + identifier = ProjectIdentifierADM(maybeIri = Some(checkedProjectIri)), + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser )).mapTo[ProjectGetResponseADM] } yield projectInfoResponse.project diff --git a/webapi/src/main/scala/org/knora/webapi/routing/RouteUtilV1.scala b/webapi/src/main/scala/org/knora/webapi/routing/RouteUtilV1.scala index fac96be542..3c45d5af45 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/RouteUtilV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/RouteUtilV1.scala @@ -27,6 +27,7 @@ import akka.pattern._ import akka.util.Timeout import org.knora.webapi.IRI import org.knora.webapi.exceptions.{BadRequestException, SipiException, UnexpectedMessageException} +import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.http.status.ApiStatusCodesV1 import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.store.sipimessages.GetFileMetadataResponse @@ -197,6 +198,7 @@ object RouteUtilV1 { * resources. In a bulk import, this allows standoff links to resources * that are to be created by the import. * @param userProfile the user making the request. + * @param featureFactoryConfig the feature factory configuration. * @param settings the application's settings. * @param responderManager a reference to the responder manager. * @param log a logging adapter. @@ -208,6 +210,7 @@ object RouteUtilV1 { mappingIri: IRI, acceptStandoffLinksToClientIDs: Boolean, userProfile: UserADM, + featureFactoryConfig: FeatureFactoryConfig, settings: KnoraSettingsImpl, responderManager: ActorRef, log: LoggingAdapter)(implicit timeout: Timeout, executionContext: ExecutionContext): Future[TextWithStandoffTagsV2] = { @@ -215,7 +218,11 @@ object RouteUtilV1 { for { // get the mapping directly from v2 responder directly (to avoid useless back and forth conversions between v2 and v1 message formats) - mappingResponse: GetMappingResponseV2 <- (responderManager ? GetMappingRequestV2(mappingIri = mappingIri, requestingUser = userProfile)).mapTo[GetMappingResponseV2] + mappingResponse: GetMappingResponseV2 <- (responderManager ? GetMappingRequestV2( + mappingIri = mappingIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = userProfile + )).mapTo[GetMappingResponseV2] textWithStandoffTagV1 = StandoffTagUtilV2.convertXMLtoStandoffTagV2( xml = xml, diff --git a/webapi/src/main/scala/org/knora/webapi/routing/RouteUtilV2.scala b/webapi/src/main/scala/org/knora/webapi/routing/RouteUtilV2.scala index 5527852d8d..4a4847ad70 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/RouteUtilV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/RouteUtilV2.scala @@ -25,12 +25,11 @@ import akka.http.scaladsl.model._ import akka.http.scaladsl.server.{RequestContext, RouteResult} import akka.pattern._ import akka.util.Timeout -import org.apache.jena import org.knora.webapi._ import org.knora.webapi.exceptions.{BadRequestException, UnexpectedMessageException} import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.IriConversions._ -import org.knora.webapi.messages.util.{JsonLDDocument, RdfFormatUtil} +import org.knora.webapi.messages.util.rdf.{JsonLDDocument, RdfFeatureFactory, RdfFormat, RdfModel} import org.knora.webapi.messages.v2.responder.resourcemessages.ResourceTEIGetResponseV2 import org.knora.webapi.messages.v2.responder.{KnoraRequestV2, KnoraResponseV2} import org.knora.webapi.messages.{SmartIri, StringFormatter} @@ -231,9 +230,10 @@ object RouteUtilV2 { // Format the response message. formattedResponseContent: String = knoraResponse.format( - mediaType = specificMediaType, + rdfFormat = RdfFormat.fromMediaType(specificMediaType), targetSchema = targetSchema, settings = settings, + featureFactoryConfig = featureFactoryConfig, schemaOptions = schemaOptions ) } yield featureFactoryConfig.addHeaderToHttpResponse( @@ -343,16 +343,16 @@ object RouteUtilV2 { } /** - * Parses a request entity to a [[jena.graph.Graph]]. + * Parses a request entity to an [[RdfModel]]. * * @param entityStr the request entity. * @param requestContext the request context. - * @return the corresponding [[jena.graph.Graph]]. + * @return the corresponding [[RdfModel]]. */ - def requestToJenaGraph(entityStr: String, requestContext: RequestContext): jena.graph.Graph = { - RdfFormatUtil.parseToJenaGraph( + def requestToRdfModel(entityStr: String, requestContext: RequestContext, featureFactoryConfig: FeatureFactoryConfig): RdfModel = { + RdfFeatureFactory.getRdfFormatUtil(featureFactoryConfig).parseToRdfModel( rdfStr = entityStr, - mediaType = getRequestContentType(requestContext) + rdfFormat = RdfFormat.fromMediaType(getRequestContentType(requestContext)) ) } @@ -363,10 +363,10 @@ object RouteUtilV2 { * @param requestContext the request context. * @return the corresponding [[JsonLDDocument]]. */ - def requestToJsonLD(entityStr: String, requestContext: RequestContext): JsonLDDocument = { - RdfFormatUtil.parseToJsonLDDocument( + def requestToJsonLD(entityStr: String, requestContext: RequestContext, featureFactoryConfig: FeatureFactoryConfig): JsonLDDocument = { + RdfFeatureFactory.getRdfFormatUtil(featureFactoryConfig).parseToJsonLDDocument( rdfStr = entityStr, - mediaType = getRequestContentType(requestContext) + rdfFormat = RdfFormat.fromMediaType(getRequestContentType(requestContext)) ) } diff --git a/webapi/src/main/scala/org/knora/webapi/routing/admin/GroupsRouteADM.scala b/webapi/src/main/scala/org/knora/webapi/routing/admin/GroupsRouteADM.scala index 55ba181fda..783b40d5eb 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/admin/GroupsRouteADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/admin/GroupsRouteADM.scala @@ -62,8 +62,14 @@ class GroupsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wi /* return all groups */ requestContext => val requestMessage = for { - requestingUser <- getUserADM(requestContext) - } yield GroupsGetRequestADM(requestingUser) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + } yield GroupsGetRequestADM( + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -85,9 +91,13 @@ class GroupsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wi entity(as[CreateGroupApiRequestADM]) { apiRequest => requestContext => val requestMessage = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield GroupCreateRequestADM( createRequest = apiRequest, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -114,8 +124,15 @@ class GroupsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wi val checkedGroupIri = stringFormatter.validateAndEscapeIri(value, throw BadRequestException(s"Invalid group IRI $value")) val requestMessage = for { - requestingUser <- getUserADM(requestContext) - } yield GroupGetRequestADM(checkedGroupIri, requestingUser) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + } yield GroupGetRequestADM( + groupIri = checkedGroupIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -148,10 +165,14 @@ class GroupsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wi } val requestMessage = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield GroupChangeRequestADM( groupIri = checkedGroupIri, changeGroupRequest = apiRequest, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -191,10 +212,14 @@ class GroupsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wi } val requestMessage = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield GroupChangeStatusRequestADM( groupIri = checkedGroupIri, changeGroupRequest = apiRequest, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -221,10 +246,14 @@ class GroupsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wi val checkedGroupIri = stringFormatter.validateAndEscapeIri(value, throw BadRequestException(s"Invalid group IRI $value")) val requestMessage = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield GroupChangeStatusRequestADM( groupIri = checkedGroupIri, changeGroupRequest = ChangeGroupApiRequestADM(status = Some(false)), + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -250,8 +279,15 @@ class GroupsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wi val checkedGroupIri = stringFormatter.validateAndEscapeIri(value, throw BadRequestException(s"Invalid group IRI $value")) val requestMessage = for { - requestingUser <- getUserADM(requestContext) - } yield GroupMembersGetRequestADM(groupIri = checkedGroupIri, requestingUser = requestingUser) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + } yield GroupMembersGetRequestADM( + groupIri = checkedGroupIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, diff --git a/webapi/src/main/scala/org/knora/webapi/routing/admin/PermissionsRouteADM.scala b/webapi/src/main/scala/org/knora/webapi/routing/admin/PermissionsRouteADM.scala index 27a5900e6e..b98604e26c 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/admin/PermissionsRouteADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/admin/PermissionsRouteADM.scala @@ -60,7 +60,10 @@ class PermissionsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeDat get { requestContext => val requestMessage = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield AdministrativePermissionForProjectGroupGetRequestADM(projectIri, groupIri, requestingUser) RouteUtilADM.runJsonRoute( @@ -78,7 +81,10 @@ class PermissionsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeDat get { requestContext => val requestMessage = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield AdministrativePermissionsForProjectGetRequestADM( projectIri = projectIri, requestingUser = requestingUser, @@ -100,7 +106,10 @@ class PermissionsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeDat get { requestContext => val requestMessage = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield DefaultObjectAccessPermissionsForProjectGetRequestADM( projectIri = projectIri, requestingUser = requestingUser, @@ -123,9 +132,13 @@ class PermissionsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeDat get { requestContext => val requestMessage = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield PermissionsForProjectGetRequestADM( projectIri = projectIri, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -150,9 +163,13 @@ class PermissionsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeDat entity(as[CreateAdministrativePermissionAPIRequestADM]) { apiRequest => requestContext => val requestMessage = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield AdministrativePermissionCreateRequestADM( createRequest = apiRequest, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -178,9 +195,13 @@ class PermissionsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeDat entity(as[CreateDefaultObjectAccessPermissionAPIRequestADM]) { apiRequest => requestContext => val requestMessage: Future[DefaultObjectAccessPermissionCreateRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield DefaultObjectAccessPermissionCreateRequestADM( createRequest = apiRequest, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) diff --git a/webapi/src/main/scala/org/knora/webapi/routing/admin/ProjectsRouteADM.scala b/webapi/src/main/scala/org/knora/webapi/routing/admin/ProjectsRouteADM.scala index 94628d04fb..ccac3c2358 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/admin/ProjectsRouteADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/admin/ProjectsRouteADM.scala @@ -86,8 +86,14 @@ class ProjectsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) private def getProjects(featureFactoryConfig: FeatureFactoryConfig): Route = path(ProjectsBasePath) { get { requestContext => val requestMessage: Future[ProjectsGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) - } yield ProjectsGetRequestADM(requestingUser = requestingUser) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + } yield ProjectsGetRequestADM( + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -114,9 +120,13 @@ class ProjectsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) entity(as[CreateProjectApiRequestADM]) { apiRequest => requestContext => val requestMessage: Future[ProjectCreateRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield ProjectCreateRequestADM( createRequest = apiRequest, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -138,8 +148,14 @@ class ProjectsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) get { requestContext => val requestMessage: Future[ProjectsKeywordsGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) - } yield ProjectsKeywordsGetRequestADM(requestingUser = requestingUser) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + } yield ProjectsKeywordsGetRequestADM( + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -159,8 +175,15 @@ class ProjectsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) val checkedProjectIri = stringFormatter.validateAndEscapeProjectIri(value, throw BadRequestException(s"Invalid project IRI $value")) val requestMessage: Future[ProjectKeywordsGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) - } yield ProjectKeywordsGetRequestADM(projectIri = checkedProjectIri, requestingUser = requestingUser) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + } yield ProjectKeywordsGetRequestADM( + projectIri = checkedProjectIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -180,10 +203,17 @@ class ProjectsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) get { requestContext => val requestMessage: Future[ProjectGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) checkedProjectIri = stringFormatter.validateAndEscapeProjectIri(value, throw BadRequestException(s"Invalid project IRI $value")) - } yield ProjectGetRequestADM(ProjectIdentifierADM(maybeIri = Some(checkedProjectIri)), requestingUser = requestingUser) + } yield ProjectGetRequestADM( + identifier = ProjectIdentifierADM(maybeIri = Some(checkedProjectIri)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -203,10 +233,17 @@ class ProjectsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) get { requestContext => val requestMessage: Future[ProjectGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) shortNameDec = stringFormatter.validateAndEscapeProjectShortname(value, throw BadRequestException(s"Invalid project shortname $value")) - } yield ProjectGetRequestADM(ProjectIdentifierADM(maybeShortname = Some(shortNameDec)), requestingUser = requestingUser) + } yield ProjectGetRequestADM( + identifier = ProjectIdentifierADM(maybeShortname = Some(shortNameDec)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -226,10 +263,17 @@ class ProjectsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) get { requestContext => val requestMessage: Future[ProjectGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) checkedShortcode = stringFormatter.validateAndEscapeProjectShortcode(value, throw BadRequestException(s"Invalid project shortcode $value")) - } yield ProjectGetRequestADM(ProjectIdentifierADM(maybeShortcode = Some(checkedShortcode)), requestingUser = requestingUser) + } yield ProjectGetRequestADM( + identifier = ProjectIdentifierADM(maybeShortcode = Some(checkedShortcode)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -254,10 +298,14 @@ class ProjectsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) /* the api request is already checked at time of creation. see case class. */ val requestMessage: Future[ProjectChangeRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield ProjectChangeRequestADM( projectIri = checkedProjectIri, changeProjectRequest = apiRequest, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -284,10 +332,14 @@ class ProjectsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) val checkedProjectIri = stringFormatter.validateAndEscapeProjectIri(value, throw BadRequestException(s"Invalid project IRI $value")) val requestMessage: Future[ProjectChangeRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield ProjectChangeRequestADM( projectIri = checkedProjectIri, changeProjectRequest = ChangeProjectApiRequestADM(status = Some(false)), + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -312,10 +364,17 @@ class ProjectsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) requestContext => val requestMessage: Future[ProjectMembersGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) checkedProjectIri = stringFormatter.validateAndEscapeProjectIri(value, throw BadRequestException(s"Invalid project IRI $value")) - } yield ProjectMembersGetRequestADM(ProjectIdentifierADM(maybeIri = Some(checkedProjectIri)), requestingUser = requestingUser) + } yield ProjectMembersGetRequestADM( + identifier = ProjectIdentifierADM(maybeIri = Some(checkedProjectIri)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -336,10 +395,17 @@ class ProjectsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) get { requestContext => val requestMessage: Future[ProjectMembersGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) shortNameDec = stringFormatter.validateAndEscapeProjectShortname(value, throw BadRequestException(s"Invalid project shortname $value")) - } yield ProjectMembersGetRequestADM(ProjectIdentifierADM(maybeShortname = Some(shortNameDec)), requestingUser = requestingUser) + } yield ProjectMembersGetRequestADM( + identifier = ProjectIdentifierADM(maybeShortname = Some(shortNameDec)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -361,10 +427,17 @@ class ProjectsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) requestContext => val requestMessage: Future[ProjectMembersGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) checkedShortcode = stringFormatter.validateAndEscapeProjectShortcode(value, throw BadRequestException(s"Invalid project shortcode $value")) - } yield ProjectMembersGetRequestADM(ProjectIdentifierADM(maybeShortcode = Some(checkedShortcode)), requestingUser = requestingUser) + } yield ProjectMembersGetRequestADM( + identifier = ProjectIdentifierADM(maybeShortcode = Some(checkedShortcode)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -385,10 +458,17 @@ class ProjectsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) get { requestContext => val requestMessage: Future[ProjectAdminMembersGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) checkedProjectIri = stringFormatter.validateAndEscapeProjectIri(value, throw BadRequestException(s"Invalid project IRI $value")) - } yield ProjectAdminMembersGetRequestADM(ProjectIdentifierADM(maybeIri = Some(checkedProjectIri)), requestingUser = requestingUser) + } yield ProjectAdminMembersGetRequestADM( + identifier = ProjectIdentifierADM(maybeIri = Some(checkedProjectIri)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -409,10 +489,17 @@ class ProjectsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) get { requestContext => val requestMessage: Future[ProjectAdminMembersGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) checkedShortname = stringFormatter.validateAndEscapeProjectShortname(value, throw BadRequestException(s"Invalid project shortname $value")) - } yield ProjectAdminMembersGetRequestADM(ProjectIdentifierADM(maybeShortname = Some(checkedShortname)), requestingUser = requestingUser) + } yield ProjectAdminMembersGetRequestADM( + identifier = ProjectIdentifierADM(maybeShortname = Some(checkedShortname)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -433,10 +520,17 @@ class ProjectsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) get { requestContext => val requestMessage: Future[ProjectAdminMembersGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) checkedShortcode = stringFormatter.validateProjectShortcode(value, throw BadRequestException(s"Invalid project shortcode $value")) - } yield ProjectAdminMembersGetRequestADM(ProjectIdentifierADM(maybeShortcode = Some(checkedShortcode)), requestingUser = requestingUser) + } yield ProjectAdminMembersGetRequestADM( + identifier = ProjectIdentifierADM(maybeShortcode = Some(checkedShortcode)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -457,9 +551,16 @@ class ProjectsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) get { requestContext => val requestMessage: Future[ProjectRestrictedViewSettingsGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) - } yield ProjectRestrictedViewSettingsGetRequestADM(ProjectIdentifierADM(maybeIri = Some(value)), requestingUser) + } yield ProjectRestrictedViewSettingsGetRequestADM( + identifier = ProjectIdentifierADM(maybeIri = Some(value)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -480,10 +581,17 @@ class ProjectsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) get { requestContext => val requestMessage: Future[ProjectRestrictedViewSettingsGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) shortNameDec = java.net.URLDecoder.decode(value, "utf-8") - } yield ProjectRestrictedViewSettingsGetRequestADM(ProjectIdentifierADM(maybeShortname = Some(shortNameDec)), requestingUser) + } yield ProjectRestrictedViewSettingsGetRequestADM( + identifier = ProjectIdentifierADM(maybeShortname = Some(shortNameDec)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -504,8 +612,15 @@ class ProjectsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) get { requestContext => val requestMessage: Future[ProjectRestrictedViewSettingsGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) - } yield ProjectRestrictedViewSettingsGetRequestADM(ProjectIdentifierADM(maybeShortcode = Some(value)), requestingUser) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + } yield ProjectRestrictedViewSettingsGetRequestADM( + identifier = ProjectIdentifierADM(maybeShortcode = Some(value)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -528,25 +643,40 @@ class ProjectsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) featureFactoryConfig.makeHttpResponseHeader match { case Some(featureToggleHeader) => respondWithHeaders(projectDataHeader, featureToggleHeader) { - getProjectDataEntity(projectIri) + getProjectDataEntity( + projectIri = projectIri, + featureFactoryConfig = featureFactoryConfig + ) } case None => respondWithHeaders(projectDataHeader) { - getProjectDataEntity(projectIri) + getProjectDataEntity( + projectIri = projectIri, + featureFactoryConfig = featureFactoryConfig + ) } } } } - private def getProjectDataEntity(projectIri: IRI): Route = { + private def getProjectDataEntity(projectIri: IRI, featureFactoryConfig: FeatureFactoryConfig): Route = { requestContext => val projectIdentifier = ProjectIdentifierADM(maybeIri = Some(projectIri)) val httpEntityFuture: Future[HttpEntity.Chunked] = for { - requestingUser <- getUserADM(requestContext) - requestMessage = ProjectDataGetRequestADM(projectIdentifier, requestingUser) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + + requestMessage = ProjectDataGetRequestADM( + projectIdentifier = projectIdentifier, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) + responseMessage <- (responderManager ? requestMessage).mapTo[ProjectDataGetResponseADM] // Stream the output file back to the client, then delete the file. diff --git a/webapi/src/main/scala/org/knora/webapi/routing/admin/SipiRouteADM.scala b/webapi/src/main/scala/org/knora/webapi/routing/admin/SipiRouteADM.scala index d5f3fd79d2..0d81754fc1 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/admin/SipiRouteADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/admin/SipiRouteADM.scala @@ -43,10 +43,18 @@ class SipiRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) with get { requestContext => val requestMessage = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) projectID = stringFormatter.validateProjectShortcode(projectIDAndFile.head, throw BadRequestException(s"Invalid project ID: '${projectIDAndFile.head}'")) filename = stringFormatter.toSparqlEncodedString(projectIDAndFile(1), throw BadRequestException(s"Invalid filename: '${projectIDAndFile(1)}'")) - } yield SipiFileInfoGetRequestADM(projectID = projectID, filename = filename, requestingUser = requestingUser) + } yield SipiFileInfoGetRequestADM( + projectID = projectID, + filename = filename, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, diff --git a/webapi/src/main/scala/org/knora/webapi/routing/admin/StoreRouteADM.scala b/webapi/src/main/scala/org/knora/webapi/routing/admin/StoreRouteADM.scala index 69dc294793..c25c483efb 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/admin/StoreRouteADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/admin/StoreRouteADM.scala @@ -59,7 +59,12 @@ class StoreRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit entity(as[Seq[RdfDataObject]]) { apiRequest => parameter('prependdefaults.as[Boolean] ? true) { prependDefaults => requestContext => - val msg = ResetTriplestoreContentRequestADM(apiRequest, prependDefaults) + val msg = ResetTriplestoreContentRequestADM( + rdfDataObjects = apiRequest, + prependDefaults = prependDefaults, + featureFactoryConfig = featureFactoryConfig + ) + val requestMessage = Future.successful(msg) RouteUtilADM.runJsonRoute( diff --git a/webapi/src/main/scala/org/knora/webapi/routing/admin/UsersRouteADM.scala b/webapi/src/main/scala/org/knora/webapi/routing/admin/UsersRouteADM.scala index aa918178e1..fd726b27af 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/admin/UsersRouteADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/admin/UsersRouteADM.scala @@ -83,8 +83,14 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit get { requestContext => val requestMessage: Future[UsersGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) - } yield UsersGetRequestADM(requestingUser = requestingUser) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + } yield UsersGetRequestADM( + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -111,9 +117,13 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit entity(as[CreateUserApiRequestADM]) { apiRequest => requestContext => val requestMessage: Future[UserCreateRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield UserCreateRequestADM( createRequest = apiRequest, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -137,8 +147,16 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit get { requestContext => val requestMessage: Future[UserGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) - } yield UserGetRequestADM(UserIdentifierADM(maybeIri = Some(value)), UserInformationTypeADM.RESTRICTED, requestingUser) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + } yield UserGetRequestADM( + identifier = UserIdentifierADM(maybeIri = Some(value)), + userInformationTypeADM = UserInformationTypeADM.RESTRICTED, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -158,8 +176,16 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit get { requestContext => val requestMessage: Future[UserGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) - } yield UserGetRequestADM(UserIdentifierADM(maybeEmail = Some(value)), UserInformationTypeADM.RESTRICTED, requestingUser) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + } yield UserGetRequestADM( + identifier = UserIdentifierADM(maybeEmail = Some(value)), + userInformationTypeADM = UserInformationTypeADM.RESTRICTED, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -179,8 +205,16 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit get { requestContext => val requestMessage: Future[UserGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) - } yield UserGetRequestADM(UserIdentifierADM(maybeUsername = Some(value)), UserInformationTypeADM.RESTRICTED, requestingUser) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + } yield UserGetRequestADM( + identifier = UserIdentifierADM(maybeUsername = Some(value)), + userInformationTypeADM = UserInformationTypeADM.RESTRICTED, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -211,11 +245,15 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit /* the api request is already checked at time of creation. see case class. */ val requestMessage: Future[UsersResponderRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield UserChangeBasicUserInformationRequestADM( - userIri, + userIri = userIri, changeUserRequest = apiRequest, - requestingUser, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -249,11 +287,15 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit /* the api request is already checked at time of creation. see case class. */ val requestMessage: Future[UsersResponderRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield UserChangePasswordRequestADM( userIri = userIri, changeUserRequest = apiRequest, - requestingUser, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -287,11 +329,15 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit /* the api request is already checked at time of creation. see case class. */ val requestMessage: Future[UsersResponderRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield UserChangeStatusRequestADM( - userIri, + userIri = userIri, changeUserRequest = apiRequest, - requestingUser, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -322,11 +368,15 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit /* update existing user's status to false */ val requestMessage: Future[UserChangeStatusRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield UserChangeStatusRequestADM( - userIri, + userIri = userIri, changeUserRequest = ChangeUserApiRequestADM(status = Some(false)), - requestingUser, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -360,11 +410,15 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit /* the api request is already checked at time of creation. see case class. */ val requestMessage: Future[UsersResponderRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield UserChangeSystemAdminMembershipStatusRequestADM( - userIri, + userIri = userIri, changeUserRequest = apiRequest, - requestingUser, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -390,11 +444,14 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit val checkedUserIri = stringFormatter.validateAndEscapeUserIri(userIri, throw BadRequestException(s"Invalid user IRI $userIri")) val requestMessage: Future[UserProjectMembershipsGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield UserProjectMembershipsGetRequestADM( userIri = checkedUserIri, - requestingUser = requestingUser, - apiRequestID = UUID.randomUUID() + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser ) RouteUtilADM.runJsonRoute( @@ -419,10 +476,14 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit val checkedProjectIri = stringFormatter.validateAndEscapeProjectIri(projectIri, throw BadRequestException(s"Invalid project IRI $projectIri")) val requestMessage: Future[UserProjectMembershipAddRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield UserProjectMembershipAddRequestADM( userIri = checkedUserIri, projectIri = checkedProjectIri, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -450,10 +511,14 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit val checkedProjectIri = stringFormatter.validateAndEscapeProjectIri(projectIri, throw BadRequestException(s"Invalid project IRI $projectIri")) val requestMessage: Future[UserProjectMembershipRemoveRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield UserProjectMembershipRemoveRequestADM( userIri = checkedUserIri, projectIri = checkedProjectIri, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -479,9 +544,13 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit val checkedUserIri = stringFormatter.validateAndEscapeUserIri(userIri, throw BadRequestException(s"Invalid user IRI $userIri")) val requestMessage: Future[UserProjectAdminMembershipsGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield UserProjectAdminMembershipsGetRequestADM( userIri = checkedUserIri, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -509,10 +578,14 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit val checkedProjectIri = stringFormatter.validateAndEscapeProjectIri(projectIri, throw BadRequestException(s"Invalid project IRI $projectIri")) val requestMessage: Future[UserProjectAdminMembershipAddRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield UserProjectAdminMembershipAddRequestADM( userIri = checkedUserIri, projectIri = checkedProjectIri, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -539,10 +612,14 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit val checkedProjectIri = stringFormatter.validateAndEscapeProjectIri(projectIri, throw BadRequestException(s"Invalid project IRI $projectIri")) val requestMessage: Future[UserProjectAdminMembershipRemoveRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield UserProjectAdminMembershipRemoveRequestADM( userIri = checkedUserIri, projectIri = checkedProjectIri, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -568,11 +645,14 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit val checkedUserIri = stringFormatter.validateAndEscapeUserIri(userIri, throw BadRequestException(s"Invalid user IRI $userIri")) val requestMessage: Future[UserGroupMembershipsGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield UserGroupMembershipsGetRequestADM( userIri = checkedUserIri, - requestingUser = requestingUser, - apiRequestID = UUID.randomUUID() + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser ) RouteUtilADM.runJsonRoute( @@ -597,10 +677,14 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit val checkedGroupIri = stringFormatter.validateAndEscapeIri(groupIri, throw BadRequestException(s"Invalid group IRI $groupIri")) val requestMessage: Future[UserGroupMembershipAddRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield UserGroupMembershipAddRequestADM( userIri = checkedUserIri, groupIri = checkedGroupIri, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -627,10 +711,14 @@ class UsersRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit val checkedGroupIri = stringFormatter.validateAndEscapeIri(groupIri, throw BadRequestException(s"Invalid group IRI $groupIri")) val requestMessage: Future[UserGroupMembershipRemoveRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield UserGroupMembershipRemoveRequestADM( userIri = checkedUserIri, groupIri = checkedGroupIri, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) diff --git a/webapi/src/main/scala/org/knora/webapi/routing/admin/lists/NewListsRouteADMFeature.scala b/webapi/src/main/scala/org/knora/webapi/routing/admin/lists/NewListsRouteADMFeature.scala index afbcff75e6..5a718c62bc 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/admin/lists/NewListsRouteADMFeature.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/admin/lists/NewListsRouteADMFeature.scala @@ -73,8 +73,15 @@ class NewListsRouteADMFeature(routeData: KnoraRouteData) extends KnoraRoute(rout val projectIri = stringFormatter.toOptionalIri(maybeProjectIri, throw BadRequestException(s"Invalid param project IRI: $maybeProjectIri")) val requestMessage: Future[ListsGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) - } yield ListsGetRequestADM(projectIri, requestingUser) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + } yield ListsGetRequestADM( + projectIri = projectIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -103,9 +110,13 @@ class NewListsRouteADMFeature(routeData: KnoraRouteData) extends KnoraRoute(rout entity(as[CreateListApiRequestADM]) { apiRequest => requestContext => val requestMessage: Future[ListCreateRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield ListCreateRequestADM( createListRequest = apiRequest, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -170,10 +181,14 @@ class NewListsRouteADMFeature(routeData: KnoraRouteData) extends KnoraRoute(rout val listIri = stringFormatter.validateAndEscapeIri(iri, throw BadRequestException(s"Invalid param list IRI: $iri")) val requestMessage: Future[ListInfoChangeRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield ListInfoChangeRequestADM( listIri = listIri, changeListRequest = apiRequest, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -210,10 +225,14 @@ class NewListsRouteADMFeature(routeData: KnoraRouteData) extends KnoraRoute(rout val parentNodeIri = stringFormatter.validateAndEscapeIri(iri, throw BadRequestException(s"Invalid param list IRI: $iri")) val requestMessage: Future[ListChildNodeCreateRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield ListChildNodeCreateRequestADM( parentNodeIri = parentNodeIri, createChildNodeRequest = apiRequest, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -246,8 +265,15 @@ class NewListsRouteADMFeature(routeData: KnoraRouteData) extends KnoraRoute(rout val listIri = stringFormatter.validateAndEscapeIri(iri, throw BadRequestException(s"Invalid param list IRI: $iri")) val requestMessage: Future[ListInfoGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) - } yield ListInfoGetRequestADM(listIri, requestingUser) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + } yield ListInfoGetRequestADM( + iri = listIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -267,8 +293,15 @@ class NewListsRouteADMFeature(routeData: KnoraRouteData) extends KnoraRoute(rout val listIri = stringFormatter.validateAndEscapeIri(iri, throw BadRequestException(s"Invalid param list IRI: $iri")) val requestMessage: Future[ListNodeInfoGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) - } yield ListNodeInfoGetRequestADM(listIri, requestingUser) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + } yield ListNodeInfoGetRequestADM( + iri = listIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, diff --git a/webapi/src/main/scala/org/knora/webapi/routing/admin/lists/OldListsRouteADMFeature.scala b/webapi/src/main/scala/org/knora/webapi/routing/admin/lists/OldListsRouteADMFeature.scala index 633ab1f385..bf74f7c04d 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/admin/lists/OldListsRouteADMFeature.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/admin/lists/OldListsRouteADMFeature.scala @@ -71,8 +71,15 @@ class OldListsRouteADMFeature(routeData: KnoraRouteData) extends KnoraRoute(rout val projectIri = stringFormatter.toOptionalIri(maybeProjectIri, throw BadRequestException(s"Invalid param project IRI: $maybeProjectIri")) val requestMessage: Future[ListsGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) - } yield ListsGetRequestADM(projectIri, requestingUser) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + } yield ListsGetRequestADM( + projectIri = projectIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -101,9 +108,13 @@ class OldListsRouteADMFeature(routeData: KnoraRouteData) extends KnoraRoute(rout entity(as[CreateListApiRequestADM]) { apiRequest => requestContext => val requestMessage: Future[ListCreateRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield ListCreateRequestADM( createListRequest = apiRequest, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -133,8 +144,15 @@ class OldListsRouteADMFeature(routeData: KnoraRouteData) extends KnoraRoute(rout val listIri = stringFormatter.validateAndEscapeIri(iri, throw BadRequestException(s"Invalid param list IRI: $iri")) val requestMessage: Future[ListGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) - } yield ListGetRequestADM(listIri, requestingUser) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + } yield ListGetRequestADM( + iri = listIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -167,10 +185,14 @@ class OldListsRouteADMFeature(routeData: KnoraRouteData) extends KnoraRoute(rout val listIri = stringFormatter.validateAndEscapeIri(iri, throw BadRequestException(s"Invalid param list IRI: $iri")) val requestMessage: Future[ListInfoChangeRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield ListInfoChangeRequestADM( listIri = listIri, changeListRequest = apiRequest, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -207,10 +229,14 @@ class OldListsRouteADMFeature(routeData: KnoraRouteData) extends KnoraRoute(rout val parentNodeIri = stringFormatter.validateAndEscapeIri(iri, throw BadRequestException(s"Invalid param list IRI: $iri")) val requestMessage: Future[ListChildNodeCreateRequestADM] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield ListChildNodeCreateRequestADM( parentNodeIri = parentNodeIri, createChildNodeRequest = apiRequest, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID() ) @@ -243,8 +269,15 @@ class OldListsRouteADMFeature(routeData: KnoraRouteData) extends KnoraRoute(rout val listIri = stringFormatter.validateAndEscapeIri(iri, throw BadRequestException(s"Invalid param list IRI: $iri")) val requestMessage: Future[ListInfoGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) - } yield ListInfoGetRequestADM(listIri, requestingUser) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + } yield ListInfoGetRequestADM( + iri = listIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, @@ -264,8 +297,15 @@ class OldListsRouteADMFeature(routeData: KnoraRouteData) extends KnoraRoute(rout val listIri = stringFormatter.validateAndEscapeIri(iri, throw BadRequestException(s"Invalid param list IRI: $iri")) val requestMessage: Future[ListNodeInfoGetRequestADM] = for { - requestingUser <- getUserADM(requestContext) - } yield ListNodeInfoGetRequestADM(listIri, requestingUser) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + } yield ListNodeInfoGetRequestADM( + iri = listIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilADM.runJsonRoute( requestMessageF = requestMessage, diff --git a/webapi/src/main/scala/org/knora/webapi/routing/v1/AuthenticationRouteV1.scala b/webapi/src/main/scala/org/knora/webapi/routing/v1/AuthenticationRouteV1.scala index b9c9fda54b..2fcd277575 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/v1/AuthenticationRouteV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/v1/AuthenticationRouteV1.scala @@ -38,7 +38,10 @@ class AuthenticationRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeD get { requestContext => { requestContext.complete { - doAuthenticateV1(requestContext) + doAuthenticateV1( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } } } @@ -50,16 +53,25 @@ class AuthenticationRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeD if (params.contains("logout")) { doLogoutV2(requestContext) } else if (params.contains("login")) { - doLoginV1(requestContext) + doLoginV1( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } else { - doAuthenticateV1(requestContext) + doAuthenticateV1( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } } } } ~ post { requestContext => { requestContext.complete { - doLoginV1(requestContext) + doLoginV1( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } } } ~ delete { diff --git a/webapi/src/main/scala/org/knora/webapi/routing/v1/CkanRouteV1.scala b/webapi/src/main/scala/org/knora/webapi/routing/v1/CkanRouteV1.scala index d0bcb7b111..ad803cfe02 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/v1/CkanRouteV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/v1/CkanRouteV1.scala @@ -40,12 +40,21 @@ class CkanRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) with requestContext => val requestMessage = for { - userProfile <- getUserADM(requestContext) + userProfile <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) params = requestContext.request.uri.query().toMap project: Option[Seq[String]] = params.get("project").map(_.split(",")) limit: Option[Int] = params.get("limit").map(_.toInt) info: Boolean = params.getOrElse("info", false) == true - } yield CkanRequestV1(project, limit, info, userProfile) + } yield CkanRequestV1( + projects = project, + limit = limit, + info = info, + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) RouteUtilV1.runJsonRouteWithFuture( requestMessage, diff --git a/webapi/src/main/scala/org/knora/webapi/routing/v1/ListsRouteV1.scala b/webapi/src/main/scala/org/knora/webapi/routing/v1/ListsRouteV1.scala index f0e1150188..3f008ed10b 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/v1/ListsRouteV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/v1/ListsRouteV1.scala @@ -44,7 +44,10 @@ class ListsRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) with requestContext => val requestMessageFuture = for { - userProfile <- getUserADM(requestContext).map(_.asUserProfileV1) + userProfile <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ).map(_.asUserProfileV1) listIri = stringFormatter.validateAndEscapeIri(iri, throw BadRequestException(s"Invalid param list IRI: $iri")) requestMessage = requestContext.request.uri.query().get("reqtype") match { @@ -68,7 +71,10 @@ class ListsRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) with get { requestContext => val requestMessageFuture = for { - userProfile <- getUserADM(requestContext).map(_.asUserProfileV1) + userProfile <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ).map(_.asUserProfileV1) selIri = stringFormatter.validateAndEscapeIri(iri, throw BadRequestException(s"Invalid param list IRI: $iri")) requestMessage = requestContext.request.uri.query().get("reqtype") match { diff --git a/webapi/src/main/scala/org/knora/webapi/routing/v1/ProjectsRouteV1.scala b/webapi/src/main/scala/org/knora/webapi/routing/v1/ProjectsRouteV1.scala index 0704a5f743..c8c90f849c 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/v1/ProjectsRouteV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/v1/ProjectsRouteV1.scala @@ -30,9 +30,6 @@ import org.knora.webapi.routing.{Authenticator, KnoraRoute, KnoraRouteData, Rout class ProjectsRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) with Authenticator with ProjectV1JsonProtocol { - private val schemes = Array("http", "https") - private val urlValidator = new UrlValidator(schemes) - /** * Returns the route. */ @@ -43,9 +40,14 @@ class ProjectsRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) w /* returns all projects */ requestContext => val requestMessage = for { - userProfile <- getUserADM(requestContext).map(_.asUserProfileV1) - } yield ProjectsGetRequestV1(Some(userProfile)) - + userProfile <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ).map(_.asUserProfileV1) + } yield ProjectsGetRequestV1( + featureFactoryConfig = featureFactoryConfig, + userProfile = Some(userProfile) + ) RouteUtilV1.runJsonRouteWithFuture( requestMessage, @@ -64,13 +66,27 @@ class ProjectsRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) w val requestMessage = if (identifier != "iri") { // identify project by shortname. val shortNameDec = java.net.URLDecoder.decode(value, "utf-8") for { - userProfile <- getUserADM(requestContext).map(_.asUserProfileV1) - } yield ProjectInfoByShortnameGetRequestV1(shortNameDec, Some(userProfile)) + userProfile <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ).map(_.asUserProfileV1) + } yield ProjectInfoByShortnameGetRequestV1( + shortname = shortNameDec, + featureFactoryConfig = featureFactoryConfig, + userProfileV1 = Some(userProfile) + ) } else { // identify project by iri. this is the default case. val checkedProjectIri = stringFormatter.validateAndEscapeIri(value, throw BadRequestException(s"Invalid project IRI $value")) for { - userProfile <- getUserADM(requestContext).map(_.asUserProfileV1) - } yield ProjectInfoByIRIGetRequestV1(checkedProjectIri, Some(userProfile)) + userProfile <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ).map(_.asUserProfileV1) + } yield ProjectInfoByIRIGetRequestV1( + iri = checkedProjectIri, + featureFactoryConfig = featureFactoryConfig, + userProfileV1 = Some(userProfile) + ) } RouteUtilV1.runJsonRouteWithFuture( diff --git a/webapi/src/main/scala/org/knora/webapi/routing/v1/ResourceTypesRouteV1.scala b/webapi/src/main/scala/org/knora/webapi/routing/v1/ResourceTypesRouteV1.scala index 592f04b412..2a7368048d 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/v1/ResourceTypesRouteV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/v1/ResourceTypesRouteV1.scala @@ -41,7 +41,10 @@ class ResourceTypesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeDa requestContext => val requestMessage = for { - userProfile <- getUserADM(requestContext) + userProfile <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) // TODO: Check that this is the IRI of a resource type and not just any IRI resourceTypeIri = stringFormatter.validateAndEscapeIri(iri, throw BadRequestException(s"Invalid resource class IRI: $iri")) @@ -62,7 +65,10 @@ class ResourceTypesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeDa requestContext => val requestMessage = for { - userADM <- getUserADM(requestContext) + userADM <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) params = requestContext.request.uri.query().toMap vocabularyId = params.getOrElse("vocabulary", throw BadRequestException("Required param vocabulary is missing")) @@ -72,7 +78,11 @@ class ResourceTypesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeDa case other => Some(stringFormatter.validateAndEscapeIri(vocabularyId, throw BadRequestException(s"Invalid vocabulary IRI: $vocabularyId"))) } - } yield ResourceTypesForNamedGraphGetRequestV1(namedGraphIri, userADM) + } yield ResourceTypesForNamedGraphGetRequestV1( + namedGraph = namedGraphIri, + featureFactoryConfig = featureFactoryConfig, + userADM = userADM + ) RouteUtilV1.runJsonRouteWithFuture( requestMessage, @@ -88,7 +98,10 @@ class ResourceTypesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeDa requestContext => val requestMessage = for { - userADM <- getUserADM(requestContext) + userADM <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) params = requestContext.request.uri.query().toMap vocabularyId: Option[String] = params.get("vocabulary") @@ -98,17 +111,31 @@ class ResourceTypesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeDa _ = if (vocabularyId.nonEmpty && resourcetypeId.nonEmpty) throw BadRequestException("Both vocabulary and restype params are set, only one is allowed") } yield vocabularyId match { case Some("0") => // 0 means that all named graphs should be queried - PropertyTypesForNamedGraphGetRequestV1(namedGraph = None, userADM = userADM) + PropertyTypesForNamedGraphGetRequestV1( + namedGraph = None, + featureFactoryConfig = featureFactoryConfig, + userADM = userADM + ) + case Some(vocId) => val namedGraphIri = stringFormatter.validateAndEscapeIri(vocId, throw BadRequestException(s"Invalid vocabulary IRI: $vocabularyId")) - PropertyTypesForNamedGraphGetRequestV1(namedGraph = Some(namedGraphIri), userADM = userADM) + PropertyTypesForNamedGraphGetRequestV1( + namedGraph = Some(namedGraphIri), + featureFactoryConfig = featureFactoryConfig, + userADM = userADM + ) + case None => // no vocabulary id given, check for restype resourcetypeId match { case Some(restypeId) => // get property types for given resource type val resourceClassIri = stringFormatter.validateAndEscapeIri(restypeId, throw BadRequestException(s"Invalid vocabulary IRI: $restypeId")) PropertyTypesForResourceTypeGetRequestV1(restypeId, userADM) case None => // no params given, get all property types (behaves like vocbulary=0) - PropertyTypesForNamedGraphGetRequestV1(namedGraph = None, userADM = userADM) + PropertyTypesForNamedGraphGetRequestV1( + namedGraph = None, + featureFactoryConfig = featureFactoryConfig, + userADM = userADM + ) } } @@ -125,8 +152,14 @@ class ResourceTypesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeDa get { requestContext => val requestMessage = for { - userADM <- getUserADM(requestContext) - } yield NamedGraphsGetRequestV1(userADM = userADM) + userADM <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + } yield NamedGraphsGetRequestV1( + featureFactoryConfig = featureFactoryConfig, + userADM = userADM + ) RouteUtilV1.runJsonRouteWithFuture( requestMessage, @@ -141,8 +174,14 @@ class ResourceTypesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeDa get { requestContext => val requestMessage = for { - userADM <- getUserADM(requestContext) - } yield LoadOntologiesRequest(userADM) + userADM <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + } yield LoadOntologiesRequestV1( + featureFactoryConfig = featureFactoryConfig, + userADM = userADM + ) RouteUtilV1.runJsonRouteWithFuture( requestMessage, @@ -158,7 +197,10 @@ class ResourceTypesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeDa requestContext => val requestMessage = for { - userADM <- getUserADM(requestContext) + userADM <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) // TODO: Check that this is the IRI of a resource type and not just any IRI resourceClassIri = stringFormatter.validateAndEscapeIri(iri, throw BadRequestException(s"Invalid resource class IRI: $iri")) diff --git a/webapi/src/main/scala/org/knora/webapi/routing/v1/ResourcesRouteV1.scala b/webapi/src/main/scala/org/knora/webapi/routing/v1/ResourcesRouteV1.scala index e8a8a2d44a..17d81fd10b 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/v1/ResourcesRouteV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/v1/ResourcesRouteV1.scala @@ -79,10 +79,32 @@ class ResourcesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) val validResIri = stringFormatter.validateAndEscapeIri(resIri, throw BadRequestException(s"Invalid resource IRI: $resIri")) requestType match { - case "info" => ResourceInfoGetRequestV1(iri = validResIri, userProfile = userADM) - case "rights" => ResourceRightsGetRequestV1(validResIri, userADM) - case "context" => ResourceContextGetRequestV1(validResIri, userADM, resinfo) - case "" => ResourceFullGetRequestV1(validResIri, userADM) + case "info" => ResourceInfoGetRequestV1( + iri = validResIri, + featureFactoryConfig = featureFactoryConfig, + userProfile = userADM + ) + + case "rights" => ResourceRightsGetRequestV1( + iri = validResIri, + featureFactoryConfig = featureFactoryConfig, + userProfile = userADM + ) + + case "context" => ResourceContextGetRequestV1( + iri = validResIri, + featureFactoryConfig = featureFactoryConfig, + userProfile = userADM, + resinfo = resinfo + ) + + case "" => + ResourceFullGetRequestV1( + iri = validResIri, + featureFactoryConfig = featureFactoryConfig, + userADM = userADM + ) + case other => throw BadRequestException(s"Invalid request type: $other") } } @@ -129,6 +151,7 @@ class ResourcesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) mappingIri = mappingIri, acceptStandoffLinksToClientIDs = acceptStandoffLinksToClientIDs, userProfile = userProfile, + featureFactoryConfig = featureFactoryConfig, settings = settings, responderManager = responderManager, log = log @@ -221,14 +244,20 @@ class ResourcesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) } - def makeCreateResourceRequestMessage(apiRequest: CreateResourceApiRequestV1, userADM: UserADM): Future[ResourceCreateRequestV1] = { + def makeCreateResourceRequestMessage(apiRequest: CreateResourceApiRequestV1, + featureFactoryConfig: FeatureFactoryConfig, + userADM: UserADM): Future[ResourceCreateRequestV1] = { val projectIri = stringFormatter.validateAndEscapeIri(apiRequest.project_id, throw BadRequestException(s"Invalid project IRI: ${apiRequest.project_id}")) val resourceTypeIri = stringFormatter.validateAndEscapeIri(apiRequest.restype_id, throw BadRequestException(s"Invalid resource IRI: ${apiRequest.restype_id}")) val label = stringFormatter.toSparqlEncodedString(apiRequest.label, throw BadRequestException(s"Invalid label: '${apiRequest.label}'")) for { projectShortcode: String <- for { - projectResponse: ProjectGetResponseADM <- (responderManager ? ProjectGetRequestADM(ProjectIdentifierADM(maybeIri = Some(projectIri)), requestingUser = userADM)).mapTo[ProjectGetResponseADM] + projectResponse: ProjectGetResponseADM <- (responderManager ? ProjectGetRequestADM( + ProjectIdentifierADM(maybeIri = Some(projectIri)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = userADM + )).mapTo[ProjectGetResponseADM] } yield projectResponse.project.shortcode file: Option[FileValueV1] <- apiRequest.file match { @@ -266,6 +295,7 @@ class ResourcesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) projectIri = projectIri, values = valuesToBeCreated.toMap, file = file, + featureFactoryConfig = featureFactoryConfig, userProfile = userADM, apiRequestID = UUID.randomUUID ) @@ -313,7 +343,11 @@ class ResourcesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) ) } - def makeMultiResourcesRequestMessage(resourceRequest: Seq[CreateResourceFromXmlImportRequestV1], projectId: IRI, apiRequestID: UUID, userProfile: UserADM): Future[MultipleResourceCreateRequestV1] = { + def makeMultiResourcesRequestMessage(resourceRequest: Seq[CreateResourceFromXmlImportRequestV1], + projectId: IRI, + apiRequestID: UUID, + featureFactoryConfig: FeatureFactoryConfig, + userProfile: UserADM): Future[MultipleResourceCreateRequestV1] = { // Make sure there are no duplicate client resource IDs. val duplicateClientIDs: immutable.Iterable[String] = resourceRequest.map(_.client_id).groupBy(identity).collect { case (clientID, occurrences) if occurrences.size > 1 => clientID } @@ -324,7 +358,11 @@ class ResourcesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) for { projectShortcode: String <- for { - projectResponse: ProjectGetResponseADM <- (responderManager ? ProjectGetRequestADM(ProjectIdentifierADM(maybeIri = Some(projectId)), requestingUser = userProfile)).mapTo[ProjectGetResponseADM] + projectResponse: ProjectGetResponseADM <- (responderManager ? ProjectGetRequestADM( + identifier = ProjectIdentifierADM(maybeIri = Some(projectId)), + featureFactoryConfig = featureFactoryConfig, + requestingUser = userProfile + )).mapTo[ProjectGetResponseADM] } yield projectResponse.project.shortcode resourcesToCreate: Seq[Future[OneOfMultipleResourceCreateRequestV1]] = resourceRequest.map { @@ -340,19 +378,25 @@ class ResourcesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) } yield MultipleResourceCreateRequestV1( resourcesToCreate = resToCreateCollection, projectIri = projectId, + featureFactoryConfig = featureFactoryConfig, userProfile = userProfile, apiRequestID = apiRequestID ) } - def makeGetPropertiesRequestMessage(resIri: IRI, userADM: UserADM) = { - PropertiesGetRequestV1(resIri, userADM) + def makeGetPropertiesRequestMessage(resIri: IRI, userADM: UserADM): PropertiesGetRequestV1 = { + PropertiesGetRequestV1( + iri = resIri, + featureFactoryConfig = featureFactoryConfig, + userProfile = userADM + ) } - def makeResourceDeleteMessage(resIri: IRI, deleteComment: Option[String], userADM: UserADM) = { + def makeResourceDeleteMessage(resIri: IRI, deleteComment: Option[String], userADM: UserADM): ResourceDeleteRequestV1 = { ResourceDeleteRequestV1( resourceIri = stringFormatter.validateAndEscapeIri(resIri, throw BadRequestException(s"Invalid resource IRI: $resIri")), deleteComment = deleteComment.map(comment => stringFormatter.toSparqlEncodedString(comment, throw BadRequestException(s"Invalid comment: '$comment'"))), + featureFactoryConfig = featureFactoryConfig, userADM = userADM, apiRequestID = UUID.randomUUID ) @@ -900,7 +944,10 @@ class ResourcesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) val requestMessage = for { - userProfile <- getUserADM(requestContext) + userProfile <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) params = requestContext.request.uri.query().toMap searchstr = params.getOrElse("searchstr", throw BadRequestException(s"required param searchstr is missing")) @@ -947,8 +994,15 @@ class ResourcesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) entity(as[CreateResourceApiRequestV1]) { apiRequest => requestContext => val requestMessageFuture = for { - userProfile <- getUserADM(requestContext) - request <- makeCreateResourceRequestMessage(apiRequest = apiRequest, userADM = userProfile) + userProfile <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + request <- makeCreateResourceRequestMessage( + apiRequest = apiRequest, + featureFactoryConfig = featureFactoryConfig, + userADM = userProfile + ) } yield request RouteUtilV1.runJsonRouteWithFuture( @@ -967,7 +1021,10 @@ class ResourcesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) val requestMessage = for { - userADM <- getUserADM(requestContext) + userADM <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) requestType = reqtypeParam.getOrElse("") resinfo = resinfoParam.getOrElse(false) } yield makeResourceRequestMessage(resIri = resIri, resinfo = resinfo, requestType = requestType, userADM = userADM) @@ -985,7 +1042,10 @@ class ResourcesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) requestContext => val requestMessage = for { - userADM <- getUserADM(requestContext) + userADM <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield makeResourceDeleteMessage(resIri = resIri, deleteComment = deleteCommentParam, userADM = userADM) RouteUtilV1.runJsonRouteWithFuture( @@ -1007,9 +1067,16 @@ class ResourcesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) val requestMessage = requestType match { case "properties" => for { - userADM <- getUserADM(requestContext) + userADM <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) resIri = stringFormatter.validateAndEscapeIri(iri, throw BadRequestException(s"Invalid param resource IRI: $iri")) - } yield ResourceFullGetRequestV1(resIri, userADM) + } yield ResourceFullGetRequestV1( + iri = resIri, + featureFactoryConfig = featureFactoryConfig, + userADM = userADM + ) case other => throw BadRequestException(s"Invalid request type: $other") } @@ -1026,7 +1093,10 @@ class ResourcesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) get { requestContext => val requestMessage = for { - userADM <- getUserADM(requestContext) + userADM <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) resIri = stringFormatter.validateAndEscapeIri(iri, throw BadRequestException(s"Invalid param resource IRI: $iri")) } yield makeGetPropertiesRequestMessage(resIri, userADM) @@ -1044,13 +1114,17 @@ class ResourcesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) entity(as[ChangeResourceLabelApiRequestV1]) { apiRequest => requestContext => val requestMessage = for { - userADM <- getUserADM(requestContext) + userADM <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) resIri = stringFormatter.validateAndEscapeIri(iri, throw BadRequestException(s"Invalid param resource IRI: $iri")) label = stringFormatter.toSparqlEncodedString(apiRequest.label, throw BadRequestException(s"Invalid label: '${apiRequest.label}'")) } yield ChangeResourceLabelRequestV1( resourceIri = resIri, label = label, apiRequestID = UUID.randomUUID, + featureFactoryConfig = featureFactoryConfig, userADM = userADM ) @@ -1068,7 +1142,10 @@ class ResourcesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) parameters("depth".as[Int].?) { depth => requestContext => val requestMessage = for { - userADM <- getUserADM(requestContext) + userADM <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) resourceIri = stringFormatter.validateAndEscapeIri(iri, throw BadRequestException(s"Invalid param resource IRI: $iri")) } yield GraphDataGetRequestV1(resourceIri, depth.getOrElse(4), userADM) @@ -1106,7 +1183,10 @@ class ResourcesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) entity(as[String]) { xml => requestContext => val requestMessage = for { - userADM <- getUserADM(requestContext) + userADM <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) _ = if (userADM.isAnonymousUser) { throw ForbiddenException("You are not logged in, and only a system administrator or project administrator can perform a bulk import") @@ -1140,7 +1220,14 @@ class ResourcesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) // Make a MultipleResourceCreateRequestV1 for the creation of all the resources. apiRequestID: UUID = UUID.randomUUID - updateRequest: MultipleResourceCreateRequestV1 <- makeMultiResourcesRequestMessage(resourcesToCreate, projectId, apiRequestID, userADM) + + updateRequest: MultipleResourceCreateRequestV1 <- makeMultiResourcesRequestMessage( + resourceRequest = resourcesToCreate, + projectId = projectId, + apiRequestID = apiRequestID, + featureFactoryConfig = featureFactoryConfig, + userProfile = userADM + ) } yield updateRequest RouteUtilV1.runJsonRouteWithFuture( @@ -1167,7 +1254,10 @@ class ResourcesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) respondWithHeader(`Content-Disposition`(ContentDispositionTypes.attachment, Map("filename" -> (internalOntologyPrefixLabel + "-xml-schemas.zip")))) { requestContext => val httpResponseFuture: Future[HttpResponse] = for { - userProfile <- getUserADM(requestContext) + userProfile <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) schemaZipFileBytes: Array[Byte] <- generateSchemaZipFile( internalOntologyIri = internalOntologyIri, userProfile = userProfile diff --git a/webapi/src/main/scala/org/knora/webapi/routing/v1/SearchRouteV1.scala b/webapi/src/main/scala/org/knora/webapi/routing/v1/SearchRouteV1.scala index da01c19865..63f4534dce 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/v1/SearchRouteV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/v1/SearchRouteV1.scala @@ -192,7 +192,10 @@ class SearchRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit get { requestContext => { val requestMessage = for { - userADM <- getUserADM(requestContext) + userADM <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) params: Map[String, Seq[String]] = requestContext.request.uri.query().toMultiMap } yield makeExtendedSearchRequestMessage(userADM, params) @@ -210,7 +213,10 @@ class SearchRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit get { requestContext => { val requestMessage = for { - userADM <- getUserADM(requestContext) + userADM <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) params: Map[String, String] = requestContext.request.uri.query().toMap } yield makeFulltextSearchRequestMessage(userADM, searchval, params) diff --git a/webapi/src/main/scala/org/knora/webapi/routing/v1/StandoffRouteV1.scala b/webapi/src/main/scala/org/knora/webapi/routing/v1/StandoffRouteV1.scala index ffc9a9335e..a04d2f6c2a 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/v1/StandoffRouteV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/v1/StandoffRouteV1.scala @@ -58,15 +58,14 @@ class StandoffRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) w // collect all parts of the multipart as it arrives into a map val allPartsFuture: Future[Map[Name, String]] = formdata.parts.mapAsync[(Name, String)](1) { - case b: BodyPart if b.name == JSON_PART => { + case b: BodyPart if b.name == JSON_PART => //loggingAdapter.debug(s"inside allPartsFuture - processing $JSON_PART") b.toStrict(2.seconds).map { strict => //loggingAdapter.debug(strict.entity.data.utf8String) (b.name, strict.entity.data.utf8String) } - } - case b: BodyPart if b.name == XML_PART => { + case b: BodyPart if b.name == XML_PART => //loggingAdapter.debug(s"inside allPartsFuture - processing $XML_PART") b.toStrict(2.seconds).map { @@ -75,7 +74,6 @@ class StandoffRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) w (b.name, strict.entity.data.utf8String) } - } case b: BodyPart if b.name.isEmpty => throw BadRequestException("part of HTTP multipart request has no name") case b: BodyPart => throw BadRequestException(s"multipart contains invalid name: ${b.name}") case _ => throw BadRequestException("multipart request could not be handled") @@ -83,7 +81,10 @@ class StandoffRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) w val requestMessageFuture: Future[CreateMappingRequestV1] = for { - userProfile <- getUserADM(requestContext) + userProfile <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) allParts: Map[Name, String] <- allPartsFuture @@ -98,13 +99,13 @@ class StandoffRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) w } xml: String = allParts.getOrElse(XML_PART, throw BadRequestException(s"MultiPart POST request was sent without required '$XML_PART' part!")).toString - } yield CreateMappingRequestV1( - projectIri = stringFormatter.validateAndEscapeIri(standoffApiJSONRequest.project_id, throw BadRequestException("invalid project IRI")), xml = xml, - userProfile = userProfile, label = stringFormatter.toSparqlEncodedString(standoffApiJSONRequest.label, throw BadRequestException("'label' contains invalid characters")), + projectIri = stringFormatter.validateAndEscapeIri(standoffApiJSONRequest.project_id, throw BadRequestException("invalid project IRI")), mappingName = stringFormatter.toSparqlEncodedString(standoffApiJSONRequest.mappingName, throw BadRequestException("'mappingName' contains invalid characters")), + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile, apiRequestID = UUID.randomUUID ) diff --git a/webapi/src/main/scala/org/knora/webapi/routing/v1/UsersRouteV1.scala b/webapi/src/main/scala/org/knora/webapi/routing/v1/UsersRouteV1.scala index af3f9c8993..2fe0f0845d 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/v1/UsersRouteV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/v1/UsersRouteV1.scala @@ -48,7 +48,10 @@ class UsersRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) with /* return all users */ requestContext => val requestMessage = for { - userProfile <- getUserADM(requestContext).map(_.asUserProfileV1) + userProfile <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ).map(_.asUserProfileV1) } yield UsersGetRequestV1(userProfile) RouteUtilV1.runJsonRouteWithFuture( @@ -69,13 +72,29 @@ class UsersRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) with /* check if email or iri was supplied */ val requestMessage = if (identifier == "email") { for { - userProfile <- getUserADM(requestContext).map(_.asUserProfileV1) - } yield UserProfileByEmailGetRequestV1(value, UserProfileTypeV1.RESTRICTED, userProfile) + userProfile <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ).map(_.asUserProfileV1) + } yield UserProfileByEmailGetRequestV1( + email = value, + userProfileType = UserProfileTypeV1.RESTRICTED, + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) } else { for { - userProfile <- getUserADM(requestContext).map(_.asUserProfileV1) + userProfile <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ).map(_.asUserProfileV1) userIri = stringFormatter.validateAndEscapeIri(value, throw BadRequestException(s"Invalid user IRI $value")) - } yield UserProfileByIRIGetRequestV1(userIri, UserProfileTypeV1.RESTRICTED, userProfile) + } yield UserProfileByIRIGetRequestV1( + userIri = userIri, + userProfileType = UserProfileTypeV1.RESTRICTED, + featureFactoryConfig = featureFactoryConfig, + userProfile = userProfile + ) } RouteUtilV1.runJsonRouteWithFuture( @@ -94,7 +113,10 @@ class UsersRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) with requestContext => val requestMessage = for { - userProfile <- getUserADM(requestContext).map(_.asUserProfileV1) + userProfile <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ).map(_.asUserProfileV1) checkedUserIri = stringFormatter.validateAndEscapeIri(userIri, throw BadRequestException(s"Invalid user IRI $userIri")) } yield UserProjectMembershipsGetRequestV1( userIri = checkedUserIri, @@ -117,7 +139,10 @@ class UsersRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) with requestContext => val requestMessage = for { - userProfile <- getUserADM(requestContext).map(_.asUserProfileV1) + userProfile <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ).map(_.asUserProfileV1) checkedUserIri = stringFormatter.validateAndEscapeIri(userIri, throw BadRequestException(s"Invalid user IRI $userIri")) } yield UserProjectAdminMembershipsGetRequestV1( userIri = checkedUserIri, @@ -140,7 +165,10 @@ class UsersRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) with requestContext => val requestMessage = for { - userProfile <- getUserADM(requestContext).map(_.asUserProfileV1) + userProfile <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ).map(_.asUserProfileV1) checkedUserIri = stringFormatter.validateAndEscapeIri(userIri, throw BadRequestException(s"Invalid user IRI $userIri")) } yield UserGroupMembershipsGetRequestV1( userIri = checkedUserIri, diff --git a/webapi/src/main/scala/org/knora/webapi/routing/v1/ValuesRouteV1.scala b/webapi/src/main/scala/org/knora/webapi/routing/v1/ValuesRouteV1.scala index d0728fed11..3578d63a7f 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/v1/ValuesRouteV1.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/v1/ValuesRouteV1.scala @@ -81,6 +81,7 @@ class ValuesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit subjectIri = subjectIri, predicateIri = predicateIri, objectIri = objectIri, + featureFactoryConfig = featureFactoryConfig, userProfile = userADM ) } @@ -112,6 +113,7 @@ class ValuesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit mappingIri = mappingIri, acceptStandoffLinksToClientIDs = false, userProfile = userADM, + featureFactoryConfig = featureFactoryConfig, settings = settings, responderManager = responderManager, log = log @@ -187,6 +189,7 @@ class ValuesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit propertyIri = propertyIri, value = value, comment = commentStr.map(str => stringFormatter.toSparqlEncodedString(str, throw BadRequestException(s"Invalid comment: '$str'"))), + featureFactoryConfig = featureFactoryConfig, userProfile = userADM, apiRequestID = UUID.randomUUID ) @@ -218,6 +221,7 @@ class ValuesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit mappingIri = mappingIri, acceptStandoffLinksToClientIDs = false, userProfile = userADM, + featureFactoryConfig = featureFactoryConfig, settings = settings, responderManager = responderManager, log = log @@ -291,6 +295,7 @@ class ValuesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit valueIri = valueIri, value = value, comment = commentStr.map(str => stringFormatter.toSparqlEncodedString(str, throw BadRequestException(s"Invalid comment: '$str'"))), + featureFactoryConfig = featureFactoryConfig, userProfile = userADM, apiRequestID = UUID.randomUUID ) @@ -300,6 +305,7 @@ class ValuesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit ChangeCommentRequestV1( valueIri = stringFormatter.validateAndEscapeIri(valueIriStr, throw BadRequestException(s"Invalid value IRI: $valueIriStr")), comment = comment.map(str => stringFormatter.toSparqlEncodedString(str, throw BadRequestException(s"Invalid comment: '$str'"))), + featureFactoryConfig = featureFactoryConfig, userProfile = userADM, apiRequestID = UUID.randomUUID ) @@ -309,6 +315,7 @@ class ValuesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit DeleteValueRequestV1( valueIri = stringFormatter.validateAndEscapeIri(valueIriStr, throw BadRequestException(s"Invalid value IRI: $valueIriStr")), deleteComment = deleteComment.map(comment => stringFormatter.toSparqlEncodedString(comment, throw BadRequestException(s"Invalid comment: '$comment'"))), + featureFactoryConfig = featureFactoryConfig, userProfile = userADM, apiRequestID = UUID.randomUUID ) @@ -316,8 +323,9 @@ class ValuesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit def makeGetValueRequest(valueIriStr: IRI, userADM: UserADM): ValueGetRequestV1 = { ValueGetRequestV1( - stringFormatter.validateAndEscapeIri(valueIriStr, throw BadRequestException(s"Invalid value IRI: $valueIriStr")), - userADM + valueIri = stringFormatter.validateAndEscapeIri(valueIriStr, throw BadRequestException(s"Invalid value IRI: $valueIriStr")), + featureFactoryConfig = featureFactoryConfig, + userProfile = userADM ) } @@ -335,6 +343,7 @@ class ValuesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit projectShortcode = projectShortcode ), apiRequestID = UUID.randomUUID, + featureFactoryConfig = featureFactoryConfig, userProfile = userADM ) } @@ -344,7 +353,10 @@ class ValuesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit get { requestContext => { val requestMessage = for { - userADM <- getUserADM(requestContext) + userADM <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield makeVersionHistoryRequestMessage(iris = iris, userADM = userADM) @@ -362,7 +374,10 @@ class ValuesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit entity(as[CreateValueApiRequestV1]) { apiRequest => requestContext => val requestMessageFuture = for { - userADM <- getUserADM(requestContext) + userADM <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) request <- makeCreateValueRequestMessage(apiRequest = apiRequest, userADM = userADM) } yield request @@ -379,7 +394,10 @@ class ValuesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit get { requestContext => { val requestMessage = for { - userADM <- getUserADM(requestContext) + userADM <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield makeGetValueRequest(valueIriStr = valueIriStr, userADM = userADM) RouteUtilV1.runJsonRouteWithFuture( @@ -396,7 +414,10 @@ class ValuesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit // In API v1, you cannot change a value and its comment in a single request. So we know that here, // we are getting a request to change either the value or the comment, but not both. val requestMessageFuture = for { - userADM <- getUserADM(requestContext) + userADM <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) request <- apiRequest match { case ChangeValueApiRequestV1(_, _, _, _, _, _, _, _, _, _, _, _, _, Some(comment)) => FastFuture.successful(makeChangeCommentRequestMessage(valueIriStr = valueIriStr, comment = Some(comment), userADM = userADM)) case _ => makeAddValueVersionRequestMessage(valueIriStr = valueIriStr, apiRequest = apiRequest, userADM = userADM) @@ -414,7 +435,10 @@ class ValuesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit } ~ delete { requestContext => { val requestMessage = for { - userADM <- getUserADM(requestContext) + userADM <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) params = requestContext.request.uri.query().toMap deleteComment = params.get("deleteComment") } yield makeDeleteValueRequest(valueIriStr = valueIriStr, deleteComment = deleteComment, userADM = userADM) @@ -432,7 +456,10 @@ class ValuesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit delete { requestContext => { val requestMessage = for { - userADM <- getUserADM(requestContext) + userADM <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield makeChangeCommentRequestMessage(valueIriStr = valueIriStr, comment = None, userADM = userADM) RouteUtilV1.runJsonRouteWithFuture( @@ -449,7 +476,10 @@ class ValuesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit get { requestContext => { val requestMessage = for { - userADM <- getUserADM(requestContext) + userADM <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield makeLinkValueGetRequestMessage(iris = iris, userADM = userADM) RouteUtilV1.runJsonRouteWithFuture( @@ -466,9 +496,18 @@ class ValuesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit entity(as[ChangeFileValueApiRequestV1]) { apiRequest => requestContext => val requestMessage = for { - userADM <- getUserADM(requestContext) + userADM <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) resourceIri = stringFormatter.validateAndEscapeIri(resIriStr, throw BadRequestException(s"Invalid resource IRI: $resIriStr")) - resourceInfoResponse <- (responderManager ? ResourceInfoGetRequestV1(resourceIri, userADM)).mapTo[ResourceInfoResponseV1] + + resourceInfoResponse <- (responderManager ? ResourceInfoGetRequestV1( + iri = resourceIri, + featureFactoryConfig = featureFactoryConfig, + userProfile = userADM + )).mapTo[ResourceInfoResponseV1] + projectShortcode = resourceInfoResponse.resource_info.getOrElse(throw NotFoundException(s"Resource not found: $resourceIri")).project_shortcode request <- makeChangeFileValueRequest( diff --git a/webapi/src/main/scala/org/knora/webapi/routing/v2/AuthenticationRouteV2.scala b/webapi/src/main/scala/org/knora/webapi/routing/v2/AuthenticationRouteV2.scala index 3e9f8c2a11..1fb26753d8 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/v2/AuthenticationRouteV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/v2/AuthenticationRouteV2.scala @@ -40,7 +40,10 @@ class AuthenticationRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeD get { // authenticate credentials requestContext => { requestContext.complete { - doAuthenticateV2(requestContext) + doAuthenticateV2( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } } } ~ @@ -62,14 +65,15 @@ class AuthenticationRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeD requestContext => requestContext.complete { doLoginV2( - KnoraPasswordCredentialsV2( + credentials = KnoraPasswordCredentialsV2( UserIdentifierADM( maybeIri = apiRequest.iri, maybeEmail = apiRequest.email, maybeUsername = apiRequest.username ), password = apiRequest.password - ) + ), + featureFactoryConfig = featureFactoryConfig ) } } @@ -94,12 +98,13 @@ class AuthenticationRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeD requestContext => { requestContext.complete { doLoginV2( - KnoraPasswordCredentialsV2( + credentials = KnoraPasswordCredentialsV2( UserIdentifierADM( maybeUsername = Some(username) ), password = password - ) + ), + featureFactoryConfig = featureFactoryConfig ) } } diff --git a/webapi/src/main/scala/org/knora/webapi/routing/v2/ListsRouteV2.scala b/webapi/src/main/scala/org/knora/webapi/routing/v2/ListsRouteV2.scala index 0e1ed36953..87a7a9644c 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/v2/ListsRouteV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/v2/ListsRouteV2.scala @@ -46,9 +46,16 @@ class ListsRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) with /* return a list (a graph with all list nodes) */ requestContext => val requestMessage: Future[ListGetRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) listIri: IRI = stringFormatter.validateAndEscapeIri(lIri, throw BadRequestException(s"Invalid list IRI: '$lIri'")) - } yield ListGetRequestV2(listIri, requestingUser) + } yield ListGetRequestV2( + listIri = listIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilV2.runRdfRouteWithFuture( requestMessageF = requestMessage, @@ -68,9 +75,16 @@ class ListsRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) with /* return a list node */ requestContext => val requestMessage: Future[NodeGetRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) nodeIri: IRI = stringFormatter.validateAndEscapeIri(nIri, throw BadRequestException(s"Invalid list IRI: '$nIri'")) - } yield NodeGetRequestV2(nodeIri, requestingUser) + } yield NodeGetRequestV2( + nodeIri = nodeIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilV2.runRdfRouteWithFuture( requestMessageF = requestMessage, diff --git a/webapi/src/main/scala/org/knora/webapi/routing/v2/MetadataRouteV2.scala b/webapi/src/main/scala/org/knora/webapi/routing/v2/MetadataRouteV2.scala index 68b7c63b5a..5f596d7c87 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/v2/MetadataRouteV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/v2/MetadataRouteV2.scala @@ -4,17 +4,18 @@ import java.util.UUID import akka.http.scaladsl.server.Directives._ import akka.http.scaladsl.server.{PathMatcher, Route} -import org.apache.jena.graph.Graph import org.knora.webapi.feature.FeatureFactoryConfig -import org.knora.webapi.{ApiV2Complex, InternalSchema} +import org.knora.webapi.messages.util.rdf.RdfModel import org.knora.webapi.messages.v2.responder.metadatamessages.{MetadataGetRequestV2, MetadataPutRequestV2} import org.knora.webapi.routing.{Authenticator, KnoraRoute, KnoraRouteData, RouteUtilV2} +import org.knora.webapi.{ApiV2Complex, InternalSchema} import scala.concurrent.Future object MetadataRouteV2 { val MetadataBasePath: PathMatcher[Unit] = PathMatcher("v2" / "metadata") } + /** * Provides a routing function for API v2 routes that deal with metadata. */ @@ -37,10 +38,19 @@ class MetadataRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) w requestContext => { // Make the request message. val requestMessageFuture: Future[MetadataGetRequestV2] = for { - requestingUser <- getUserADM(requestContext) - project <- getProjectADM(projectIri, requestingUser) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + + project <- getProjectADM( + projectIri = projectIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) } yield MetadataGetRequestV2( projectADM = project, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) @@ -67,18 +77,28 @@ class MetadataRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) w entity(as[String]) { entityStr => requestContext => { // Parse the request to a Jena Graph. - val requestGraph: Graph = RouteUtilV2.requestToJenaGraph( + val requestModel: RdfModel = RouteUtilV2.requestToRdfModel( entityStr = entityStr, - requestContext = requestContext + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig ) // Make the request message. val requestMessageFuture: Future[MetadataPutRequestV2] = for { - requestingUser <- getUserADM(requestContext) - project <- getProjectADM(projectIri, requestingUser) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + + project <- getProjectADM( + projectIri = projectIri, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) } yield MetadataPutRequestV2( - graph = requestGraph, + rdfModel = requestModel, projectADM = project, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = UUID.randomUUID ) 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 73ce39aa59..84f247875c 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 @@ -27,7 +27,7 @@ import org.knora.webapi._ import org.knora.webapi.exceptions.BadRequestException import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.IriConversions._ -import org.knora.webapi.messages.util.{JsonLDDocument, JsonLDUtil} +import org.knora.webapi.messages.util.rdf.{JsonLDDocument, JsonLDUtil} import org.knora.webapi.messages.v2.responder.ontologymessages._ import org.knora.webapi.messages.{OntologyConstants, SmartIri} import org.knora.webapi.routing.{Authenticator, KnoraRoute, KnoraRouteData, RouteUtilV2} @@ -101,7 +101,10 @@ class OntologiesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) val allLanguages = stringFormatter.optionStringToBoolean(allLanguagesStr, throw BadRequestException(s"Invalid boolean for $ALL_LANGUAGES: $allLanguagesStr")) val requestMessageFuture: Future[OntologyEntitiesGetRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield OntologyEntitiesGetRequestV2( ontologyIri = requestedOntology, allLanguages = allLanguages, @@ -128,7 +131,10 @@ class OntologiesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) val maybeProjectIri: Option[SmartIri] = RouteUtilV2.getProject(requestContext) val requestMessageFuture: Future[OntologyMetadataGetByProjectRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield OntologyMetadataGetByProjectRequestV2(projectIris = maybeProjectIri.toSet, requestingUser = requestingUser) RouteUtilV2.runRdfRouteWithFuture( @@ -153,13 +159,17 @@ class OntologiesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) val requestDoc: JsonLDDocument = JsonLDUtil.parseJsonLD(jsonRequest) val requestMessageFuture: Future[ChangeOntologyMetadataRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) requestMessage: ChangeOntologyMetadataRequestV2 <- ChangeOntologyMetadataRequestV2.fromJsonLD( jsonLDDocument = requestDoc, apiRequestID = UUID.randomUUID, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, + featureFactoryConfig = featureFactoryConfig, settings = settings, log = log ) @@ -185,7 +195,10 @@ class OntologiesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) requestContext => { val requestMessageFuture: Future[OntologyMetadataGetByProjectRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) validatedProjectIris = projectIris.map(iri => iri.toSmartIriWithErr(throw BadRequestException(s"Invalid project IRI: $iri"))).toSet } yield OntologyMetadataGetByProjectRequestV2(projectIris = validatedProjectIris, requestingUser = requestingUser) @@ -218,7 +231,10 @@ class OntologiesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) val allLanguages = stringFormatter.optionStringToBoolean(params.get(ALL_LANGUAGES), throw BadRequestException(s"Invalid boolean for $ALL_LANGUAGES: $allLanguagesStr")) val requestMessageFuture: Future[OntologyEntitiesGetRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield OntologyEntitiesGetRequestV2( ontologyIri = requestedOntologyIri, allLanguages = allLanguages, @@ -246,7 +262,10 @@ class OntologiesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) requestContext => { val requestMessageFuture: Future[CreateClassRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) requestDoc: JsonLDDocument = JsonLDUtil.parseJsonLD(jsonRequest) requestMessage: CreateClassRequestV2 <- CreateClassRequestV2.fromJsonLD( jsonLDDocument = requestDoc, @@ -254,6 +273,7 @@ class OntologiesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, + featureFactoryConfig = featureFactoryConfig, settings = settings, log = log ) @@ -281,7 +301,10 @@ class OntologiesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) requestContext => { val requestMessageFuture: Future[ChangeClassLabelsOrCommentsRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) requestDoc: JsonLDDocument = JsonLDUtil.parseJsonLD(jsonRequest) requestMessage <- ChangeClassLabelsOrCommentsRequestV2.fromJsonLD( jsonLDDocument = requestDoc, @@ -289,6 +312,7 @@ class OntologiesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, + featureFactoryConfig = featureFactoryConfig, settings = settings, log = log ) @@ -316,7 +340,10 @@ class OntologiesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) requestContext => { val requestMessageFuture: Future[AddCardinalitiesToClassRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) requestDoc: JsonLDDocument = JsonLDUtil.parseJsonLD(jsonRequest) requestMessage: AddCardinalitiesToClassRequestV2 <- AddCardinalitiesToClassRequestV2.fromJsonLD( jsonLDDocument = requestDoc, @@ -324,6 +351,7 @@ class OntologiesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, + featureFactoryConfig = featureFactoryConfig, settings = settings, log = log ) @@ -351,7 +379,10 @@ class OntologiesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) requestContext => { val requestMessageFuture: Future[ChangeCardinalitiesRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) requestDoc: JsonLDDocument = JsonLDUtil.parseJsonLD(jsonRequest) requestMessage: ChangeCardinalitiesRequestV2 <- ChangeCardinalitiesRequestV2.fromJsonLD( jsonLDDocument = requestDoc, @@ -359,6 +390,7 @@ class OntologiesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, + featureFactoryConfig = featureFactoryConfig, settings = settings, log = log ) @@ -418,7 +450,10 @@ class OntologiesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) val allLanguages = stringFormatter.optionStringToBoolean(params.get(ALL_LANGUAGES), throw BadRequestException(s"Invalid boolean for $ALL_LANGUAGES: $allLanguagesStr")) val requestMessageFuture: Future[ClassesGetRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield ClassesGetRequestV2( classIris = classesForResponder, allLanguages = allLanguages, @@ -458,11 +493,15 @@ class OntologiesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) val lastModificationDate = stringFormatter.xsdDateTimeStampToInstant(lastModificationDateStr, throw BadRequestException(s"Invalid timestamp: $lastModificationDateStr")) val requestMessageFuture: Future[DeleteClassRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield DeleteClassRequestV2( classIri = classIri, lastModificationDate = lastModificationDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) @@ -487,7 +526,10 @@ class OntologiesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) requestContext => { val requestMessageFuture: Future[CreatePropertyRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) requestDoc: JsonLDDocument = JsonLDUtil.parseJsonLD(jsonRequest) requestMessage: CreatePropertyRequestV2 <- CreatePropertyRequestV2.fromJsonLD( jsonLDDocument = requestDoc, @@ -495,6 +537,7 @@ class OntologiesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, + featureFactoryConfig = featureFactoryConfig, settings = settings, log = log ) @@ -522,7 +565,10 @@ class OntologiesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) requestContext => { val requestMessageFuture: Future[ChangePropertyLabelsOrCommentsRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) requestDoc: JsonLDDocument = JsonLDUtil.parseJsonLD(jsonRequest) requestMessage: ChangePropertyLabelsOrCommentsRequestV2 <- ChangePropertyLabelsOrCommentsRequestV2.fromJsonLD( jsonLDDocument = requestDoc, @@ -530,6 +576,7 @@ class OntologiesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, + featureFactoryConfig = featureFactoryConfig, settings = settings, log = log ) @@ -589,7 +636,10 @@ class OntologiesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) val allLanguages = stringFormatter.optionStringToBoolean(params.get(ALL_LANGUAGES), throw BadRequestException(s"Invalid boolean for $ALL_LANGUAGES: $allLanguagesStr")) val requestMessageFuture: Future[PropertiesGetRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield PropertiesGetRequestV2( propertyIris = propsForResponder, allLanguages = allLanguages, @@ -629,11 +679,15 @@ class OntologiesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) val lastModificationDate = stringFormatter.xsdDateTimeStampToInstant(lastModificationDateStr, throw BadRequestException(s"Invalid timestamp: $lastModificationDateStr")) val requestMessageFuture: Future[DeletePropertyRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield DeletePropertyRequestV2( propertyIri = propertyIri, lastModificationDate = lastModificationDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) @@ -658,7 +712,10 @@ class OntologiesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) requestContext => { val requestMessageFuture: Future[CreateOntologyRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) requestDoc: JsonLDDocument = JsonLDUtil.parseJsonLD(jsonRequest) requestMessage: CreateOntologyRequestV2 <- CreateOntologyRequestV2.fromJsonLD( jsonLDDocument = requestDoc, @@ -666,6 +723,7 @@ class OntologiesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, + featureFactoryConfig = featureFactoryConfig, settings = settings, log = log ) @@ -700,11 +758,15 @@ class OntologiesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) val lastModificationDate = stringFormatter.xsdDateTimeStampToInstant(lastModificationDateStr, throw BadRequestException(s"Invalid timestamp: $lastModificationDateStr")) val requestMessageFuture: Future[DeleteOntologyRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield DeleteOntologyRequestV2( ontologyIri = ontologyIri, lastModificationDate = lastModificationDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) 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 8771f6fdbe..d6b18f8ee8 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 @@ -28,7 +28,7 @@ import org.knora.webapi._ import org.knora.webapi.exceptions.BadRequestException import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.IriConversions._ -import org.knora.webapi.messages.util.{JsonLDDocument, JsonLDUtil} +import org.knora.webapi.messages.util.rdf.{JsonLDDocument, JsonLDUtil} import org.knora.webapi.messages.v2.responder.resourcemessages._ import org.knora.webapi.messages.v2.responder.searchmessages.SearchResourcesByProjectAndClassRequestV2 import org.knora.webapi.messages.{SmartIri, StringFormatter} @@ -80,13 +80,17 @@ class ResourcesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) val requestDoc: JsonLDDocument = JsonLDUtil.parseJsonLD(jsonRequest) val requestMessageFuture: Future[CreateResourceRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) requestMessage: CreateResourceRequestV2 <- CreateResourceRequestV2.fromJsonLD( requestDoc, apiRequestID = UUID.randomUUID, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, + featureFactoryConfig = featureFactoryConfig, settings = settings, log = log ) @@ -114,13 +118,17 @@ class ResourcesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) val requestDoc: JsonLDDocument = JsonLDUtil.parseJsonLD(jsonRequest) val requestMessageFuture: Future[UpdateResourceMetadataRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) requestMessage: UpdateResourceMetadataRequestV2 <- UpdateResourceMetadataRequestV2.fromJsonLD( requestDoc, apiRequestID = UUID.randomUUID, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, + featureFactoryConfig = featureFactoryConfig, settings = settings, log = log ) @@ -174,7 +182,10 @@ class ResourcesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) val targetSchema: ApiV2Schema = RouteUtilV2.getOntologySchema(requestContext) val requestMessageFuture: Future[SearchResourcesByProjectAndClassRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield SearchResourcesByProjectAndClassRequestV2( projectIri = projectIri, resourceClass = resourceClass.toOntologySchema(ApiV2Complex), @@ -182,6 +193,7 @@ class ResourcesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) page = page, targetSchema = targetSchema, schemaOptions = schemaOptions, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) @@ -208,11 +220,15 @@ class ResourcesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) val endDate = params.get("endDate").map(dateStr => stringFormatter.xsdDateTimeStampToInstant(dateStr, throw BadRequestException(s"Invalid end date: $dateStr"))) val requestMessageFuture: Future[ResourceVersionHistoryGetRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield ResourceVersionHistoryGetRequestV2( resourceIri = resourceIri, startDate = startDate, endDate = endDate, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) @@ -261,12 +277,16 @@ class ResourcesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) val schemaOptions: Set[SchemaOption] = RouteUtilV2.getSchemaOptions(requestContext) val requestMessageFuture: Future[ResourcesGetRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield ResourcesGetRequestV2( resourceIris = resourceIris, versionDate = versionDate, targetSchema = targetSchema, schemaOptions = schemaOptions, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) @@ -297,8 +317,16 @@ class ResourcesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) val targetSchema: ApiV2Schema = RouteUtilV2.getOntologySchema(requestContext) val requestMessageFuture: Future[ResourcesPreviewGetRequestV2] = for { - requestingUser <- getUserADM(requestContext) - } yield ResourcesPreviewGetRequestV2(resourceIris = resourceIris, targetSchema = targetSchema, requestingUser = requestingUser) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + } yield ResourcesPreviewGetRequestV2( + resourceIris = resourceIris, + targetSchema = targetSchema, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilV2.runRdfRouteWithFuture( requestMessageF = requestMessageFuture, @@ -332,13 +360,17 @@ class ResourcesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) val headerXSLTIri = getHeaderXSLTIriFromParams(params) val requestMessageFuture: Future[ResourceTEIGetRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield ResourceTEIGetRequestV2( resourceIri = resourceIri, textProperty = textProperty, mappingIri = mappingIri, gravsearchTemplateIri = gravsearchTemplateIri, headerXSLTIri = headerXSLTIri, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) @@ -381,7 +413,10 @@ class ResourcesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) } val requestMessageFuture: Future[GraphDataGetRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield GraphDataGetRequestV2( resourceIri = resourceIri, depth = depth, @@ -412,13 +447,17 @@ class ResourcesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) val requestDoc: JsonLDDocument = JsonLDUtil.parseJsonLD(jsonRequest) val requestMessageFuture: Future[DeleteOrEraseResourceRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) requestMessage: DeleteOrEraseResourceRequestV2 <- DeleteOrEraseResourceRequestV2.fromJsonLD( requestDoc, apiRequestID = UUID.randomUUID, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, + featureFactoryConfig = featureFactoryConfig, settings = settings, log = log ) @@ -446,13 +485,17 @@ class ResourcesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) val requestDoc: JsonLDDocument = JsonLDUtil.parseJsonLD(jsonRequest) val requestMessageFuture: Future[DeleteOrEraseResourceRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) requestMessage: DeleteOrEraseResourceRequestV2 <- DeleteOrEraseResourceRequestV2.fromJsonLD( requestDoc, apiRequestID = UUID.randomUUID, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, + featureFactoryConfig = featureFactoryConfig, settings = settings, log = log ) diff --git a/webapi/src/main/scala/org/knora/webapi/routing/v2/SearchRouteV2.scala b/webapi/src/main/scala/org/knora/webapi/routing/v2/SearchRouteV2.scala index 20648bef8f..f2f5248075 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/v2/SearchRouteV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/v2/SearchRouteV2.scala @@ -174,12 +174,16 @@ class SearchRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit val limitToStandoffClass: Option[SmartIri] = getStandoffClass(params) val requestMessage: Future[FullTextSearchCountRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield FullTextSearchCountRequestV2( searchValue = escapedSearchStr, limitToProject = limitToProject, limitToResourceClass = limitToResourceClass, limitToStandoffClass = limitToStandoffClass, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) @@ -223,13 +227,17 @@ class SearchRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit val schemaOptions: Set[SchemaOption] = RouteUtilV2.getSchemaOptions(requestContext) val requestMessage: Future[FulltextSearchRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield FulltextSearchRequestV2( searchValue = escapedSearchStr, offset = offset, limitToProject = limitToProject, limitToResourceClass = limitToResourceClass, limitToStandoffClass, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, targetSchema = targetSchema, schemaOptions = schemaOptions @@ -255,8 +263,15 @@ class SearchRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit val constructQuery = GravsearchParser.parseQuery(gravsearchQuery) val requestMessage: Future[GravsearchCountRequestV2] = for { - requestingUser <- getUserADM(requestContext) - } yield GravsearchCountRequestV2(constructQuery = constructQuery, requestingUser = requestingUser) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + } yield GravsearchCountRequestV2( + constructQuery = constructQuery, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilV2.runRdfRouteWithFuture( requestMessageF = requestMessage, @@ -278,8 +293,15 @@ class SearchRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit requestContext => { val constructQuery = GravsearchParser.parseQuery(gravsearchQuery) val requestMessage: Future[GravsearchCountRequestV2] = for { - requestingUser <- getUserADM(requestContext) - } yield GravsearchCountRequestV2(constructQuery = constructQuery, requestingUser = requestingUser) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) + } yield GravsearchCountRequestV2( + constructQuery = constructQuery, + featureFactoryConfig = featureFactoryConfig, + requestingUser = requestingUser + ) RouteUtilV2.runRdfRouteWithFuture( requestMessageF = requestMessage, @@ -304,11 +326,15 @@ class SearchRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit val schemaOptions: Set[SchemaOption] = RouteUtilV2.getSchemaOptions(requestContext) val requestMessage: Future[GravsearchRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield GravsearchRequestV2( constructQuery = constructQuery, targetSchema = targetSchema, schemaOptions = schemaOptions, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) @@ -335,11 +361,15 @@ class SearchRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit val schemaOptions: Set[SchemaOption] = RouteUtilV2.getSchemaOptions(requestContext) val requestMessage: Future[GravsearchRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield GravsearchRequestV2( constructQuery = constructQuery, targetSchema = targetSchema, schemaOptions = schemaOptions, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) @@ -375,11 +405,15 @@ class SearchRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit val limitToResourceClass: Option[SmartIri] = getResourceClassFromParams(params) val requestMessage: Future[SearchResourceByLabelCountRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield SearchResourceByLabelCountRequestV2( searchValue = searchString, limitToProject = limitToProject, limitToResourceClass = limitToResourceClass, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) @@ -417,13 +451,17 @@ class SearchRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit val targetSchema: ApiV2Schema = RouteUtilV2.getOntologySchema(requestContext) val requestMessage: Future[SearchResourceByLabelRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield SearchResourceByLabelRequestV2( searchValue = searchString, offset = offset, limitToProject = limitToProject, limitToResourceClass = limitToResourceClass, targetSchema = targetSchema, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) diff --git a/webapi/src/main/scala/org/knora/webapi/routing/v2/StandoffRouteV2.scala b/webapi/src/main/scala/org/knora/webapi/routing/v2/StandoffRouteV2.scala index ec9e0b9388..2ddcfdd5cc 100644 --- a/webapi/src/main/scala/org/knora/webapi/routing/v2/StandoffRouteV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/routing/v2/StandoffRouteV2.scala @@ -30,7 +30,7 @@ import org.knora.webapi.exceptions.BadRequestException import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.SmartIri -import org.knora.webapi.messages.util.JsonLDUtil +import org.knora.webapi.messages.util.rdf.JsonLDUtil import org.knora.webapi.messages.v2.responder.standoffmessages.{CreateMappingRequestMetadataV2, CreateMappingRequestV2, CreateMappingRequestXMLV2, GetStandoffPageRequestV2} import org.knora.webapi.routing.{Authenticator, KnoraRoute, KnoraRouteData, RouteUtilV2} @@ -68,12 +68,16 @@ class StandoffRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) w val targetSchema: ApiV2Schema = RouteUtilV2.getOntologySchema(requestContext) val requestMessageFuture: Future[GetStandoffPageRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield GetStandoffPageRequestV2( resourceIri = resourceIri.toString, valueIri = valueIri.toString, offset = offset, targetSchema = targetSchema, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) @@ -91,7 +95,7 @@ class StandoffRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) w } } ~ path("v2" / "mapping") { post { - entity(as[Multipart.FormData]) { formdata: Multipart.FormData => + entity(as[Multipart.FormData]) { formData: Multipart.FormData => requestContext => val JSON_PART = "json" @@ -101,7 +105,7 @@ class StandoffRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) w val apiRequestID = UUID.randomUUID // collect all parts of the multipart as it arrives into a map - val allPartsFuture: Future[Map[Name, String]] = formdata.parts.mapAsync[(Name, String)](1) { + val allPartsFuture: Future[Map[Name, String]] = formData.parts.mapAsync[(Name, String)](1) { case b: BodyPart if b.name == JSON_PART => //loggingAdapter.debug(s"inside allPartsFuture - processing $JSON_PART") b.toStrict(2.seconds).map { strict => @@ -126,7 +130,10 @@ class StandoffRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) w }.runFold(Map.empty[Name, String])((map, tuple) => map + tuple) val requestMessageFuture: Future[CreateMappingRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) allParts: Map[Name, String] <- allPartsFuture jsonldDoc = JsonLDUtil.parseJsonLD(allParts.getOrElse(JSON_PART, throw BadRequestException(s"MultiPart POST request was sent without required '$JSON_PART' part!")).toString) @@ -136,6 +143,7 @@ class StandoffRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) w requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, + featureFactoryConfig = featureFactoryConfig, settings = settings, log = log ) @@ -144,6 +152,7 @@ class StandoffRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) w } yield CreateMappingRequestV2( metadata = metadata, xml = CreateMappingRequestXMLV2(xml), + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser, apiRequestID = apiRequestID ) 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 3f4575317f..1c91c1aea6 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 @@ -29,7 +29,7 @@ import org.knora.webapi.exceptions.BadRequestException import org.knora.webapi.feature.FeatureFactoryConfig import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.SmartIri -import org.knora.webapi.messages.util.{JsonLDDocument, JsonLDUtil} +import org.knora.webapi.messages.util.rdf.{JsonLDDocument, JsonLDUtil} import org.knora.webapi.messages.v2.responder.resourcemessages.ResourcesGetRequestV2 import org.knora.webapi.messages.v2.responder.valuemessages._ import org.knora.webapi.routing.{Authenticator, KnoraRoute, KnoraRouteData, RouteUtilV2} @@ -87,12 +87,16 @@ class ValuesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit val schemaOptions: Set[SchemaOption] = RouteUtilV2.getSchemaOptions(requestContext) val requestMessageFuture: Future[ResourcesGetRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) } yield ResourcesGetRequestV2( resourceIris = Seq(resourceIri.toString), valueUuid = Some(valueUuid), versionDate = versionDate, targetSchema = targetSchema, + featureFactoryConfig = featureFactoryConfig, requestingUser = requestingUser ) @@ -117,13 +121,17 @@ class ValuesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit val requestDoc: JsonLDDocument = JsonLDUtil.parseJsonLD(jsonRequest) val requestMessageFuture: Future[CreateValueRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) requestMessage: CreateValueRequestV2 <- CreateValueRequestV2.fromJsonLD( requestDoc, apiRequestID = UUID.randomUUID, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, + featureFactoryConfig = featureFactoryConfig, settings = settings, log = log ) @@ -151,13 +159,17 @@ class ValuesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit val requestDoc: JsonLDDocument = JsonLDUtil.parseJsonLD(jsonRequest) val requestMessageFuture: Future[UpdateValueRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) requestMessage: UpdateValueRequestV2 <- UpdateValueRequestV2.fromJsonLD( requestDoc, apiRequestID = UUID.randomUUID, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, + featureFactoryConfig = featureFactoryConfig, settings = settings, log = log ) @@ -185,13 +197,17 @@ class ValuesRouteV2(routeData: KnoraRouteData) extends KnoraRoute(routeData) wit val requestDoc: JsonLDDocument = JsonLDUtil.parseJsonLD(jsonRequest) val requestMessageFuture: Future[DeleteValueRequestV2] = for { - requestingUser <- getUserADM(requestContext) + requestingUser <- getUserADM( + requestContext = requestContext, + featureFactoryConfig = featureFactoryConfig + ) requestMessage: DeleteValueRequestV2 <- DeleteValueRequestV2.fromJsonLD( requestDoc, apiRequestID = UUID.randomUUID, requestingUser = requestingUser, responderManager = responderManager, storeManager = storeManager, + featureFactoryConfig = featureFactoryConfig, settings = settings, log = log ) diff --git a/webapi/src/main/scala/org/knora/webapi/store/BUILD.bazel b/webapi/src/main/scala/org/knora/webapi/store/BUILD.bazel index 3e7eb7f1ed..932e9b9323 100644 --- a/webapi/src/main/scala/org/knora/webapi/store/BUILD.bazel +++ b/webapi/src/main/scala/org/knora/webapi/store/BUILD.bazel @@ -14,6 +14,7 @@ scala_library( "//webapi/src/main/scala/org/knora/webapi/messages", "//webapi/src/main/scala/org/knora/webapi/routing", "//webapi/src/main/scala/org/knora/webapi/settings", + "//webapi/src/main/scala/org/knora/webapi/feature", "//webapi/src/main/scala/org/knora/webapi/util", "@maven//:com_twitter_chill_2_12", "@maven//:com_typesafe_akka_akka_actor_2_12", diff --git a/webapi/src/main/scala/org/knora/webapi/store/triplestore/http/HttpTriplestoreConnector.scala b/webapi/src/main/scala/org/knora/webapi/store/triplestore/http/HttpTriplestoreConnector.scala index fda8b113e3..20c7d68f51 100644 --- a/webapi/src/main/scala/org/knora/webapi/store/triplestore/http/HttpTriplestoreConnector.scala +++ b/webapi/src/main/scala/org/knora/webapi/store/triplestore/http/HttpTriplestoreConnector.scala @@ -40,16 +40,14 @@ import org.apache.http.impl.client.{BasicAuthCache, BasicCredentialsProvider, Cl import org.apache.http.message.BasicNameValuePair import org.apache.http.util.EntityUtils import org.apache.http.{Consts, HttpEntity, HttpHost, HttpRequest, NameValuePair} -import org.eclipse.rdf4j.model.impl.SimpleValueFactory -import org.eclipse.rdf4j.model.{Resource, Statement} -import org.eclipse.rdf4j.rio.turtle._ -import org.eclipse.rdf4j.rio.{RDFFormat, RDFHandler, RDFWriter, Rio} +import org.eclipse.rdf4j import org.knora.webapi._ import org.knora.webapi.exceptions._ import org.knora.webapi.instrumentation.InstrumentationSupport import org.knora.webapi.messages.store.triplestoremessages._ import org.knora.webapi.messages.util.FakeTriplestore import org.knora.webapi.messages.util.SparqlResultProtocol._ +import org.knora.webapi.messages.util.rdf.{RdfFeatureFactory, RdfFormatUtil, RdfModel, Statement, Turtle} import org.knora.webapi.settings.{KnoraDispatchers, KnoraSettings, TriplestoreTypes} import org.knora.webapi.store.triplestore.RdfDataObjectFactory import org.knora.webapi.util.ActorUtil._ @@ -57,6 +55,7 @@ import org.knora.webapi.util.FileUtil import spray.json._ import scala.collection.JavaConverters._ +import scala.collection.mutable import scala.concurrent.ExecutionContext import scala.util.{Failure, Success, Try} @@ -186,8 +185,8 @@ class HttpTriplestoreConnector extends Actor with ActorLogging with Instrumentat */ def receive: PartialFunction[Any, Unit] = { case SparqlSelectRequest(sparql: String) => try2Message(sender(), sparqlHttpSelect(sparql), log) - case SparqlConstructRequest(sparql: String) => try2Message(sender(), sparqlHttpConstruct(sparql), log) - case SparqlExtendedConstructRequest(sparql: String) => try2Message(sender(), sparqlHttpExtendedConstruct(sparql), log) + case sparqlConstructRequest: SparqlConstructRequest => try2Message(sender(), sparqlHttpConstruct(sparqlConstructRequest), log) + case sparqlExtendedConstructRequest: SparqlExtendedConstructRequest => try2Message(sender(), sparqlHttpExtendedConstruct(sparqlExtendedConstructRequest), log) case SparqlConstructFileRequest(sparql: String, graphIri: IRI, outputFile: File) => try2Message(sender(), sparqlHttpConstructFile(sparql, graphIri, outputFile), log) case NamedGraphFileRequest(graphIri: IRI, outputFile: File) => try2Message(sender(), sparqlHttpGraphFile(graphIri, outputFile), log) case NamedGraphDataRequest(graphIri: IRI) => try2Message(sender(), sparqlHttpGraphData(graphIri), log) @@ -248,58 +247,31 @@ class HttpTriplestoreConnector extends Actor with ActorLogging with Instrumentat responseMessage <- parseJsonResponse(sparql, resultStr) } yield responseMessage } - /** * Given a SPARQL CONSTRUCT query string, runs the query, returning the result as a [[SparqlConstructResponse]]. * - * @param sparql the SPARQL CONSTRUCT query string. + * @param sparqlConstructRequest the request message. * @return a [[SparqlConstructResponse]] */ - private def sparqlHttpConstruct(sparql: String): Try[SparqlConstructResponse] = { + private def sparqlHttpConstruct(sparqlConstructRequest: SparqlConstructRequest): Try[SparqlConstructResponse] = { // println(logDelimiter + sparql) - /** - * Converts a graph in parsed Turtle to a [[SparqlConstructResponse]]. - */ - class ConstructResponseTurtleHandler extends RDFHandler { - /** - * A collection of all the statements in the input file, grouped and sorted by subject IRI. - */ - private var statements = Map.empty[IRI, Seq[(IRI, String)]] - - override def handleComment(comment: IRI): Unit = {} - - /** - * Adds a statement to the collection `statements`. - * - * @param st the statement to be added. - */ - override def handleStatement(st: Statement): Unit = { - val subjectIri = st.getSubject.stringValue - val predicateIri = st.getPredicate.stringValue - val objectIri = st.getObject.stringValue - val currentStatementsForSubject: Seq[(IRI, String)] = statements.getOrElse(subjectIri, Vector.empty[(IRI, String)]) - statements += (subjectIri -> (currentStatementsForSubject :+ (predicateIri, objectIri))) - } - - override def endRDF(): Unit = {} - - override def handleNamespace(prefix: IRI, uri: IRI): Unit = {} - - override def startRDF(): Unit = {} + val rdfFormatUtil: RdfFormatUtil = RdfFeatureFactory.getRdfFormatUtil(sparqlConstructRequest.featureFactoryConfig) - def getConstructResponse: SparqlConstructResponse = { - SparqlConstructResponse(statements) - } - } - - def parseTurtleResponse(sparql: String, turtleStr: String): Try[SparqlConstructResponse] = { + def parseTurtleResponse(sparql: String, turtleStr: String, rdfFormatUtil: RdfFormatUtil): Try[SparqlConstructResponse] = { val parseTry = Try { - val turtleParser = new TurtleParser() - val handler = new ConstructResponseTurtleHandler - turtleParser.setRDFHandler(handler) - turtleParser.parse(new StringReader(turtleStr), "") - handler.getConstructResponse + val rdfModel: RdfModel = rdfFormatUtil.parseToRdfModel(rdfStr = turtleStr, rdfFormat = Turtle) + val statementMap: mutable.Map[IRI, Seq[(IRI, String)]] = mutable.Map.empty + + for (st: Statement <- rdfModel.getStatements) { + val subjectIri = st.subj.stringValue + val predicateIri = st.pred.stringValue + val objectIri = st.obj.stringValue + val currentStatementsForSubject: Seq[(IRI, String)] = statementMap.getOrElse(subjectIri, Vector.empty[(IRI, String)]) + statementMap += (subjectIri -> (currentStatementsForSubject :+ (predicateIri, objectIri))) + } + + SparqlConstructResponse(statementMap.toMap) } parseTry match { @@ -311,8 +283,13 @@ class HttpTriplestoreConnector extends Actor with ActorLogging with Instrumentat } for { - turtleStr <- getSparqlHttpResponse(sparql, isUpdate = false, acceptMimeType = mimeTypeTextTurtle) - response <- parseTurtleResponse(sparql, turtleStr) + turtleStr <- getSparqlHttpResponse(sparqlConstructRequest.sparql, isUpdate = false, acceptMimeType = mimeTypeTextTurtle) + + response <- parseTurtleResponse( + sparql = sparqlConstructRequest.sparql, + turtleStr = turtleStr, + rdfFormatUtil = rdfFormatUtil + ) } yield response } @@ -320,11 +297,11 @@ class HttpTriplestoreConnector extends Actor with ActorLogging with Instrumentat * Adds a named graph to CONSTRUCT query results. * * @param graphIri the IRI of the named graph. - * @param rdfWriter an [[RDFWriter]] for writing the result. + * @param rdfWriter an [[rdf4j.rio.RDFWriter]] for writing the result. */ - private class ConstructToGraphHandler(graphIri: IRI, rdfWriter: RDFWriter) extends RDFHandler { - private val valueFactory: SimpleValueFactory = SimpleValueFactory.getInstance() - private val context: Resource = valueFactory.createIRI(graphIri) + private class ConstructToGraphHandler(graphIri: IRI, rdfWriter: rdf4j.rio.RDFWriter) extends rdf4j.rio.RDFHandler { + private val valueFactory: rdf4j.model.impl.SimpleValueFactory = rdf4j.model.impl.SimpleValueFactory.getInstance() + private val context: rdf4j.model.Resource = valueFactory.createIRI(graphIri) override def startRDF(): Unit = rdfWriter.startRDF() @@ -332,7 +309,7 @@ class HttpTriplestoreConnector extends Actor with ActorLogging with Instrumentat override def handleNamespace(prefix: IRI, uri: IRI): Unit = rdfWriter.handleNamespace(prefix, uri) - override def handleStatement(st: Statement): Unit = { + override def handleStatement(st: rdf4j.model.Statement): Unit = { val outputStatement = valueFactory.createStatement( st.getSubject, st.getPredicate, @@ -353,12 +330,14 @@ class HttpTriplestoreConnector extends Actor with ActorLogging with Instrumentat * @param outputFile the output file. */ private def turtleToTrig(input: Reader, graphIri: IRI, outputFile: File): Unit = { + // TODO: Provide a streaming API in RdfFormatUtil for this. + var maybeBufferedFileWriter: Option[BufferedWriter] = None try { maybeBufferedFileWriter = Some(new BufferedWriter(new FileWriter(outputFile))) - val turtleParser = Rio.createParser(RDFFormat.TURTLE) - val trigFileWriter: RDFWriter = Rio.createWriter(RDFFormat.TRIG, maybeBufferedFileWriter.get) + val turtleParser = rdf4j.rio.Rio.createParser(rdf4j.rio.RDFFormat.TURTLE) + val trigFileWriter: rdf4j.rio.RDFWriter = rdf4j.rio.Rio.createWriter(rdf4j.rio.RDFFormat.TRIG, maybeBufferedFileWriter.get) val constructToGraphHandler = new ConstructToGraphHandler(graphIri = graphIri, rdfWriter = trigFileWriter) turtleParser.setRDFHandler(constructToGraphHandler) turtleParser.parse(input, "") @@ -384,17 +363,23 @@ class HttpTriplestoreConnector extends Actor with ActorLogging with Instrumentat } /** - * Given a SPARQL CONSTRUCT query string, runs the query, returning the result as a [[SparqlExtendedConstructResponse]]. + * Given a SPARQL CONSTRUCT query string, runs the query, returns the result as a [[SparqlExtendedConstructResponse]]. * - * @param sparql the SPARQL CONSTRUCT query string. + * @param sparqlExtendedConstructRequest the request message. * @return a [[SparqlExtendedConstructResponse]] */ - private def sparqlHttpExtendedConstruct(sparql: String): Try[SparqlExtendedConstructResponse] = { + private def sparqlHttpExtendedConstruct(sparqlExtendedConstructRequest: SparqlExtendedConstructRequest): Try[SparqlExtendedConstructResponse] = { // println(sparql) + val rdfFormatUtil: RdfFormatUtil = RdfFeatureFactory.getRdfFormatUtil(sparqlExtendedConstructRequest.featureFactoryConfig) val parseTry = for { - turtleStr <- getSparqlHttpResponse(sparql, isUpdate = false, acceptMimeType = mimeTypeTextTurtle) - response <- SparqlExtendedConstructResponse.parseTurtleResponse(turtleStr, log) + turtleStr <- getSparqlHttpResponse(sparqlExtendedConstructRequest.sparql, isUpdate = false, acceptMimeType = mimeTypeTextTurtle) + + response <- SparqlExtendedConstructResponse.parseTurtleResponse( + turtleStr = turtleStr, + rdfFormatUtil = rdfFormatUtil, + log = log + ) } yield response parseTry match { @@ -1051,6 +1036,8 @@ class HttpTriplestoreConnector extends Actor with ActorLogging with Instrumentat throw TriplestoreResponseException(s"Triplestore returned no content for for repository dump") } case Some(responseEntity: HttpEntity) => + // TODO: Provide a streaming API in RdfFormatUtil for this. + // Stream the HTTP entity to the output file. if (convertToTrig) { // Stream the HTTP entity to the temporary .ttl file. diff --git a/webapi/src/main/scala/org/knora/webapi/util/BUILD.bazel b/webapi/src/main/scala/org/knora/webapi/util/BUILD.bazel index fe3a77d1b8..61e00fb033 100644 --- a/webapi/src/main/scala/org/knora/webapi/util/BUILD.bazel +++ b/webapi/src/main/scala/org/knora/webapi/util/BUILD.bazel @@ -7,6 +7,7 @@ scala_library( srcs = glob(["**/*.scala"]), unused_dependency_checker_mode = "warn", deps = [ + "//webapi/src/main/scala/org/knora/webapi", "//webapi/src/main/scala/org/knora/webapi/exceptions", "//webapi/src/main/scala/org/knora/webapi/settings", "@maven//:com_jsuereth_scala_arm_2_12", diff --git a/webapi/src/main/scala/org/knora/webapi/util/JavaUtil.scala b/webapi/src/main/scala/org/knora/webapi/util/JavaUtil.scala index 7d9b9963bc..aadf188fd1 100644 --- a/webapi/src/main/scala/org/knora/webapi/util/JavaUtil.scala +++ b/webapi/src/main/scala/org/knora/webapi/util/JavaUtil.scala @@ -47,19 +47,17 @@ object JavaUtil { (a: A, b: B) => f(a, b) /** - * Helps turn matches for optional regular expression groups, which can be null, into Scala Option objects. See + * Helps turn matches for optional regular expression groups, which can be null, into Scala [[Option]] objects. See * [[https://stackoverflow.com/a/18794646]]. */ object Optional { - def unapply[T](a: T): Some[Option[T]] = if (null == a) Some(None) else Some(Some(a)) + def unapply[T](group: T): Some[Option[T]] = if (group == null) Some(None) else Some(Some(group)) } /** * Wraps a Java `Optional` and converts it to a Scala [[Option]]. */ - class JavaOptional[T](opt: java.util.Optional[T]) { - def toOption: Option[T] = if (opt.isPresent) Some(opt.get()) else None + implicit class ConvertibleJavaOptional[T](val self: java.util.Optional[T]) extends AnyVal { + def toOption: Option[T] = if (self.isPresent) Some(self.get) else None } - - implicit def toJavaOptional[T](optional: java.util.Optional[T]): JavaOptional[T] = new JavaOptional[T](optional) } diff --git a/webapi/src/test/scala/org/knora/webapi/CoreSpec.scala b/webapi/src/test/scala/org/knora/webapi/CoreSpec.scala index ffdfcad6b3..fe139217ae 100644 --- a/webapi/src/test/scala/org/knora/webapi/CoreSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/CoreSpec.scala @@ -28,12 +28,13 @@ import akka.util.Timeout import com.typesafe.config.{Config, ConfigFactory} import org.knora.webapi.app.{ApplicationActor, LiveManagers} import org.knora.webapi.core.Core +import org.knora.webapi.feature.{FeatureFactoryConfig, KnoraSettingsFeatureFactoryConfig, TestFeatureFactoryConfig} import org.knora.webapi.messages.StringFormatter import org.knora.webapi.messages.app.appmessages.{AppStart, AppStop, SetAllowReloadOverHTTPState} import org.knora.webapi.messages.store.cacheservicemessages.CacheServiceFlushDB import org.knora.webapi.messages.store.triplestoremessages.{RdfDataObject, ResetRepositoryContent} import org.knora.webapi.messages.util.{KnoraSystemInstances, ResponderData} -import org.knora.webapi.messages.v1.responder.ontologymessages.LoadOntologiesRequest +import org.knora.webapi.messages.v2.responder.ontologymessages.LoadOntologiesRequestV2 import org.knora.webapi.settings.{KnoraDispatchers, KnoraSettings, KnoraSettingsImpl, _} import org.knora.webapi.util.StartupUtils import org.scalatest.BeforeAndAfterAll @@ -62,7 +63,7 @@ object CoreSpec { case -1 ⇒ s case z ⇒ s drop (z + 1) } - reduced.head.replaceFirst( """.*\.""", "").replaceAll("[^a-zA-Z_0-9]", "_") + reduced.head.replaceFirst(""".*\.""", "").replaceAll("[^a-zA-Z_0-9]", "_") } } @@ -70,9 +71,13 @@ abstract class CoreSpec(_system: ActorSystem) extends TestKit(_system) with Core /* constructors - individual tests can override the configuration by giving their own */ def this(name: String, config: Config) = this(ActorSystem(name, TestContainers.PortConfig.withFallback(ConfigFactory.load(config.withFallback(CoreSpec.defaultConfig))))) + def this(config: Config) = this(ActorSystem(CoreSpec.getCallerName(getClass), TestContainers.PortConfig.withFallback(ConfigFactory.load(config.withFallback(CoreSpec.defaultConfig))))) + def this(name: String) = this(ActorSystem(name, TestContainers.PortConfig.withFallback(ConfigFactory.load()))) + def this() = this(ActorSystem(CoreSpec.getCallerName(getClass), TestContainers.PortConfig.withFallback(ConfigFactory.load()))) + /* needed by the core trait */ implicit lazy val settings: KnoraSettingsImpl = KnoraSettings(system) implicit val materializer: Materializer = Materializer.matFromSystem(system) @@ -97,6 +102,11 @@ abstract class CoreSpec(_system: ActorSystem) extends TestKit(_system) with Core appActor = appActor ) + protected val defaultFeatureFactoryConfig: FeatureFactoryConfig = new TestFeatureFactoryConfig( + testToggles = Set.empty, + parent = new KnoraSettingsFeatureFactoryConfig(settings) + ) + final override def beforeAll() { // set allow reload over http appActor ! SetAllowReloadOverHTTPState(true) @@ -121,7 +131,12 @@ abstract class CoreSpec(_system: ActorSystem) extends TestKit(_system) with Core logger.info("Loading test data started ...") implicit val timeout: Timeout = Timeout(settings.defaultTimeout) Await.result(appActor ? ResetRepositoryContent(rdfDataObjects), 479999.milliseconds) - Await.result(appActor ? LoadOntologiesRequest(KnoraSystemInstances.Users.SystemUser), 1 minute) + + Await.result(appActor ? LoadOntologiesRequestV2( + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ), 1 minute) + Await.result(appActor ? CacheServiceFlushDB(KnoraSystemInstances.Users.SystemUser), 5 seconds) logger.info("... loading test data done.") } diff --git a/webapi/src/test/scala/org/knora/webapi/E2ESpec.scala b/webapi/src/test/scala/org/knora/webapi/E2ESpec.scala index 66ba02da40..35a72c987a 100644 --- a/webapi/src/test/scala/org/knora/webapi/E2ESpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/E2ESpec.scala @@ -19,7 +19,7 @@ package org.knora.webapi -import java.io.{File, StringReader} +import java.io.File import akka.actor.{ActorRef, ActorSystem, Props} import akka.event.LoggingAdapter @@ -29,15 +29,14 @@ import akka.http.scaladsl.model._ import akka.stream.Materializer import com.typesafe.config.{Config, ConfigFactory} import com.typesafe.scalalogging.LazyLogging -import org.eclipse.rdf4j.model.Model -import org.eclipse.rdf4j.rio.{RDFFormat, Rio} import org.knora.webapi.app.{ApplicationActor, LiveManagers} import org.knora.webapi.core.Core +import org.knora.webapi.feature.{FeatureFactoryConfig, KnoraSettingsFeatureFactoryConfig, TestFeatureFactoryConfig} import org.knora.webapi.messages.StringFormatter import org.knora.webapi.messages.app.appmessages.{AppStart, AppStop, SetAllowReloadOverHTTPState} import org.knora.webapi.messages.store.triplestoremessages.{RdfDataObject, TriplestoreJsonProtocol} -import org.knora.webapi.messages.util.{JsonLDDocument, JsonLDUtil} -import org.knora.webapi.settings.{KnoraDispatchers, KnoraSettings, KnoraSettingsImpl, _} +import org.knora.webapi.messages.util.rdf._ +import org.knora.webapi.settings._ import org.knora.webapi.util.{FileUtil, StartupUtils} import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpecLike @@ -86,6 +85,11 @@ class E2ESpec(_system: ActorSystem) extends Core with StartupUtils with Triplest protected val baseApiUrl: String = settings.internalKnoraApiBaseUrl + protected val defaultFeatureFactoryConfig: FeatureFactoryConfig = new TestFeatureFactoryConfig( + testToggles = Set.empty, + parent = new KnoraSettingsFeatureFactoryConfig(settings) + ) + override def beforeAll: Unit = { // set allow reload over http @@ -136,16 +140,19 @@ class E2ESpec(_system: ActorSystem) extends Core with StartupUtils with Triplest responseToString(response) } - protected def parseTrig(trigStr: String): Model = { - Rio.parse(new StringReader(trigStr), "", RDFFormat.TRIG) + protected def parseTrig(trigStr: String): RdfModel = { + val rdfFormatUtil: RdfFormatUtil = RdfFeatureFactory.getRdfFormatUtil(defaultFeatureFactoryConfig) + rdfFormatUtil.parseToRdfModel(rdfStr = trigStr, rdfFormat = TriG) } - protected def parseTurtle(turtleStr: String): Model = { - Rio.parse(new StringReader(turtleStr), "", RDFFormat.TURTLE, null) + protected def parseTurtle(turtleStr: String): RdfModel = { + val rdfFormatUtil: RdfFormatUtil = RdfFeatureFactory.getRdfFormatUtil(defaultFeatureFactoryConfig) + rdfFormatUtil.parseToRdfModel(rdfStr = turtleStr, rdfFormat = Turtle) } - protected def parseRdfXml(rdfXmlStr: String): Model = { - Rio.parse(new StringReader(rdfXmlStr), "", RDFFormat.RDFXML, null) + protected def parseRdfXml(rdfXmlStr: String): RdfModel = { + val rdfFormatUtil: RdfFormatUtil = RdfFeatureFactory.getRdfFormatUtil(defaultFeatureFactoryConfig) + rdfFormatUtil.parseToRdfModel(rdfStr = rdfXmlStr, rdfFormat = RdfXml) } protected def getResponseEntityBytes(httpResponse: HttpResponse): Array[Byte] = { diff --git a/webapi/src/test/scala/org/knora/webapi/R2RSpec.scala b/webapi/src/test/scala/org/knora/webapi/R2RSpec.scala index aec0a11118..6cbe8218ee 100644 --- a/webapi/src/test/scala/org/knora/webapi/R2RSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/R2RSpec.scala @@ -19,7 +19,7 @@ package org.knora.webapi -import java.io.{File, StringReader} +import java.io.File import akka.actor.{ActorRef, ActorSystem, Props} import akka.event.LoggingAdapter @@ -30,16 +30,16 @@ import akka.pattern.ask import akka.util.Timeout import com.typesafe.config.ConfigFactory import com.typesafe.scalalogging.LazyLogging -import org.eclipse.rdf4j.model.Model -import org.eclipse.rdf4j.rio.{RDFFormat, Rio} import org.knora.webapi.app.{ApplicationActor, LiveManagers} import org.knora.webapi.core.Core +import org.knora.webapi.feature.{FeatureFactoryConfig, KnoraSettingsFeatureFactoryConfig, TestFeatureFactoryConfig} import org.knora.webapi.http.handler import org.knora.webapi.messages.StringFormatter import org.knora.webapi.messages.app.appmessages.{AppStart, AppStop, SetAllowReloadOverHTTPState} import org.knora.webapi.messages.store.triplestoremessages.{RdfDataObject, ResetRepositoryContent} -import org.knora.webapi.messages.util.{JsonLDDocument, JsonLDUtil, KnoraSystemInstances} -import org.knora.webapi.messages.v1.responder.ontologymessages.LoadOntologiesRequest +import org.knora.webapi.messages.util.KnoraSystemInstances +import org.knora.webapi.messages.util.rdf._ +import org.knora.webapi.messages.v2.responder.ontologymessages.LoadOntologiesRequestV2 import org.knora.webapi.routing.KnoraRouteData import org.knora.webapi.settings.{KnoraDispatchers, KnoraSettings, KnoraSettingsImpl, _} import org.knora.webapi.util.{FileUtil, StartupUtils} @@ -52,8 +52,8 @@ import scala.concurrent.{Await, ExecutionContext, Future} import scala.language.postfixOps /** - * R(oute)2R(esponder) Spec base class. Please, for any new E2E tests, use E2ESpec. - */ + * R(oute)2R(esponder) Spec base class. Please, for any new E2E tests, use E2ESpec. + */ class R2RSpec extends Core with StartupUtils with Suite with ScalatestRouteTest with AnyWordSpecLike with Matchers with BeforeAndAfterAll with LazyLogging { /* needed by the core trait */ @@ -62,6 +62,11 @@ class R2RSpec extends Core with StartupUtils with Suite with ScalatestRouteTest implicit lazy val settings: KnoraSettingsImpl = KnoraSettings(_system) + protected val defaultFeatureFactoryConfig: FeatureFactoryConfig = new TestFeatureFactoryConfig( + testToggles = Set.empty, + parent = new KnoraSettingsFeatureFactoryConfig(settings) + ) + lazy val executionContext: ExecutionContext = _system.dispatchers.lookup(KnoraDispatchers.KnoraActorDispatcher) // override so that we can use our own system @@ -114,28 +119,34 @@ class R2RSpec extends Core with StartupUtils with Suite with ScalatestRouteTest JsonLDUtil.parseJsonLD(responseBodyStr) } - protected def parseTurtle(turtleStr: String): Model = { - Rio.parse(new StringReader(turtleStr), "", RDFFormat.TURTLE, null) + protected def parseTurtle(turtleStr: String): RdfModel = { + val rdfFormatUtil: RdfFormatUtil = RdfFeatureFactory.getRdfFormatUtil(defaultFeatureFactoryConfig) + rdfFormatUtil.parseToRdfModel(rdfStr = turtleStr, rdfFormat = Turtle) } - protected def parseRdfXml(rdfXmlStr: String): Model = { - Rio.parse(new StringReader(rdfXmlStr), "", RDFFormat.RDFXML, null) + protected def parseRdfXml(rdfXmlStr: String): RdfModel = { + val rdfFormatUtil: RdfFormatUtil = RdfFeatureFactory.getRdfFormatUtil(defaultFeatureFactoryConfig) + rdfFormatUtil.parseToRdfModel(rdfStr = rdfXmlStr, rdfFormat = RdfXml) } protected def loadTestData(rdfDataObjects: Seq[RdfDataObject]): Unit = { implicit val timeout: Timeout = Timeout(settings.defaultTimeout) Await.result(appActor ? ResetRepositoryContent(rdfDataObjects), 5 minutes) - Await.result(appActor ? LoadOntologiesRequest(KnoraSystemInstances.Users.SystemUser), 30 seconds) + + Await.result(appActor ? LoadOntologiesRequestV2( + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ), 30 seconds) } /** - * Reads or writes a test data file. - * - * @param responseAsString the API response received from Knora. - * @param file the file in which the expected API response is stored. - * @param writeFile if `true`, writes the response to the file and returns it, otherwise returns the current contents of the file. - * @return the expected response. - */ + * Reads or writes a test data file. + * + * @param responseAsString the API response received from Knora. + * @param file the file in which the expected API response is stored. + * @param writeFile if `true`, writes the response to the file and returns it, otherwise returns the current contents of the file. + * @return the expected response. + */ protected def readOrWriteTextFile(responseAsString: String, file: File, writeFile: Boolean = false): String = { if (writeFile) { // Per default only read access is allowed in the bazel sandbox. diff --git a/webapi/src/test/scala/org/knora/webapi/e2e/FeatureToggleR2RSpec.scala b/webapi/src/test/scala/org/knora/webapi/e2e/FeatureToggleR2RSpec.scala index ef8a7ce567..3f4d9095ff 100644 --- a/webapi/src/test/scala/org/knora/webapi/e2e/FeatureToggleR2RSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/e2e/FeatureToggleR2RSpec.scala @@ -26,8 +26,7 @@ import akka.http.scaladsl.server.Directives.{get, path} import akka.http.scaladsl.server.Route import akka.http.scaladsl.testkit.RouteTestTimeout import akka.http.scaladsl.util.FastFuture -import com.typesafe.config.ConfigFactory -import org.knora.webapi.{R2RSpec, TestContainers} +import org.knora.webapi.R2RSpec import org.knora.webapi.feature._ import org.knora.webapi.routing.{KnoraRoute, KnoraRouteData, KnoraRouteFactory} @@ -37,15 +36,11 @@ import scala.concurrent.ExecutionContextExecutor * Tests feature toggles that replace implementations of API routes. */ class FeatureToggleR2RSpec extends R2RSpec { - // Don't take feature toggles from application.conf, just take them from the config in this spec. - override implicit lazy val _system: ActorSystem = ActorSystem(actorSystemNameFrom(getClass), - TestContainers.PortConfig.withFallback(ConfigFactory.parseString(testConfigSource).withFallback(ConfigFactory.load().withoutPath("app.feature-toggles")))) - // Some feature toggles for testing. override def testConfigSource: String = """app { | feature-toggles { - | new-foo { + | FeatureToggleR2RSpec-new-foo { | description = "Replace the old foo routes with new ones." | | available-versions = [ 1, 2 ] @@ -58,7 +53,7 @@ class FeatureToggleR2RSpec extends R2RSpec { | ] | } | - | new-bar { + | FeatureToggleR2RSpec-new-bar { | description = "Replace the old bar routes with new ones." | | available-versions = [ 1 ] @@ -71,7 +66,7 @@ class FeatureToggleR2RSpec extends R2RSpec { | ] | } | - | new-baz { + | FeatureToggleR2RSpec-new-baz { | description = "Replace the old baz routes with new ones." | | available-versions = [ 1 ] @@ -149,7 +144,7 @@ class FeatureToggleR2RSpec extends R2RSpec { */ def makeRoute(featureFactoryConfig: FeatureFactoryConfig): Route = { // Get the 'new-foo' feature toggle. - val fooToggle: FeatureToggle = featureFactoryConfig.getToggle("new-foo") + val fooToggle: FeatureToggle = featureFactoryConfig.getToggle("FeatureToggleR2RSpec-new-foo") // Choose a route according to the toggle state. val route: KnoraRoute = fooToggle.getMatchableState(NEW_FOO_1, NEW_FOO_2) match { @@ -177,7 +172,7 @@ class FeatureToggleR2RSpec extends R2RSpec { def makeRoute(featureFactoryConfig: FeatureFactoryConfig): Route = { // Is the 'new-bar' feature toggle enabled? - val route: KnoraRoute = if (featureFactoryConfig.getToggle("new-bar").isEnabled) { + val route: KnoraRoute = if (featureFactoryConfig.getToggle("FeatureToggleR2RSpec-new-bar").isEnabled) { // Yes. Use the new implementation. newBar } else { @@ -204,7 +199,7 @@ class FeatureToggleR2RSpec extends R2RSpec { def makeRoute(featureFactoryConfig: FeatureFactoryConfig): Route = { // Is the 'new-baz' feature toggle enabled? - val route: KnoraRoute = if (featureFactoryConfig.getToggle("new-baz").isEnabled) { + val route: KnoraRoute = if (featureFactoryConfig.getToggle("FeatureToggleR2RSpec-new-baz").isEnabled) { // Yes. Use the new implementation. newBaz } else { @@ -265,7 +260,10 @@ class FeatureToggleR2RSpec extends R2RSpec { */ private def parseResponseHeader(response: HttpResponse): Set[String] = { response.headers.find(_.lowercaseName == FeatureToggle.RESPONSE_HEADER_LOWERCASE) match { - case Some(header) => header.value.split(',').toSet + case Some(header) => header.value.split(',').toSet.filter { + toggleStr => toggleStr.contains("FeatureToggleR2RSpec") + } + case None => Set.empty } } @@ -276,62 +274,74 @@ class FeatureToggleR2RSpec extends R2RSpec { val responseStr = responseAs[String] assert(status == StatusCodes.OK, responseStr) assert(responseStr == "You are using the new foo, version 1") - assert(parseResponseHeader(response) == Set("new-foo:1=on", "new-bar:1=on", "new-baz=off")) + assert(parseResponseHeader(response) == Set( + "FeatureToggleR2RSpec-new-foo:1=on", + "FeatureToggleR2RSpec-new-bar:1=on", + "FeatureToggleR2RSpec-new-baz=off" + )) } } "turn off a toggle" in { - Get(s"/foo").addHeader(RawHeader(FeatureToggle.REQUEST_HEADER, "new-foo=off")) ~> fooRoute ~> check { + Get(s"/foo").addHeader(RawHeader(FeatureToggle.REQUEST_HEADER, "FeatureToggleR2RSpec-new-foo=off")) ~> fooRoute ~> check { val responseStr = responseAs[String] assert(status == StatusCodes.OK, responseStr) assert(responseStr == "You are using the old foo") - assert(parseResponseHeader(response) == Set("new-foo=off", "new-bar:1=on", "new-baz=off")) + assert(parseResponseHeader(response) == Set( + "FeatureToggleR2RSpec-new-foo=off", + "FeatureToggleR2RSpec-new-bar:1=on", + "FeatureToggleR2RSpec-new-baz=off" + )) } } "override the default toggle version" in { - Get(s"/foo").addHeader(RawHeader(FeatureToggle.REQUEST_HEADER, "new-foo:2=on")) ~> fooRoute ~> check { + Get(s"/foo").addHeader(RawHeader(FeatureToggle.REQUEST_HEADER, "FeatureToggleR2RSpec-new-foo:2=on")) ~> fooRoute ~> check { val responseStr = responseAs[String] assert(status == StatusCodes.OK, responseStr) assert(responseStr == "You are using the new foo, version 2") - assert(parseResponseHeader(response) == Set("new-foo:2=on", "new-bar:1=on", "new-baz=off")) + assert(parseResponseHeader(response) == Set( + "FeatureToggleR2RSpec-new-foo:2=on", + "FeatureToggleR2RSpec-new-bar:1=on", + "FeatureToggleR2RSpec-new-baz=off" + )) } } "not enable a toggle without specifying the version number" in { - Get(s"/foo").addHeader(RawHeader(FeatureToggle.REQUEST_HEADER, "new-foo=on")) ~> fooRoute ~> check { + Get(s"/foo").addHeader(RawHeader(FeatureToggle.REQUEST_HEADER, "FeatureToggleR2RSpec-new-foo=on")) ~> fooRoute ~> check { val responseStr = responseAs[String] assert(status == StatusCodes.BadRequest, responseStr) - assert(responseStr.contains("You must specify a version number to enable feature toggle new-foo")) + assert(responseStr.contains("You must specify a version number to enable feature toggle FeatureToggleR2RSpec-new-foo")) } } "not enable a nonexistent version of a toggle" in { - Get(s"/foo").addHeader(RawHeader(FeatureToggle.REQUEST_HEADER, "new-foo:3=on")) ~> fooRoute ~> check { + Get(s"/foo").addHeader(RawHeader(FeatureToggle.REQUEST_HEADER, "FeatureToggleR2RSpec-new-foo:3=on")) ~> fooRoute ~> check { val responseStr = responseAs[String] assert(status == StatusCodes.BadRequest, responseStr) - assert(responseStr.contains("Feature toggle new-foo has no version 3")) + assert(responseStr.contains("Feature toggle FeatureToggleR2RSpec-new-foo has no version 3")) } } "not accept a version number when disabling a toggle" in { - Get(s"/foo").addHeader(RawHeader(FeatureToggle.REQUEST_HEADER, "new-foo:2=off")) ~> fooRoute ~> check { + Get(s"/foo").addHeader(RawHeader(FeatureToggle.REQUEST_HEADER, "FeatureToggleR2RSpec-new-foo:2=off")) ~> fooRoute ~> check { val responseStr = responseAs[String] assert(status == StatusCodes.BadRequest, responseStr) - assert(responseStr.contains("You cannot specify a version number when disabling feature toggle new-foo")) + assert(responseStr.contains("You cannot specify a version number when disabling feature toggle FeatureToggleR2RSpec-new-foo")) } } "not override a default toggle if the base configuration doesn't allow it" in { - Get(s"/baz").addHeader(RawHeader(FeatureToggle.REQUEST_HEADER, "new-baz=on")) ~> bazRoute ~> check { + Get(s"/baz").addHeader(RawHeader(FeatureToggle.REQUEST_HEADER, "FeatureToggleR2RSpec-new-baz=on")) ~> bazRoute ~> check { val responseStr = responseAs[String] assert(status == StatusCodes.BadRequest, responseStr) - assert(responseStr.contains("Feature toggle new-baz cannot be overridden")) + assert(responseStr.contains("Feature toggle FeatureToggleR2RSpec-new-baz cannot be overridden")) } } "not accept two settings for the same toggle" in { - Get(s"/baz").addHeader(RawHeader(FeatureToggle.REQUEST_HEADER, "new-foo=off,new-foo:2=on")) ~> bazRoute ~> check { + Get(s"/baz").addHeader(RawHeader(FeatureToggle.REQUEST_HEADER, "FeatureToggleR2RSpec-new-foo=off,FeatureToggleR2RSpec-new-foo:2=on")) ~> bazRoute ~> check { val responseStr = responseAs[String] assert(status == StatusCodes.BadRequest, responseStr) assert(responseStr.contains("You cannot set the same feature toggle more than once per request")) diff --git a/webapi/src/test/scala/org/knora/webapi/e2e/InstanceChecker.scala b/webapi/src/test/scala/org/knora/webapi/e2e/InstanceChecker.scala index 3af4ed24cb..5cba1476a0 100644 --- a/webapi/src/test/scala/org/knora/webapi/e2e/InstanceChecker.scala +++ b/webapi/src/test/scala/org/knora/webapi/e2e/InstanceChecker.scala @@ -26,6 +26,7 @@ import org.knora.webapi._ import org.knora.webapi.exceptions.AssertionException import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.util._ +import org.knora.webapi.messages.util.rdf._ import org.knora.webapi.messages.v2.responder.ontologymessages.Cardinality._ import org.knora.webapi.messages.v2.responder.ontologymessages._ import org.knora.webapi.messages.{OntologyConstants, SmartIri, StringFormatter} @@ -429,16 +430,16 @@ class JsonLDInstanceInspector extends InstanceInspector { case jsonLDObject: JsonLDObject => if (jsonLDObject.isStringWithLang) { // This object represents a string with a language tag. - val literalContent = jsonLDObject.requireString(JsonLDConstants.VALUE) + val literalContent = jsonLDObject.requireString(JsonLDKeywords.VALUE) Vector(InstanceElement(elementType = OntologyConstants.Xsd.String, literalContent = Some(literalContent))) } else if (jsonLDObject.isDatatypeValue) { // This object represents a JSON-LD datatype value. - val datatype = jsonLDObject.requireString(JsonLDConstants.TYPE) - val literalContent = jsonLDObject.requireString(JsonLDConstants.VALUE) + val datatype = jsonLDObject.requireString(JsonLDKeywords.TYPE) + val literalContent = jsonLDObject.requireString(JsonLDKeywords.VALUE) Vector(InstanceElement(elementType = datatype, literalContent = Some(literalContent))) } else if (jsonLDObject.isIri) { // This object represents an IRI. - val literalContent = jsonLDObject.requireString(JsonLDConstants.ID) + val literalContent = jsonLDObject.requireString(JsonLDKeywords.ID) Vector(InstanceElement(elementType = OntologyConstants.Xsd.Uri, literalContent = Some(literalContent))) } else { // This object represents a class instance. @@ -466,11 +467,11 @@ class JsonLDInstanceInspector extends InstanceInspector { } private def jsonLDObjectToElement(jsonLDObject: JsonLDObject): InstanceElement = { - val elementType = jsonLDObject.requireString(JsonLDConstants.TYPE) + val elementType = jsonLDObject.requireString(JsonLDKeywords.TYPE) val propertyObjects: Map[String, Vector[InstanceElement]] = jsonLDObject.value.map { case (key, jsonLDValue: JsonLDValue) => key -> jsonLDValueToElements(jsonLDValue) - } - JsonLDConstants.ID - JsonLDConstants.TYPE + } - JsonLDKeywords.ID - JsonLDKeywords.TYPE InstanceElement(elementType = elementType, propertyObjects = propertyObjects) } diff --git a/webapi/src/test/scala/org/knora/webapi/e2e/admin/ProjectsADME2ESpec.scala b/webapi/src/test/scala/org/knora/webapi/e2e/admin/ProjectsADME2ESpec.scala index 9bee4fade3..525181aea4 100644 --- a/webapi/src/test/scala/org/knora/webapi/e2e/admin/ProjectsADME2ESpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/e2e/admin/ProjectsADME2ESpec.scala @@ -28,18 +28,17 @@ import akka.http.scaladsl.testkit.RouteTestTimeout import akka.http.scaladsl.unmarshalling.Unmarshal import akka.util.Timeout import com.typesafe.config.{Config, ConfigFactory} -import org.eclipse.rdf4j.model.Model import org.knora.webapi.e2e.{ClientTestDataCollector, TestDataFileContent, TestDataFilePath} import org.knora.webapi.messages.admin.responder.projectsmessages._ import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.admin.responder.usersmessages.UsersADMJsonProtocol._ import org.knora.webapi.messages.store.triplestoremessages.{RdfDataObject, StringLiteralV2, TriplestoreJsonProtocol} +import org.knora.webapi.messages.util.rdf.RdfModel import org.knora.webapi.messages.v1.responder.sessionmessages.SessionJsonProtocol import org.knora.webapi.sharedtestdata.SharedTestDataADM import org.knora.webapi.util.{AkkaHttpUtils, MutableTestIri} import org.knora.webapi.{E2ESpec, IRI} -import scala.collection.JavaConverters._ import scala.concurrent.duration._ import scala.concurrent.{Await, Future} @@ -708,8 +707,8 @@ class ProjectsADME2ESpec extends E2ESpec(ProjectsADME2ESpec.config) with Session assert(response.status === StatusCodes.OK) val trigStrFuture: Future[String] = Unmarshal(response.entity).to[String] val trigStr: String = Await.result(trigStrFuture, Timeout(5.seconds).duration) - val parsedTrig: Model = parseTrig(trigStr) - val contextIris: Set[IRI] = parsedTrig.contexts.asScala.map(_.stringValue).toSet + val parsedTrig: RdfModel = parseTrig(trigStr) + val contextIris: Set[IRI] = parsedTrig.getContexts assert(contextIris == Set( "http://www.knora.org/ontology/0001/something", diff --git a/webapi/src/test/scala/org/knora/webapi/e2e/v2/JSONLDHandlingV2R2RSpec.scala b/webapi/src/test/scala/org/knora/webapi/e2e/v2/JSONLDHandlingV2R2RSpec.scala index f2c4ca3bd8..7868edeabc 100644 --- a/webapi/src/test/scala/org/knora/webapi/e2e/v2/JSONLDHandlingV2R2RSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/e2e/v2/JSONLDHandlingV2R2RSpec.scala @@ -28,7 +28,7 @@ import akka.http.scaladsl.testkit.RouteTestTimeout import org.knora.webapi._ import org.knora.webapi.e2e.v2.ResponseCheckerV2._ import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject -import org.knora.webapi.messages.util.JsonLDUtil +import org.knora.webapi.messages.util.rdf.JsonLDUtil import org.knora.webapi.routing.v2.ResourcesRouteV2 import spray.json._ diff --git a/webapi/src/test/scala/org/knora/webapi/e2e/v2/ListsRouteV2R2RSpec.scala b/webapi/src/test/scala/org/knora/webapi/e2e/v2/ListsRouteV2R2RSpec.scala index 450aa15bee..f924ed71dc 100644 --- a/webapi/src/test/scala/org/knora/webapi/e2e/v2/ListsRouteV2R2RSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/e2e/v2/ListsRouteV2R2RSpec.scala @@ -26,10 +26,10 @@ import akka.actor.ActorSystem import akka.http.javadsl.model.StatusCodes import akka.http.scaladsl.model.headers.Accept import akka.http.scaladsl.testkit.RouteTestTimeout -import org.eclipse.rdf4j.model.Model import org.knora.webapi._ import org.knora.webapi.e2e.{ClientTestDataCollector, TestDataFileContent, TestDataFilePath} import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject +import org.knora.webapi.messages.util.rdf.RdfModel import org.knora.webapi.routing.v2.ListsRouteV2 import org.knora.webapi.util.FileUtil import spray.json.{JsValue, JsonParser} @@ -122,8 +122,8 @@ class ListsRouteV2R2RSpec extends R2RSpec { "perform a request for a list in Turtle" in { Get(s"/v2/lists/${URLEncoder.encode("http://rdfh.ch/lists/00FF/73d0ec0302", "UTF-8")}").addHeader(Accept(RdfMediaTypes.`text/turtle`)) ~> listsPath ~> check { assert(status == StatusCodes.OK, response.toString) - val expectedAnswerTurtle: Model = parseTurtle(FileUtil.readTextFile(new File("test_data/listsR2RV2/imagesList.ttl"))) - val responseTurtle: Model = parseTurtle(responseAs[String]) + val expectedAnswerTurtle: RdfModel = parseTurtle(FileUtil.readTextFile(new File("test_data/listsR2RV2/imagesList.ttl"))) + val responseTurtle: RdfModel = parseTurtle(responseAs[String]) assert(responseTurtle == expectedAnswerTurtle) } } @@ -131,8 +131,8 @@ class ListsRouteV2R2RSpec extends R2RSpec { "perform a request for a list in RDF/XML" in { Get(s"/v2/lists/${URLEncoder.encode("http://rdfh.ch/lists/00FF/73d0ec0302", "UTF-8")}").addHeader(Accept(RdfMediaTypes.`application/rdf+xml`)) ~> listsPath ~> check { assert(status == StatusCodes.OK, response.toString) - val expectedAnswerRdfXml: Model = parseRdfXml(FileUtil.readTextFile(new File("test_data/listsR2RV2/imagesList.rdf"))) - val responseRdfXml: Model = parseRdfXml(responseAs[String]) + val expectedAnswerRdfXml: RdfModel = parseRdfXml(FileUtil.readTextFile(new File("test_data/listsR2RV2/imagesList.rdf"))) + val responseRdfXml: RdfModel = parseRdfXml(responseAs[String]) assert(responseRdfXml == expectedAnswerRdfXml) } } @@ -170,8 +170,8 @@ class ListsRouteV2R2RSpec extends R2RSpec { "perform a request for a node in Turtle" in { Get(s"/v2/node/${URLEncoder.encode("http://rdfh.ch/lists/00FF/4348fb82f2", "UTF-8")}").addHeader(Accept(RdfMediaTypes.`text/turtle`)) ~> listsPath ~> check { assert(status == StatusCodes.OK, response.toString) - val expectedAnswerTurtle: Model = parseTurtle(FileUtil.readTextFile(new File("test_data/listsR2RV2/imagesListNode.ttl"))) - val responseTurtle: Model = parseTurtle(responseAs[String]) + val expectedAnswerTurtle: RdfModel = parseTurtle(FileUtil.readTextFile(new File("test_data/listsR2RV2/imagesListNode.ttl"))) + val responseTurtle: RdfModel = parseTurtle(responseAs[String]) assert(responseTurtle == expectedAnswerTurtle) } } @@ -179,8 +179,8 @@ class ListsRouteV2R2RSpec extends R2RSpec { "perform a request for a node in RDF/XML" in { Get(s"/v2/node/${URLEncoder.encode("http://rdfh.ch/lists/00FF/4348fb82f2", "UTF-8")}").addHeader(Accept(RdfMediaTypes.`application/rdf+xml`)) ~> listsPath ~> check { assert(status == StatusCodes.OK, response.toString) - val expectedAnswerRdfXml: Model = parseRdfXml(FileUtil.readTextFile(new File("test_data/listsR2RV2/imagesListNode.rdf"))) - val responseRdfXml: Model = parseRdfXml(responseAs[String]) + val expectedAnswerRdfXml: RdfModel = parseRdfXml(FileUtil.readTextFile(new File("test_data/listsR2RV2/imagesListNode.rdf"))) + val responseRdfXml: RdfModel = parseRdfXml(responseAs[String]) assert(responseRdfXml == expectedAnswerRdfXml) } } diff --git a/webapi/src/test/scala/org/knora/webapi/e2e/v2/MetadataRouteV2E2ESpec.scala b/webapi/src/test/scala/org/knora/webapi/e2e/v2/MetadataRouteV2E2ESpec.scala index ad36c5ce3c..bdb8c9e30d 100644 --- a/webapi/src/test/scala/org/knora/webapi/e2e/v2/MetadataRouteV2E2ESpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/e2e/v2/MetadataRouteV2E2ESpec.scala @@ -2,15 +2,15 @@ package org.knora.webapi.e2e.v2 import java.net.URLEncoder -import akka.http.scaladsl.model.{HttpEntity, HttpHeader, HttpResponse, MediaType} import akka.http.scaladsl.model.headers.{BasicHttpCredentials, RawHeader} -import org.knora.webapi.messages.util.RdfFormatUtil -import org.knora.webapi.{E2ESpec, IRI, RdfMediaTypes} +import akka.http.scaladsl.model.{HttpEntity, HttpResponse} +import org.knora.webapi.messages.util.rdf._ import org.knora.webapi.sharedtestdata.SharedTestDataADM +import org.knora.webapi._ class MetadataRouteV2E2ESpec extends E2ESpec { + private val rdfFormatUtil: RdfFormatUtil = RdfFeatureFactory.getRdfFormatUtil(defaultFeatureFactoryConfig) - // Directory path for generated client test data private val beolUserEmail = SharedTestDataADM.beolUser.email private val beolProjectIRI: IRI = SharedTestDataADM.BEOL_PROJECT_IRI private val password = SharedTestDataADM.testPass @@ -115,7 +115,7 @@ class MetadataRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status.isSuccess()) val responseString = responseToString(response) - assert(responseString.contains(s"Project metadata was stored for project <${beolProjectIRI}>.")) + assert(responseString.contains(s"Project metadata was stored for project <$beolProjectIRI>.")) } "perform a put request for the metadata of beol project given as JSON-LD" in { @@ -126,18 +126,18 @@ class MetadataRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status.isSuccess()) val responseString = responseToString(response) - assert(responseString.contains(s"Project metadata was stored for project <${beolProjectIRI}>.")) + assert(responseString.contains(s"Project metadata was stored for project <$beolProjectIRI>.")) } - "get the created metadata graph as JSON LD" in { + "get the created metadata graph as JSON-LD" in { val request = Get(s"$baseApiUrl/v2/metadata/${URLEncoder.encode(beolProjectIRI, "UTF-8")}") val response: HttpResponse = singleAwaitingRequest(request) val responseJSONLD = responseToJsonLDDocument(response) assert(response.status.isSuccess()) - val expectedGraphJSONLD = RdfFormatUtil.parseToJsonLDDocument( + val expectedGraphJSONLD: JsonLDDocument = rdfFormatUtil.parseToJsonLDDocument( rdfStr = metadataContent, - mediaType = RdfMediaTypes.`text/turtle` + rdfFormat = Turtle ) assert(expectedGraphJSONLD.body == responseJSONLD.body) diff --git a/webapi/src/test/scala/org/knora/webapi/e2e/v2/OntologyV2R2RSpec.scala b/webapi/src/test/scala/org/knora/webapi/e2e/v2/OntologyV2R2RSpec.scala index 7825f8c0d1..09b15e2baf 100644 --- a/webapi/src/test/scala/org/knora/webapi/e2e/v2/OntologyV2R2RSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/e2e/v2/OntologyV2R2RSpec.scala @@ -8,13 +8,12 @@ import akka.actor.ActorSystem import akka.http.scaladsl.model._ import akka.http.scaladsl.model.headers.{Accept, BasicHttpCredentials} import akka.http.scaladsl.testkit.RouteTestTimeout -import org.eclipse.rdf4j.model.Model import org.knora.webapi._ import org.knora.webapi.e2e.{ClientTestDataCollector, TestDataFileContent, TestDataFilePath} import org.knora.webapi.exceptions.AssertionException import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject -import org.knora.webapi.messages.util._ +import org.knora.webapi.messages.util.rdf._ import org.knora.webapi.messages.v2.responder.ontologymessages.{InputOntologyV2, TestResponseParsingModeV2} import org.knora.webapi.messages.{OntologyConstants, SmartIri, StringFormatter} import org.knora.webapi.routing.v2.OntologiesRouteV2 @@ -247,8 +246,8 @@ class OntologyV2R2RSpec extends R2RSpec { val existingFile: File = httpGetTest.makeFile(mediaType) if (existingFile.exists()) { - val parsedResponse: Model = parseRdfXml(responseStr) - val parsedExistingFile: Model = parseRdfXml(httpGetTest.readFile(mediaType)) + val parsedResponse: RdfModel = parseRdfXml(responseStr) + val parsedExistingFile: RdfModel = parseRdfXml(httpGetTest.readFile(mediaType)) if (parsedResponse != parsedExistingFile) { httpGetTest.writeFile(responseStr, mediaType) diff --git a/webapi/src/test/scala/org/knora/webapi/e2e/v2/ResourcesRouteV2E2ESpec.scala b/webapi/src/test/scala/org/knora/webapi/e2e/v2/ResourcesRouteV2E2ESpec.scala index 49664c9c03..775a43759d 100644 --- a/webapi/src/test/scala/org/knora/webapi/e2e/v2/ResourcesRouteV2E2ESpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/e2e/v2/ResourcesRouteV2E2ESpec.scala @@ -36,6 +36,7 @@ import org.knora.webapi.exceptions.AssertionException import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject import org.knora.webapi.messages.util._ +import org.knora.webapi.messages.util.rdf.{JsonLDArray, JsonLDKeywords, JsonLDDocument, JsonLDObject, JsonLDUtil, JsonLDValue} import org.knora.webapi.messages.{OntologyConstants, StringFormatter} import org.knora.webapi.routing.RouteUtilV2 import org.knora.webapi.sharedtestdata.SharedTestDataADM @@ -747,7 +748,7 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) assert(resourceIri.toSmartIri.isKnoraDataIri) // Request the newly created resource in the complex schema, and check that it matches the ontology. @@ -784,7 +785,7 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) assert(resourceIri.toSmartIri.isKnoraDataIri) } @@ -830,7 +831,7 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) assert(resourceIri.toSmartIri.isKnoraDataIri) val savedCreationDate: Instant = responseJsonDoc.body.requireDatatypeValueInObject( @@ -883,7 +884,7 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) assert(resourceIri == customIRI) } @@ -979,7 +980,7 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) // Request the newly created resource. val resourceGetRequest = Get(s"$baseApiUrl/v2/resources/${URLEncoder.encode(resourceIri, "UTF-8")}") ~> addCredentials(BasicHttpCredentials(anythingUserEmail, password)) @@ -989,7 +990,7 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) { // Get the value from the response. val resourceGetResponseAsJsonLD = JsonLDUtil.parseJsonLD(resourceGetResponseAsString) val valueIri: IRI = resourceGetResponseAsJsonLD.body.requireObject("http://0.0.0.0:3333/ontology/0001/anything/v2#hasBoolean"). - requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) assert(valueIri == customValueIRI) } @@ -1032,7 +1033,7 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) // Request the newly created resource. val resourceGetRequest = Get(s"$baseApiUrl/v2/resources/${URLEncoder.encode(resourceIri, "UTF-8")}") ~> addCredentials(BasicHttpCredentials(anythingUserEmail, password)) @@ -1088,7 +1089,7 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) // Request the newly created resource. val resourceGetRequest = Get(s"$baseApiUrl/v2/resources/${URLEncoder.encode(resourceIri, "UTF-8")}") ~> addCredentials(BasicHttpCredentials(anythingUserEmail, password)) @@ -1155,7 +1156,7 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) { assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) assert(resourceIri == customResourceIRI) // Request the newly created resource. @@ -1166,7 +1167,7 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) { // Get the value from the response. val resourceGetResponseAsJsonLD = JsonLDUtil.parseJsonLD(resourceGetResponseAsString) val valueIri: IRI = resourceGetResponseAsJsonLD.body.requireObject("http://0.0.0.0:3333/ontology/0001/anything/v2#hasBoolean"). - requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) assert(valueIri == customValueIRI) val valueUUID = resourceGetResponseAsJsonLD.body.requireObject("http://0.0.0.0:3333/ontology/0001/anything/v2#hasBoolean").requireString(OntologyConstants.KnoraApiV2Complex.ValueHasUUID) @@ -1230,7 +1231,7 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) assert(resourceIri.toSmartIri.isKnoraDataIri) val savedAttachedToUser: IRI = responseJsonDoc.body.requireIriInObject(OntologyConstants.KnoraApiV2Complex.AttachedToUser, stringFormatter.validateAndEscapeIri) assert(savedAttachedToUser == SharedTestDataADM.anythingUser1.id) @@ -1272,7 +1273,7 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) assert(resourceIri.toSmartIri.isKnoraDataIri) } @@ -1551,7 +1552,7 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) { assert(resourceCreateResponse.status == StatusCodes.OK, resourceCreateResponse.toString) val resourceCreateResponseAsJsonLD: JsonLDDocument = responseToJsonLDDocument(resourceCreateResponse) - val resourceIri: IRI = resourceCreateResponseAsJsonLD.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val resourceIri: IRI = resourceCreateResponseAsJsonLD.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) assert(resourceIri.toSmartIri.isKnoraDataIri) hamletResourceIri.set(resourceIri) } @@ -1599,7 +1600,7 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) { val textValue: JsonLDObject = resourceGetResponseAsJsonLD.body.requireObject("http://0.0.0.0:3333/ontology/0001/anything/v2#hasRichtext") val maybeTextValueAsXml: Option[String] = textValue.maybeString(OntologyConstants.KnoraApiV2Complex.TextValueAsXml) assert(maybeTextValueAsXml.isEmpty) - val textValueIri: IRI = textValue.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val textValueIri: IRI = textValue.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) val resourceIriEncoded: IRI = URLEncoder.encode(hamletResourceIri.get, "UTF-8") val textValueIriEncoded: IRI = URLEncoder.encode(textValueIri, "UTF-8") @@ -1615,7 +1616,7 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) { val standoffGetResponse: HttpResponse = singleAwaitingRequest(standoffGetRequest) val standoffGetResponseAsJsonLD: JsonLDObject = responseToJsonLDDocument(standoffGetResponse).body - val standoff: Seq[JsonLDValue] = standoffGetResponseAsJsonLD.maybeArray(JsonLDConstants.GRAPH).map(_.value).getOrElse(Seq.empty) + val standoff: Seq[JsonLDValue] = standoffGetResponseAsJsonLD.maybeArray(JsonLDKeywords.GRAPH).map(_.value).getOrElse(Seq.empty) val standoffAsJsonLDObjects: Seq[JsonLDObject] = standoff.map { case jsonLDObject: JsonLDObject => jsonLDObject @@ -1639,7 +1640,7 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) { instanceChecker.check( instanceResponse = docForValidation, - expectedClassIri = jsonLDObject.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr), + expectedClassIri = jsonLDObject.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr), knoraRouteGet = doGetRequest ) } @@ -1715,7 +1716,7 @@ class ResourcesRouteV2E2ESpec extends E2ESpec(ResourcesRouteV2E2ESpec.config) { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val resourceIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) assert(resourceIri.toSmartIri.isKnoraDataIri) // Request the newly created resource in the complex schema, and check that it matches the ontology. diff --git a/webapi/src/test/scala/org/knora/webapi/e2e/v2/ResponseCheckerV2.scala b/webapi/src/test/scala/org/knora/webapi/e2e/v2/ResponseCheckerV2.scala index 61c4a04387..e651742df9 100644 --- a/webapi/src/test/scala/org/knora/webapi/e2e/v2/ResponseCheckerV2.scala +++ b/webapi/src/test/scala/org/knora/webapi/e2e/v2/ResponseCheckerV2.scala @@ -23,12 +23,13 @@ import org.knora.webapi.IRI import org.knora.webapi.exceptions.AssertionException import org.knora.webapi.messages.OntologyConstants import org.knora.webapi.messages.util._ +import org.knora.webapi.messages.util.rdf.{JsonLDArray, JsonLDKeywords, JsonLDDocument, JsonLDInt, JsonLDObject, JsonLDUtil, JsonLDValue} object ResponseCheckerV2 { private val numberOfItemsMember: IRI = "http://schema.org/numberOfItems" - private val noPropertyKeys: Set[IRI] = Set(JsonLDConstants.ID, JsonLDConstants.TYPE, OntologyConstants.Rdfs.Label) + private val noPropertyKeys: Set[IRI] = Set(JsonLDKeywords.ID, JsonLDKeywords.TYPE, OntologyConstants.Rdfs.Label) /** @@ -71,26 +72,26 @@ object ResponseCheckerV2 { // Sort by the value object IRI if available, otherwise sort by the value itself. val sortedElements = values.value.sortBy { - case jsonLDObj: JsonLDObject => jsonLDObj.value(JsonLDConstants.ID) + case jsonLDObj: JsonLDObject => jsonLDObj.value(JsonLDKeywords.ID) case other => other } JsonLDArray(sortedElements) } - assert(expectedResource.value(JsonLDConstants.ID) == receivedResource.value(JsonLDConstants.ID), s"Received resource Iri ${receivedResource.value(JsonLDConstants.ID)} does not match expected Iri ${expectedResource.value(JsonLDConstants.ID)}") + assert(expectedResource.value(JsonLDKeywords.ID) == receivedResource.value(JsonLDKeywords.ID), s"Received resource Iri ${receivedResource.value(JsonLDKeywords.ID)} does not match expected Iri ${expectedResource.value(JsonLDKeywords.ID)}") - assert(expectedResource.value(JsonLDConstants.TYPE) == receivedResource.value(JsonLDConstants.TYPE), s"Received resource type ${receivedResource.value(JsonLDConstants.TYPE)} does not match expected type ${expectedResource.value(JsonLDConstants.TYPE)}") + assert(expectedResource.value(JsonLDKeywords.TYPE) == receivedResource.value(JsonLDKeywords.TYPE), s"Received resource type ${receivedResource.value(JsonLDKeywords.TYPE)} does not match expected type ${expectedResource.value(JsonLDKeywords.TYPE)}") - assert(expectedResource.value(OntologyConstants.Rdfs.Label) == receivedResource.value(OntologyConstants.Rdfs.Label), s"rdfs:label did not match for ${receivedResource.value(JsonLDConstants.ID)}") + assert(expectedResource.value(OntologyConstants.Rdfs.Label) == receivedResource.value(OntologyConstants.Rdfs.Label), s"rdfs:label did not match for ${receivedResource.value(JsonLDKeywords.ID)}") - assert(expectedResource.value.keySet -- noPropertyKeys == receivedResource.value.keySet -- noPropertyKeys, s"property Iris are different for resource ${receivedResource.value(JsonLDConstants.ID)}: expected ${expectedResource.value.keySet -- noPropertyKeys}, received ${receivedResource.value.keySet -- noPropertyKeys}") + assert(expectedResource.value.keySet -- noPropertyKeys == receivedResource.value.keySet -- noPropertyKeys, s"property Iris are different for resource ${receivedResource.value(JsonLDKeywords.ID)}: expected ${expectedResource.value.keySet -- noPropertyKeys}, received ${receivedResource.value.keySet -- noPropertyKeys}") (expectedResource.value -- noPropertyKeys).foreach { case (propIri: IRI, expectedValuesForProp: JsonLDValue) => // make sure that the property Iri exists in the received resource - assert(receivedResource.value.contains(propIri), s"Property $propIri not found in received resource ${receivedResource.value(JsonLDConstants.ID)}") + assert(receivedResource.value.contains(propIri), s"Property $propIri not found in received resource ${receivedResource.value(JsonLDKeywords.ID)}") val sortedExpectedPropertyValues: JsonLDArray = sortPropertyValues(elementToArray(expectedValuesForProp)) val sortedReceivedPropertyValues: JsonLDArray = sortPropertyValues(elementToArray(receivedResource.value(propIri))) @@ -118,10 +119,10 @@ object ResponseCheckerV2 { def compareParsedJSONLDForResourcesResponse(expectedResponse: JsonLDDocument, receivedResponse: JsonLDDocument): Unit = { // returns a list even if there is only one element - val expectedResourcesAsArray: JsonLDArray = elementToArray(expectedResponse.body.value.getOrElse(JsonLDConstants.GRAPH, expectedResponse.body)) + val expectedResourcesAsArray: JsonLDArray = elementToArray(expectedResponse.body.value.getOrElse(JsonLDKeywords.GRAPH, expectedResponse.body)) // returns a list even if there is only one element - val receivedResourcesAsArray: JsonLDArray = elementToArray(receivedResponse.body.value.getOrElse(JsonLDConstants.GRAPH, receivedResponse.body)) + val receivedResourcesAsArray: JsonLDArray = elementToArray(receivedResponse.body.value.getOrElse(JsonLDKeywords.GRAPH, receivedResponse.body)) // check that the actual amount of resources returned is correct // this check is necessary because zip returns a sequence of the length of the smaller of the two lists to be combined. @@ -179,7 +180,7 @@ object ResponseCheckerV2 { */ def checkSearchResponseNumberOfResults(receivedJSONLD: String, expectedNumber: Int): Unit = { val receivedJsonLDDocument = JsonLDUtil.parseJsonLD(receivedJSONLD) - val receivedResourcesAsArray: JsonLDArray = elementToArray(receivedJsonLDDocument.body.value.getOrElse(JsonLDConstants.GRAPH, receivedJsonLDDocument.body)) + val receivedResourcesAsArray: JsonLDArray = elementToArray(receivedJsonLDDocument.body.value.getOrElse(JsonLDKeywords.GRAPH, receivedJsonLDDocument.body)) val numberOfResultsReceived = receivedResourcesAsArray.value.size assert(numberOfResultsReceived == expectedNumber, s"Expected $expectedNumber results, received $numberOfResultsReceived") } diff --git a/webapi/src/test/scala/org/knora/webapi/e2e/v2/SearchRouteV2R2RSpec.scala b/webapi/src/test/scala/org/knora/webapi/e2e/v2/SearchRouteV2R2RSpec.scala index 104bb96a9c..0781a29020 100644 --- a/webapi/src/test/scala/org/knora/webapi/e2e/v2/SearchRouteV2R2RSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/e2e/v2/SearchRouteV2R2RSpec.scala @@ -32,8 +32,8 @@ import org.knora.webapi.e2e.v2.ResponseCheckerV2._ import org.knora.webapi.e2e.{ClientTestDataCollector, TestDataFileContent, TestDataFilePath} import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject +import org.knora.webapi.messages.util.rdf.{JsonLDKeywords, JsonLDDocument, JsonLDUtil} import org.knora.webapi.messages.util.search.SparqlQueryConstants -import org.knora.webapi.messages.util.{JsonLDConstants, JsonLDDocument, JsonLDUtil} import org.knora.webapi.messages.{OntologyConstants, StringFormatter} import org.knora.webapi.routing.RouteUtilV2 import org.knora.webapi.routing.v1.ValuesRouteV1 @@ -7788,7 +7788,7 @@ class SearchRouteV2R2RSpec extends R2RSpec { val resourceCreateResponseStr = responseAs[String] assert(status == StatusCodes.OK, resourceCreateResponseStr) val resourceCreateResponseAsJsonLD: JsonLDDocument = JsonLDUtil.parseJsonLD(resourceCreateResponseStr) - val resourceIri: IRI = resourceCreateResponseAsJsonLD.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val resourceIri: IRI = resourceCreateResponseAsJsonLD.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) assert(resourceIri.toSmartIri.isKnoraDataIri) hamletResourceIri.set(resourceIri) } @@ -7848,7 +7848,7 @@ class SearchRouteV2R2RSpec extends R2RSpec { val createTargetResourceResponseStr = responseAs[String] assert(response.status == StatusCodes.OK, createTargetResourceResponseStr) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) } assert(targetResourceIri.toSmartIri.isKnoraDataIri) @@ -7879,7 +7879,7 @@ class SearchRouteV2R2RSpec extends R2RSpec { val createSourceResource1ResponseStr = responseAs[String] assert(response.status == StatusCodes.OK, createSourceResource1ResponseStr) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) } assert(sourceResource1Iri.toSmartIri.isKnoraDataIri) @@ -7910,7 +7910,7 @@ class SearchRouteV2R2RSpec extends R2RSpec { val createSourceResource2ResponseStr = responseAs[String] assert(response.status == StatusCodes.OK, createSourceResource2ResponseStr) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) } assert(sourceResource2Iri.toSmartIri.isKnoraDataIri) @@ -7936,7 +7936,7 @@ class SearchRouteV2R2RSpec extends R2RSpec { val searchResponseStr = responseAs[String] assert(status == StatusCodes.OK, searchResponseStr) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) } assert(searchResultIri == targetResourceIri) @@ -8080,7 +8080,7 @@ class SearchRouteV2R2RSpec extends R2RSpec { val responseStr = responseAs[String] assert(status == StatusCodes.OK, responseStr) val resourceCreateResponseAsJsonLD: JsonLDDocument = JsonLDUtil.parseJsonLD(responseStr) - val resourceIri: IRI = resourceCreateResponseAsJsonLD.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val resourceIri: IRI = resourceCreateResponseAsJsonLD.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) assert(resourceIri.toSmartIri.isKnoraDataIri) timeTagResourceIri.set(resourceIri) } @@ -8110,7 +8110,7 @@ class SearchRouteV2R2RSpec extends R2RSpec { assert(status == StatusCodes.OK, responseStr) val responseAsJsonLD: JsonLDDocument = JsonLDUtil.parseJsonLD(responseStr) - val resourceIri: IRI = responseAsJsonLD.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val resourceIri: IRI = responseAsJsonLD.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) assert(resourceIri == timeTagResourceIri.get) val xmlFromResponse: String = responseAsJsonLD.body.requireObject("http://0.0.0.0:3333/ontology/0001/anything/v2#hasText"). diff --git a/webapi/src/test/scala/org/knora/webapi/e2e/v2/ValuesRouteV2E2ESpec.scala b/webapi/src/test/scala/org/knora/webapi/e2e/v2/ValuesRouteV2E2ESpec.scala index 74ddab325f..24f4a1f8ee 100644 --- a/webapi/src/test/scala/org/knora/webapi/e2e/v2/ValuesRouteV2E2ESpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/e2e/v2/ValuesRouteV2E2ESpec.scala @@ -37,6 +37,7 @@ import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject import org.knora.webapi.messages.util.search.SparqlQueryConstants import org.knora.webapi.messages.util._ +import org.knora.webapi.messages.util.rdf.{JsonLDArray, JsonLDKeywords, JsonLDDocument, JsonLDObject, JsonLDUtil} import org.knora.webapi.messages.{OntologyConstants, SmartIri, StringFormatter} import org.knora.webapi.sharedtestdata.SharedTestDataADM import org.knora.webapi.util._ @@ -160,11 +161,11 @@ class ValuesRouteV2E2ESpec extends E2ESpec { private def getValueFromResource(resource: JsonLDDocument, propertyIriInResult: SmartIri, expectedValueIri: IRI): JsonLDObject = { - val resourceIri: IRI = resource.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val resourceIri: IRI = resource.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) val propertyValues: JsonLDArray = getValuesFromResource(resource = resource, propertyIriInResult = propertyIriInResult) val matchingValues: Seq[JsonLDObject] = propertyValues.value.collect { - case jsonLDObject: JsonLDObject if jsonLDObject.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) == expectedValueIri => jsonLDObject + case jsonLDObject: JsonLDObject if jsonLDObject.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) == expectedValueIri => jsonLDObject } if (matchingValues.isEmpty) { @@ -181,8 +182,8 @@ class ValuesRouteV2E2ESpec extends E2ESpec { private def parseResourceLastModificationDate(resource: JsonLDDocument): Option[Instant] = { resource.maybeObject(OntologyConstants.KnoraApiV2Complex.LastModificationDate).map { jsonLDObject => - jsonLDObject.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.validateAndEscapeIri) should ===(OntologyConstants.Xsd.DateTimeStamp) - jsonLDObject.requireStringWithValidation(JsonLDConstants.VALUE, stringFormatter.xsdDateTimeStampToInstant) + jsonLDObject.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.validateAndEscapeIri) should ===(OntologyConstants.Xsd.DateTimeStamp) + jsonLDObject.requireStringWithValidation(JsonLDKeywords.VALUE, stringFormatter.xsdDateTimeStampToInstant) } } @@ -762,9 +763,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val responseStr: String = responseToString(response) assert(response.status == StatusCodes.OK, responseStr) val responseJsonDoc: JsonLDDocument = JsonLDUtil.parseJsonLD(responseStr) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) intValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.IntValue.toSmartIri) integerValueUUID = responseJsonDoc.body.requireStringWithValidation(OntologyConstants.KnoraApiV2Complex.ValueHasUUID, stringFormatter.validateBase64EncodedUuid) @@ -828,7 +829,7 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) assert(valueIri == customValueIri) } @@ -941,7 +942,7 @@ class ValuesRouteV2E2ESpec extends E2ESpec { assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) intValueForRsyncIri.set(valueIri) val savedCreationDate: Instant = responseJsonDoc.body.requireDatatypeValueInObject( @@ -996,7 +997,7 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) assert(valueIri == customValueIri) val valueUUID = responseJsonDoc.body.requireString(OntologyConstants.KnoraApiV2Complex.ValueHasUUID) assert(valueUUID == customValueUUID) @@ -1068,9 +1069,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) intValueWithCustomPermissionsIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.IntValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -1114,9 +1115,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) textValueWithoutStandoffIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.TextValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -1189,9 +1190,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) textValueWithoutStandoffIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.TextValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -1235,9 +1236,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) textValueWithoutStandoffIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.TextValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -1286,9 +1287,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) textValueWithoutStandoffIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.TextValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -1341,9 +1342,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) textValueWithoutStandoffIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.TextValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -1388,9 +1389,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val responseStr = responseToString(response) assert(response.status == StatusCodes.OK, responseStr) val responseJsonDoc: JsonLDDocument = JsonLDUtil.parseJsonLD(responseStr) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) textValueWithStandoffIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.TextValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -1853,9 +1854,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) textValueWithStandoffIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.TextValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -1897,8 +1898,8 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.TextValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -1922,7 +1923,7 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) textValueWithEscapeIri.set(valueIri) val propertyIri: SmartIri = "http://0.0.0.0:3333/ontology/0001/anything/v2#hasText".toSmartIri @@ -2001,7 +2002,7 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) textValueWithStandoffIri.set(valueIri) val savedValue: JsonLDObject = getValue( @@ -2070,9 +2071,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) decimalValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.DecimalValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -2135,9 +2136,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) dateValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.DateValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -2199,9 +2200,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) dateValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.DateValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -2259,9 +2260,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) dateValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.DateValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -2313,9 +2314,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) dateValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.DateValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -2363,9 +2364,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) dateValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.DateValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -2410,9 +2411,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) dateValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.DateValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -2460,9 +2461,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) dateValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.DateValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -2511,9 +2512,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) dateValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.DateValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -2570,9 +2571,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) booleanValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.BooleanValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -2622,9 +2623,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) geometryValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.GeomValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -2684,9 +2685,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) intervalValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.IntervalValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -2754,9 +2755,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) timeValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.TimeValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -2815,9 +2816,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) listValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.ListValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -2869,9 +2870,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) colorValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.ColorValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -2926,9 +2927,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) uriValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.UriValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -2985,9 +2986,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) geonameValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.GeonameValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -3042,9 +3043,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) linkValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.LinkValue.toSmartIri) linkValueUUID = responseJsonDoc.body.requireStringWithValidation(OntologyConstants.KnoraApiV2Complex.ValueHasUUID, stringFormatter.validateBase64EncodedUuid) @@ -3058,7 +3059,7 @@ class ValuesRouteV2E2ESpec extends E2ESpec { ) val savedTarget: JsonLDObject = savedValue.requireObject(OntologyConstants.KnoraApiV2Complex.LinkValueHasTarget) - val savedTargetIri: IRI = savedTarget.requireString(JsonLDConstants.ID) + val savedTargetIri: IRI = savedTarget.requireString(JsonLDKeywords.ID) savedTargetIri should ===(TestDing.iri) } @@ -3107,7 +3108,7 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) assert(valueIri == customValueIri) val valueUUID: IRI = responseJsonDoc.body.requireString(OntologyConstants.KnoraApiV2Complex.ValueHasUUID) assert(valueUUID == customValueUUID) @@ -3158,9 +3159,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val responseStr: String = responseToString(response) assert(response.status == StatusCodes.OK, responseStr) val responseJsonDoc: JsonLDDocument = JsonLDUtil.parseJsonLD(responseStr) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) intValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.IntValue.toSmartIri) val newIntegerValueUUID: UUID = responseJsonDoc.body.requireStringWithValidation(OntologyConstants.KnoraApiV2Complex.ValueHasUUID, stringFormatter.validateBase64EncodedUuid) assert(newIntegerValueUUID == integerValueUUID) // The new version should have the same UUID. @@ -3231,9 +3232,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) intValueForRsyncIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.IntValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -3276,7 +3277,7 @@ class ValuesRouteV2E2ESpec extends E2ESpec { println(responseToString(response)) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) assert(valueIri == newValueVersionIri) intValueForRsyncIri.set(valueIri) @@ -3428,9 +3429,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) intValueWithCustomPermissionsIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.IntValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -3484,9 +3485,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) intValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.IntValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -3542,9 +3543,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) decimalValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.DecimalValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -3604,9 +3605,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) textValueWithStandoffIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.TextValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -3632,7 +3633,7 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) textValueWithEscapeIri.set(valueIri) val propertyIri: SmartIri = "http://0.0.0.0:3333/ontology/0001/anything/v2#hasText".toSmartIri @@ -3672,9 +3673,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) textValueWithoutStandoffIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.TextValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -3735,9 +3736,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) dateValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.DateValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -3800,9 +3801,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) dateValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.DateValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -3861,9 +3862,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) dateValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.DateValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -3915,9 +3916,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) dateValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.DateValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -3966,9 +3967,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) dateValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.DateValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -4014,9 +4015,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) dateValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.DateValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -4076,9 +4077,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) booleanValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.BooleanValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -4129,9 +4130,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) geometryValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.GeomValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -4192,9 +4193,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) intervalValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.IntervalValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -4263,9 +4264,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) timeValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.TimeValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -4325,9 +4326,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) listValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.ListValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -4380,9 +4381,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) colorValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.ColorValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -4438,9 +4439,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) uriValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.UriValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -4498,9 +4499,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { val response: HttpResponse = singleAwaitingRequest(request) assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) geonameValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.GeonameValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -4545,9 +4546,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) linkValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.LinkValue.toSmartIri) // When you change a link value's target, it gets a new UUID. @@ -4565,7 +4566,7 @@ class ValuesRouteV2E2ESpec extends E2ESpec { ) val savedTarget: JsonLDObject = savedValue.requireObject(OntologyConstants.KnoraApiV2Complex.LinkValueHasTarget) - val savedTargetIri: IRI = savedTarget.requireString(JsonLDConstants.ID) + val savedTargetIri: IRI = savedTarget.requireString(JsonLDKeywords.ID) savedTargetIri should ===(linkTargetIri) } @@ -4604,9 +4605,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) linkValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.LinkValue.toSmartIri) // Since we only changed metadata, the UUID should be the same. @@ -4646,9 +4647,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) linkValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.LinkValue.toSmartIri) // Since we only changed metadata, the UUID should be the same. @@ -4715,9 +4716,9 @@ class ValuesRouteV2E2ESpec extends E2ESpec { assert(response.status == StatusCodes.OK, response.toString) val responseJsonDoc: JsonLDDocument = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) linkValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.LinkValue.toSmartIri) val savedValue: JsonLDObject = getValue( @@ -4730,7 +4731,7 @@ class ValuesRouteV2E2ESpec extends E2ESpec { ) val savedTarget: JsonLDObject = savedValue.requireObject(OntologyConstants.KnoraApiV2Complex.LinkValueHasTarget) - val savedTargetIri: IRI = savedTarget.requireString(JsonLDConstants.ID) + val savedTargetIri: IRI = savedTarget.requireString(JsonLDKeywords.ID) savedTargetIri should ===(TestDing.iri) val savedComment: String = savedValue.requireString(OntologyConstants.KnoraApiV2Complex.ValueHasComment) diff --git a/webapi/src/test/scala/org/knora/webapi/e2e/v2/ValuesV2R2RSpec.scala b/webapi/src/test/scala/org/knora/webapi/e2e/v2/ValuesV2R2RSpec.scala index f76ee1efef..ba5f2c97a5 100644 --- a/webapi/src/test/scala/org/knora/webapi/e2e/v2/ValuesV2R2RSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/e2e/v2/ValuesV2R2RSpec.scala @@ -29,11 +29,11 @@ import org.knora.webapi.e2e.{ClientTestDataCollector, TestDataFileContent, TestD import org.knora.webapi.exceptions.AssertionException import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject +import org.knora.webapi.messages.util.rdf._ import org.knora.webapi.messages.util.search.SparqlQueryConstants -import org.knora.webapi.messages.util.{JsonLDArray, JsonLDConstants, JsonLDDocument, JsonLDObject} import org.knora.webapi.messages.{OntologyConstants, SmartIri, StringFormatter} import org.knora.webapi.routing.v2.{SearchRouteV2, ValuesRouteV2} -import org.knora.webapi.settings.{KnoraDispatchers, _} +import org.knora.webapi.settings._ import org.knora.webapi.sharedtestdata.SharedTestDataADM import org.knora.webapi.util.MutableTestIri @@ -103,11 +103,11 @@ class ValuesV2R2RSpec extends R2RSpec { private def getValueFromResource(resource: JsonLDDocument, propertyIriInResult: SmartIri, expectedValueIri: IRI): JsonLDObject = { - val resourceIri: IRI = resource.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val resourceIri: IRI = resource.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) val propertyValues: JsonLDArray = getValuesFromResource(resource = resource, propertyIriInResult = propertyIriInResult) val matchingValues: Seq[JsonLDObject] = propertyValues.value.collect { - case jsonLDObject: JsonLDObject if jsonLDObject.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) == expectedValueIri => jsonLDObject + case jsonLDObject: JsonLDObject if jsonLDObject.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) == expectedValueIri => jsonLDObject } if (matchingValues.isEmpty) { @@ -173,9 +173,9 @@ class ValuesV2R2RSpec extends R2RSpec { Put("/v2/values", HttpEntity(RdfMediaTypes.`application/ld+json`, jsonLDEntity)) ~> addCredentials(BasicHttpCredentials(anythingUserEmail, password)) ~> valuesPath ~> check { assert(status == StatusCodes.OK, response.toString) val responseJsonDoc = responseToJsonLDDocument(response) - val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.ID, stringFormatter.validateAndEscapeIri) + val valueIri: IRI = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.ID, stringFormatter.validateAndEscapeIri) stillImageFileValueIri.set(valueIri) - val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDConstants.TYPE, stringFormatter.toSmartIriWithErr) + val valueType: SmartIri = responseJsonDoc.body.requireStringWithValidation(JsonLDKeywords.TYPE, stringFormatter.toSmartIriWithErr) valueType should ===(OntologyConstants.KnoraApiV2Complex.StillImageFileValue.toSmartIri) val savedValue: JsonLDObject = getValue( diff --git a/webapi/src/test/scala/org/knora/webapi/messages/admin/responder/permissionsmessages/PermissionsMessagesADMSpec.scala b/webapi/src/test/scala/org/knora/webapi/messages/admin/responder/permissionsmessages/PermissionsMessagesADMSpec.scala index 34a8a06cd8..dbba42bf67 100644 --- a/webapi/src/test/scala/org/knora/webapi/messages/admin/responder/permissionsmessages/PermissionsMessagesADMSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/messages/admin/responder/permissionsmessages/PermissionsMessagesADMSpec.scala @@ -21,18 +21,17 @@ package org.knora.webapi.messages.admin.responder.permissionsmessages import java.util.UUID +import org.knora.webapi.CoreSpec import org.knora.webapi.exceptions.{BadRequestException, ForbiddenException} import org.knora.webapi.messages.OntologyConstants import org.knora.webapi.sharedtestdata.SharedOntologyTestDataADM._ -import org.knora.webapi.sharedtestdata._ import org.knora.webapi.sharedtestdata.SharedTestDataV1._ -import org.scalatest.matchers.should.Matchers -import org.scalatest.wordspec.AnyWordSpecLike +import org.knora.webapi.sharedtestdata._ /** - * This spec is used to test subclasses of the [[UsersResponderRequestV1]] class. + * This spec is used to test subclasses of the [[PermissionsResponderRequestADM]] class. */ -class PermissionsMessagesADMSpec extends AnyWordSpecLike with Matchers { +class PermissionsMessagesADMSpec extends CoreSpec() { "Administrative Permission Get Requests" should { "return 'BadRequest' if the supplied project IRI for AdministrativePermissionsForProjectGetRequestADM is not valid" in { @@ -112,6 +111,7 @@ class PermissionsMessagesADMSpec extends AnyWordSpecLike with Matchers { forGroup = OntologyConstants.KnoraAdmin.ProjectMember, hasPermissions = Set(PermissionADM.ProjectAdminAllPermission) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser01, apiRequestID = UUID.randomUUID() ) @@ -128,6 +128,7 @@ class PermissionsMessagesADMSpec extends AnyWordSpecLike with Matchers { forGroup = OntologyConstants.KnoraAdmin.ProjectMember, hasPermissions = Set(PermissionADM.ProjectAdminAllPermission) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser01, apiRequestID = UUID.randomUUID() ) @@ -143,6 +144,7 @@ class PermissionsMessagesADMSpec extends AnyWordSpecLike with Matchers { forGroup = OntologyConstants.KnoraAdmin.ProjectMember, hasPermissions = Set.empty[PermissionADM] ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser01, apiRequestID = UUID.randomUUID() ) @@ -158,6 +160,7 @@ class PermissionsMessagesADMSpec extends AnyWordSpecLike with Matchers { forGroup = OntologyConstants.KnoraAdmin.ProjectMember, hasPermissions = Set(PermissionADM.ProjectAdminAllPermission) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesReviewerUser, apiRequestID = UUID.randomUUID() ) @@ -450,6 +453,7 @@ class PermissionsMessagesADMSpec extends AnyWordSpecLike with Matchers { forGroup = Some(OntologyConstants.KnoraAdmin.ProjectMember), hasPermissions = Set(PermissionADM.changeRightsPermission(OntologyConstants.KnoraAdmin.ProjectMember)) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser01, apiRequestID = UUID.randomUUID() ) @@ -466,6 +470,7 @@ class PermissionsMessagesADMSpec extends AnyWordSpecLike with Matchers { forGroup = Some(OntologyConstants.KnoraAdmin.ProjectMember), hasPermissions = Set(PermissionADM.changeRightsPermission(OntologyConstants.KnoraAdmin.ProjectMember)) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser01, apiRequestID = UUID.randomUUID() ) @@ -481,6 +486,7 @@ class PermissionsMessagesADMSpec extends AnyWordSpecLike with Matchers { forGroup = Some(SharedTestDataADM.thingSearcherGroup.id), hasPermissions = Set.empty[PermissionADM] ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.anythingAdminUser, apiRequestID = UUID.randomUUID() ) @@ -496,6 +502,7 @@ class PermissionsMessagesADMSpec extends AnyWordSpecLike with Matchers { forGroup = Some(SharedTestDataADM.thingSearcherGroup.id), hasPermissions = Set(PermissionADM.restrictedViewPermission(SharedTestDataADM.thingSearcherGroup.id)) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.anythingUser2, apiRequestID = UUID.randomUUID() ) @@ -512,6 +519,7 @@ class PermissionsMessagesADMSpec extends AnyWordSpecLike with Matchers { forResourceClass = Some(ANYTHING_THING_RESOURCE_CLASS_LocalHost), hasPermissions = Set(PermissionADM.changeRightsPermission(OntologyConstants.KnoraAdmin.ProjectMember)) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser01, apiRequestID = UUID.randomUUID() ) @@ -528,6 +536,7 @@ class PermissionsMessagesADMSpec extends AnyWordSpecLike with Matchers { forProperty = Some(ANYTHING_HasDate_PROPERTY_LocalHost), hasPermissions = Set(PermissionADM.changeRightsPermission(OntologyConstants.KnoraAdmin.ProjectMember)) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser01, apiRequestID = UUID.randomUUID() ) @@ -543,6 +552,7 @@ class PermissionsMessagesADMSpec extends AnyWordSpecLike with Matchers { forProperty = Some(SharedTestDataADM.customValueIRI), hasPermissions = Set(PermissionADM.changeRightsPermission(OntologyConstants.KnoraAdmin.ProjectMember)) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser01, apiRequestID = UUID.randomUUID() ) @@ -558,11 +568,12 @@ class PermissionsMessagesADMSpec extends AnyWordSpecLike with Matchers { forResourceClass = Some(ANYTHING_THING_RESOURCE_CLASS_LocalHost), hasPermissions = Set(PermissionADM.changeRightsPermission(OntologyConstants.KnoraAdmin.ProjectMember)) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser01, apiRequestID = UUID.randomUUID() ) ) - assert(caught.getMessage === s"Invalid resource class IRI: ${ANYTHING_THING_RESOURCE_CLASS_LocalHost}") + assert(caught.getMessage === s"Invalid resource class IRI: $ANYTHING_THING_RESOURCE_CLASS_LocalHost") } "return 'BadRequest' if neither a group, nor a resource class, nor a property is supplied for DefaultObjectAccessPermissionCreateRequestADM" in { @@ -572,6 +583,7 @@ class PermissionsMessagesADMSpec extends AnyWordSpecLike with Matchers { forProject = ANYTHING_PROJECT_IRI, hasPermissions = Set(PermissionADM.changeRightsPermission(OntologyConstants.KnoraAdmin.ProjectMember)) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser01, apiRequestID = UUID.randomUUID() ) @@ -585,6 +597,7 @@ class PermissionsMessagesADMSpec extends AnyWordSpecLike with Matchers { val caught = intercept[BadRequestException]( PermissionsForProjectGetRequestADM( projectIri = "invalid-project-IRI", + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser01, apiRequestID = UUID.randomUUID() ) @@ -596,6 +609,7 @@ class PermissionsMessagesADMSpec extends AnyWordSpecLike with Matchers { val caught = intercept[ForbiddenException]( PermissionsForProjectGetRequestADM( projectIri = SharedTestDataADM.IMAGES_PROJECT_IRI, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser02, apiRequestID = UUID.randomUUID() ) diff --git a/webapi/src/test/scala/org/knora/webapi/messages/util/BUILD.bazel b/webapi/src/test/scala/org/knora/webapi/messages/util/BUILD.bazel index e67464b4ae..9c08e5b5fd 100644 --- a/webapi/src/test/scala/org/knora/webapi/messages/util/BUILD.bazel +++ b/webapi/src/test/scala/org/knora/webapi/messages/util/BUILD.bazel @@ -58,63 +58,6 @@ scala_test( ] + BASE_TEST_DEPENDENCIES, ) -scala_test( - name = "JsonLDUtilSpec", - size = "small", - srcs = [ - "JsonLDUtilSpec.scala", - ], - data = [ - "//knora-ontologies", - "//test_data", - ], - jvm_flags = ["-Dconfig.resource=fuseki.conf"], - # unused_dependency_checker_mode = "warn", - deps = ALL_WEBAPI_MAIN_DEPENDENCIES + [ - "//webapi:main_library", - "//webapi:test_library", - "@maven//:org_eclipse_rdf4j_rdf4j_client" - ] + BASE_TEST_DEPENDENCIES_WITH_JSON_LD, -) - -scala_test( - name = "KnoraResponseV2Spec", - size = "small", - srcs = [ - "KnoraResponseV2Spec.scala", - ], - data = [ - "//knora-ontologies", - "//test_data", - ], - jvm_flags = ["-Dconfig.resource=fuseki.conf"], - # unused_dependency_checker_mode = "warn", - deps = ALL_WEBAPI_MAIN_DEPENDENCIES + [ - "//webapi:main_library", - "//webapi:test_library", - "@maven//:org_eclipse_rdf4j_rdf4j_client" - ] + BASE_TEST_DEPENDENCIES_WITH_JSON, -) - -scala_test( - name = "RdfFormatUtilSpec", - size = "small", - srcs = [ - "RdfFormatUtilSpec.scala", - ], - data = [ - "//knora-ontologies", - "//test_data", - ], - jvm_flags = ["-Dconfig.resource=fuseki.conf"], - # unused_dependency_checker_mode = "warn", - deps = ALL_WEBAPI_MAIN_DEPENDENCIES + [ - "//webapi:main_library", - "//webapi:test_library", - "@maven//:org_apache_jena_apache_jena_libs" - ] + BASE_TEST_DEPENDENCIES_WITH_JSON, -) - scala_test( name = "PermissionUtilADMSpec", size = "small", diff --git a/webapi/src/test/scala/org/knora/webapi/messages/util/ConstructResponseUtilV2Spec.scala b/webapi/src/test/scala/org/knora/webapi/messages/util/ConstructResponseUtilV2Spec.scala index 78da731d86..124dfffcab 100644 --- a/webapi/src/test/scala/org/knora/webapi/messages/util/ConstructResponseUtilV2Spec.scala +++ b/webapi/src/test/scala/org/knora/webapi/messages/util/ConstructResponseUtilV2Spec.scala @@ -27,6 +27,7 @@ import org.knora.webapi._ import org.knora.webapi.messages.StringFormatter import org.knora.webapi.messages.store.triplestoremessages.SparqlExtendedConstructResponse import org.knora.webapi.messages.util.ConstructResponseUtilV2 +import org.knora.webapi.messages.util.rdf.RdfFeatureFactory import org.knora.webapi.messages.v2.responder.resourcemessages.ReadResourcesSequenceV2 import org.knora.webapi.responders.v2.{ResourcesResponderV2SpecFullData, ResourcesResponseCheckerV2} import org.knora.webapi.sharedtestdata.SharedTestDataADM @@ -41,19 +42,18 @@ class ConstructResponseUtilV2Spec extends CoreSpec() with ImplicitSender { private implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance private implicit val timeout: Timeout = 10.seconds private val incunabulaUser = SharedTestDataADM.incunabulaProjectAdminUser - private val anythingAdminUser = SharedTestDataADM.anythingAdminUser; - private val anythingUser1 = SharedTestDataADM.anythingUser1; - private val anythingUser2 = SharedTestDataADM.anythingUser2; + private val anythingAdminUser = SharedTestDataADM.anythingAdminUser private val anonymousUser = SharedTestDataADM.anonymousUser private val resourcesResponderV2SpecFullData = new ResourcesResponderV2SpecFullData private val constructResponseUtilV2SpecFullData = new ConstructResponseUtilV2SpecFullData + private val rdfFormatUtil = RdfFeatureFactory.getRdfFormatUtil(defaultFeatureFactoryConfig) "ConstructResponseUtilV2" should { "convert a resource Turtle response into a resource" in { val resourceIri: IRI = "http://rdfh.ch/0803/c5058f3a" val turtleStr: String = FileUtil.readTextFile(new File("test_data/constructResponseUtilV2/Zeitglocklein.ttl")) - val resourceRequestResponse: SparqlExtendedConstructResponse = SparqlExtendedConstructResponse.parseTurtleResponse(turtleStr, log).get + val resourceRequestResponse: SparqlExtendedConstructResponse = SparqlExtendedConstructResponse.parseTurtleResponse(turtleStr, rdfFormatUtil, log).get val mainResourcesAndValueRdfData: ConstructResponseUtilV2.MainResourcesAndValueRdfData = ConstructResponseUtilV2.splitMainResourcesAndValueRdfData( constructQueryResults = resourceRequestResponse, requestingUser = incunabulaUser @@ -70,6 +70,7 @@ class ConstructResponseUtilV2Spec extends CoreSpec() with ImplicitSender { responderManager = responderManager, targetSchema = ApiV2Complex, settings = settings, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser ) @@ -84,7 +85,7 @@ class ConstructResponseUtilV2Spec extends CoreSpec() with ImplicitSender { "convert a resource Turtle response with hidden values into a resource with the anything admin user" in { val resourceIri: IRI = "http://rdfh.ch/0001/F8L7zPp7TI-4MGJQlCO4Zg" val turtleStr: String = FileUtil.readTextFile(new File("test_data/constructResponseUtilV2/visibleThingWithHiddenIntValues.ttl")) - val resourceRequestResponse: SparqlExtendedConstructResponse = SparqlExtendedConstructResponse.parseTurtleResponse(turtleStr, log).get + val resourceRequestResponse: SparqlExtendedConstructResponse = SparqlExtendedConstructResponse.parseTurtleResponse(turtleStr, rdfFormatUtil, log).get val mainResourcesAndValueRdfData: ConstructResponseUtilV2.MainResourcesAndValueRdfData = ConstructResponseUtilV2.splitMainResourcesAndValueRdfData( constructQueryResults = resourceRequestResponse, requestingUser = anythingAdminUser @@ -101,6 +102,7 @@ class ConstructResponseUtilV2Spec extends CoreSpec() with ImplicitSender { responderManager = responderManager, targetSchema = ApiV2Complex, settings = settings, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -115,7 +117,7 @@ class ConstructResponseUtilV2Spec extends CoreSpec() with ImplicitSender { "convert a resource Turtle response with hidden values into a resource with the incunabula user" in { val resourceIri: IRI = "http://rdfh.ch/0001/F8L7zPp7TI-4MGJQlCO4Zg" val turtleStr: String = FileUtil.readTextFile(new File("test_data/constructResponseUtilV2/visibleThingWithHiddenIntValues.ttl")) - val resourceRequestResponse: SparqlExtendedConstructResponse = SparqlExtendedConstructResponse.parseTurtleResponse(turtleStr, log).get + val resourceRequestResponse: SparqlExtendedConstructResponse = SparqlExtendedConstructResponse.parseTurtleResponse(turtleStr, rdfFormatUtil, log).get val mainResourcesAndValueRdfData: ConstructResponseUtilV2.MainResourcesAndValueRdfData = ConstructResponseUtilV2.splitMainResourcesAndValueRdfData( constructQueryResults = resourceRequestResponse, requestingUser = incunabulaUser @@ -132,6 +134,7 @@ class ConstructResponseUtilV2Spec extends CoreSpec() with ImplicitSender { responderManager = responderManager, targetSchema = ApiV2Complex, settings = settings, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser ) @@ -146,7 +149,7 @@ class ConstructResponseUtilV2Spec extends CoreSpec() with ImplicitSender { "convert a resource Turtle response with a hidden thing into a resource with the anything admin user" in { val resourceIri: IRI = "http://rdfh.ch/0001/0JhgKcqoRIeRRG6ownArSw" val turtleStr: String = FileUtil.readTextFile(new File("test_data/constructResponseUtilV2/thingWithOneHiddenThing.ttl")) - val resourceRequestResponse: SparqlExtendedConstructResponse = SparqlExtendedConstructResponse.parseTurtleResponse(turtleStr, log).get + val resourceRequestResponse: SparqlExtendedConstructResponse = SparqlExtendedConstructResponse.parseTurtleResponse(turtleStr, rdfFormatUtil, log).get val mainResourcesAndValueRdfData: ConstructResponseUtilV2.MainResourcesAndValueRdfData = ConstructResponseUtilV2.splitMainResourcesAndValueRdfData( constructQueryResults = resourceRequestResponse, requestingUser = anythingAdminUser @@ -163,6 +166,7 @@ class ConstructResponseUtilV2Spec extends CoreSpec() with ImplicitSender { responderManager = responderManager, targetSchema = ApiV2Complex, settings = settings, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -177,7 +181,7 @@ class ConstructResponseUtilV2Spec extends CoreSpec() with ImplicitSender { "convert a resource Turtle response with a hidden thing into a resource with an unknown user" in { val resourceIri: IRI = "http://rdfh.ch/0001/0JhgKcqoRIeRRG6ownArSw" val turtleStr: String = FileUtil.readTextFile(new File("test_data/constructResponseUtilV2/thingWithOneHiddenThing.ttl")) - val resourceRequestResponse: SparqlExtendedConstructResponse = SparqlExtendedConstructResponse.parseTurtleResponse(turtleStr, log).get + val resourceRequestResponse: SparqlExtendedConstructResponse = SparqlExtendedConstructResponse.parseTurtleResponse(turtleStr, rdfFormatUtil, log).get val mainResourcesAndValueRdfData: ConstructResponseUtilV2.MainResourcesAndValueRdfData = ConstructResponseUtilV2.splitMainResourcesAndValueRdfData( constructQueryResults = resourceRequestResponse, requestingUser = anonymousUser @@ -194,6 +198,7 @@ class ConstructResponseUtilV2Spec extends CoreSpec() with ImplicitSender { responderManager = responderManager, targetSchema = ApiV2Complex, settings = settings, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anonymousUser ) @@ -208,7 +213,7 @@ class ConstructResponseUtilV2Spec extends CoreSpec() with ImplicitSender { "convert a resource Turtle response with standoff into a resource with anything admin user" in { val resourceIri: IRI = "http://rdfh.ch/0001/a-thing-with-text-values" val turtleStr: String = FileUtil.readTextFile(new File("test_data/constructResponseUtilV2/thingWithStandoff.ttl")) - val resourceRequestResponse: SparqlExtendedConstructResponse = SparqlExtendedConstructResponse.parseTurtleResponse(turtleStr, log).get + val resourceRequestResponse: SparqlExtendedConstructResponse = SparqlExtendedConstructResponse.parseTurtleResponse(turtleStr, rdfFormatUtil, log).get val mainResourcesAndValueRdfData: ConstructResponseUtilV2.MainResourcesAndValueRdfData = ConstructResponseUtilV2.splitMainResourcesAndValueRdfData( constructQueryResults = resourceRequestResponse, requestingUser = anythingAdminUser @@ -225,6 +230,7 @@ class ConstructResponseUtilV2Spec extends CoreSpec() with ImplicitSender { responderManager = responderManager, targetSchema = ApiV2Complex, settings = settings, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -271,7 +277,7 @@ class ConstructResponseUtilV2Spec extends CoreSpec() with ImplicitSender { val resourceIris: Seq[IRI] = Seq("http://rdfh.ch/0803/76570a749901", "http://rdfh.ch/0803/773f258402") val turtleStr: String = FileUtil.readTextFile(new File("test_data/constructResponseUtilV2/mainQuery1.ttl")) - val resourceRequestResponse: SparqlExtendedConstructResponse = SparqlExtendedConstructResponse.parseTurtleResponse(turtleStr, log).get + val resourceRequestResponse: SparqlExtendedConstructResponse = SparqlExtendedConstructResponse.parseTurtleResponse(turtleStr, rdfFormatUtil, log).get val mainResourcesAndValueRdfData: ConstructResponseUtilV2.MainResourcesAndValueRdfData = ConstructResponseUtilV2.splitMainResourcesAndValueRdfData( constructQueryResults = resourceRequestResponse, requestingUser = incunabulaUser @@ -288,6 +294,7 @@ class ConstructResponseUtilV2Spec extends CoreSpec() with ImplicitSender { responderManager = responderManager, targetSchema = ApiV2Complex, settings = settings, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser ) @@ -335,7 +342,7 @@ class ConstructResponseUtilV2Spec extends CoreSpec() with ImplicitSender { val resourceIris: Seq[IRI] = Seq("http://rdfh.ch/0803/c5058f3a", "http://rdfh.ch/0803/ff17e5ef9601") val turtleStr: String = FileUtil.readTextFile(new File("test_data/constructResponseUtilV2/mainQuery2.ttl")) - val resourceRequestResponse: SparqlExtendedConstructResponse = SparqlExtendedConstructResponse.parseTurtleResponse(turtleStr, log).get + val resourceRequestResponse: SparqlExtendedConstructResponse = SparqlExtendedConstructResponse.parseTurtleResponse(turtleStr, rdfFormatUtil, log).get val mainResourcesAndValueRdfData: ConstructResponseUtilV2.MainResourcesAndValueRdfData = ConstructResponseUtilV2.splitMainResourcesAndValueRdfData( constructQueryResults = resourceRequestResponse, requestingUser = incunabulaUser @@ -352,6 +359,7 @@ class ConstructResponseUtilV2Spec extends CoreSpec() with ImplicitSender { responderManager = responderManager, targetSchema = ApiV2Complex, settings = settings, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser ) diff --git a/webapi/src/test/scala/org/knora/webapi/messages/util/RdfFormatUtilSpec.scala b/webapi/src/test/scala/org/knora/webapi/messages/util/RdfFormatUtilSpec.scala deleted file mode 100644 index 9e21fbe61d..0000000000 --- a/webapi/src/test/scala/org/knora/webapi/messages/util/RdfFormatUtilSpec.scala +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright © 2015-2019 the contributors (see Contributors.md). - * - * This file is part of Knora. - * - * Knora is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Knora is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public - * License along with Knora. If not, see . - */ - -package org.knora.webapi.util - -import java.io.File - -import org.apache.jena.graph._ -import org.knora.webapi.RdfMediaTypes -import org.knora.webapi.messages.util.RdfFormatUtil -import org.knora.webapi.messages.util.{JsonLDConstants, JsonLDDocument} -import org.knora.webapi.messages.{OntologyConstants, StringFormatter} -import org.scalatest.matchers.should.Matchers -import org.scalatest.wordspec.AnyWordSpecLike - -import scala.collection.JavaConverters._ - -/** - * Tests [[RdfFormatUtil]]. - */ -class RdfFormatUtilSpec extends AnyWordSpecLike with Matchers { - - StringFormatter.initForTest() - - private def checkGraphForRdfTypeBook(graph: Graph): Unit = { - val statements: Seq[Triple] = graph.find( - NodeFactory.createURI("http://rdfh.ch/0803/2a6221216701"), - NodeFactory.createURI(OntologyConstants.Rdf.Type), - Node.ANY - ).asScala.toSeq - - assert(statements.size == 1) - assert(statements.head.getObject == NodeFactory.createURI("http://0.0.0.0:3333/ontology/0803/incunabula/v2#book")) - } - - private def checkJsonLDDocumentForRdfTypeBook(jsonLDDocument: JsonLDDocument): Unit = { - assert(jsonLDDocument.requireString(JsonLDConstants.TYPE) == "http://0.0.0.0:3333/ontology/0803/incunabula/v2#book") - } - - "RdfFormatUtil" should { - "parse RDF in Turtle format, producing a Jena Graph" in { - val inputTurtle: String = FileUtil.readTextFile(new File("test_data/resourcesR2RV2/BookReiseInsHeiligeLand.ttl")) - val graph: Graph = RdfFormatUtil.parseToJenaGraph(rdfStr = inputTurtle, mediaType = RdfMediaTypes.`text/turtle`) - checkGraphForRdfTypeBook(graph) - } - - "parse RDF in JSON-LD format, producing a Jena Graph" in { - val inputTurtle: String = FileUtil.readTextFile(new File("test_data/resourcesR2RV2/BookReiseInsHeiligeLand.jsonld")) - val graph: Graph = RdfFormatUtil.parseToJenaGraph(rdfStr = inputTurtle, mediaType = RdfMediaTypes.`application/ld+json`) - checkGraphForRdfTypeBook(graph) - } - - "parse RDF in Turtle format, producing a JsonLDDocument" in { - val inputTurtle: String = FileUtil.readTextFile(new File("test_data/resourcesR2RV2/BookReiseInsHeiligeLand.ttl")) - val jsonLDDocument: JsonLDDocument = RdfFormatUtil.parseToJsonLDDocument(rdfStr = inputTurtle, mediaType = RdfMediaTypes.`text/turtle`) - checkJsonLDDocumentForRdfTypeBook(jsonLDDocument) - } - - "parse RDF in JSON-LD format, producing a JsonLDDocument" in { - val inputTurtle: String = FileUtil.readTextFile(new File("test_data/resourcesR2RV2/BookReiseInsHeiligeLand.jsonld")) - val jsonLDDocument: JsonLDDocument = RdfFormatUtil.parseToJsonLDDocument(rdfStr = inputTurtle, mediaType = RdfMediaTypes.`application/ld+json`) - checkJsonLDDocumentForRdfTypeBook(jsonLDDocument) - } - } -} diff --git a/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/BUILD.bazel b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/BUILD.bazel new file mode 100644 index 0000000000..177bcd570c --- /dev/null +++ b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/BUILD.bazel @@ -0,0 +1,14 @@ +package(default_visibility = ["//visibility:public"]) + +load("@io_bazel_rules_scala//scala:scala.bzl", "scala_test") +load("//third_party:dependencies.bzl", "ALL_WEBAPI_MAIN_DEPENDENCIES", "BASE_TEST_DEPENDENCIES", "BASE_TEST_DEPENDENCIES_WITH_JSON", "BASE_TEST_DEPENDENCIES_WITH_JSON_LD") + +filegroup( + name = "srcs", + srcs = [ + "RdfModelSpec.scala", + "RdfFormatUtilSpec.scala", + "JsonLDUtilSpec.scala", + "KnoraResponseV2Spec.scala", + ], +) diff --git a/webapi/src/test/scala/org/knora/webapi/messages/util/JsonLDUtilSpec.scala b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/JsonLDUtilSpec.scala similarity index 64% rename from webapi/src/test/scala/org/knora/webapi/messages/util/JsonLDUtilSpec.scala rename to webapi/src/test/scala/org/knora/webapi/messages/util/rdf/JsonLDUtilSpec.scala index 53881f5183..d6dd59fbc0 100644 --- a/webapi/src/test/scala/org/knora/webapi/messages/util/JsonLDUtilSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/JsonLDUtilSpec.scala @@ -17,28 +17,34 @@ * License along with Knora. If not, see . */ -package org.knora.webapi.util +package org.knora.webapi.util.rdf -import java.io.{File, StringReader} +import java.io.File -import org.eclipse.rdf4j.model.Model -import org.eclipse.rdf4j.rio.{RDFFormat, Rio} +import org.knora.webapi.CoreSpec +import org.knora.webapi.feature._ import org.knora.webapi.messages.StringFormatter -import org.knora.webapi.messages.util.{JsonLDDocument, JsonLDUtil} -import org.scalatest.matchers.should.Matchers -import org.scalatest.wordspec.AnyWordSpecLike +import org.knora.webapi.messages.util.rdf._ +import org.knora.webapi.util.FileUtil import spray.json.{JsValue, JsonParser} /** * Tests [[JsonLDUtil]]. */ -class JsonLDUtilSpec extends AnyWordSpecLike with Matchers { +abstract class JsonLDUtilSpec(featureToggle: FeatureToggle) extends CoreSpec { + private val featureFactoryConfig: FeatureFactoryConfig = new TestFeatureFactoryConfig( + testToggles = Set(featureToggle), + parent = new KnoraSettingsFeatureFactoryConfig(settings) + ) + + private val rdfFormatUtil: RdfFormatUtil = RdfFeatureFactory.getRdfFormatUtil(featureFactoryConfig) + private val rdfModelFactory: RdfModelFactory = RdfFeatureFactory.getRdfModelFactory(featureFactoryConfig) StringFormatter.initForTest() - "The JSON-LD utility" should { + "The JSON-LD tool" should { "parse JSON-LD text, compact it with an empty context, convert the result to a JsonLDDocument, and convert that back to text" in { - val inputStr = + val ontologyJsonLDInputStr = """ |{ | "knora-api:hasOntologies" : { @@ -80,7 +86,7 @@ class JsonLDUtilSpec extends AnyWordSpecLike with Matchers { |} """.stripMargin - val expectedOutputStr = + val ontologyCompactedJsonLDOutputStr = """ |{ | "http://api.knora.org/ontology/knora-api/v2#hasOntologies" : { @@ -114,10 +120,10 @@ class JsonLDUtilSpec extends AnyWordSpecLike with Matchers { |} """.stripMargin - val compactedJsonLDDoc: JsonLDDocument = JsonLDUtil.parseJsonLD(inputStr) + val compactedJsonLDDoc: JsonLDDocument = JsonLDUtil.parseJsonLD(ontologyJsonLDInputStr) val formattedCompactedDoc = compactedJsonLDDoc.toPrettyString val receivedOutputAsJsValue: JsValue = JsonParser(formattedCompactedDoc) - val expectedOutputAsJsValue: JsValue = JsonParser(expectedOutputStr) + val expectedOutputAsJsValue: JsValue = JsonParser(ontologyCompactedJsonLDOutputStr) receivedOutputAsJsValue should ===(expectedOutputAsJsValue) } @@ -129,13 +135,13 @@ class JsonLDUtilSpec extends AnyWordSpecLike with Matchers { val jsonLDDocument: JsonLDDocument = JsonLDUtil.parseJsonLD(inputJsonLD) // Convert that document to an RDF4J Model. - val outputModel: Model = jsonLDDocument.toRDF4JModel + val outputModel: RdfModel = jsonLDDocument.toRdfModel(rdfModelFactory) // Read an isomorphic Turtle file. - val expectedTurtle = FileUtil.readTextFile(new File("test_data/ontologyR2RV2/anythingOntologyWithValueObjects.ttl")) + val expectedTurtle: String = FileUtil.readTextFile(new File("test_data/ontologyR2RV2/anythingOntologyWithValueObjects.ttl")) // Parse the Turtle to an RDF4J Model. - val expectedModel = Rio.parse(new StringReader(expectedTurtle), "", RDFFormat.TURTLE, null) + val expectedModel: RdfModel = rdfFormatUtil.parseToRdfModel(rdfStr = expectedTurtle, rdfFormat = Turtle) // Compare the parsed Turtle with the model generated by the JsonLDDocument. outputModel should ===(expectedModel) @@ -146,13 +152,13 @@ class JsonLDUtilSpec extends AnyWordSpecLike with Matchers { val turtle = FileUtil.readTextFile(new File("test_data/ontologyR2RV2/anythingOntologyWithValueObjects.ttl")) // Parse it to an RDF4J Model. - val inputModel = Rio.parse(new StringReader(turtle), "", RDFFormat.TURTLE, null) + val inputModel: RdfModel = rdfFormatUtil.parseToRdfModel(rdfStr = turtle, rdfFormat = Turtle) // Convert the model to a JsonLDDocument. - val outputJsonLD: JsonLDDocument = JsonLDUtil.fromRDF4JModel(inputModel) + val outputJsonLD: JsonLDDocument = JsonLDUtil.fromRdfModel(inputModel) // Convert the JsonLDDocument back to an RDF4J Model. - val jsonLDOutputModel: Model = outputJsonLD.toRDF4JModel + val jsonLDOutputModel: RdfModel = outputJsonLD.toRdfModel(rdfModelFactory) // Compare the generated model with the original one. jsonLDOutputModel should ===(inputModel) @@ -161,7 +167,7 @@ class JsonLDUtilSpec extends AnyWordSpecLike with Matchers { val expectedJsonLD = FileUtil.readTextFile(new File("test_data/ontologyR2RV2/anythingOntologyWithValueObjects.jsonld")) // Parse it to an RDF4J Model. - val jsonLDExpectedModel: Model = Rio.parse(new StringReader(expectedJsonLD), "", RDFFormat.JSONLD, null) + val jsonLDExpectedModel: RdfModel = rdfFormatUtil.parseToRdfModel(rdfStr = expectedJsonLD, rdfFormat = JsonLD) // Compare that with the model generated by the JsonLDDocument. jsonLDOutputModel should ===(jsonLDExpectedModel) @@ -175,10 +181,10 @@ class JsonLDUtilSpec extends AnyWordSpecLike with Matchers { val jsonLDDocument: JsonLDDocument = JsonLDUtil.parseJsonLD(inputJsonLD) // Convert the document to an RDF4J Model. - val outputModel: Model = jsonLDDocument.toRDF4JModel + val outputModel: RdfModel = jsonLDDocument.toRdfModel(rdfModelFactory) // Convert the model back to a JsonLDDocument. - val outputModelAsJsonLDDocument: JsonLDDocument = JsonLDUtil.fromRDF4JModel(outputModel) + val outputModelAsJsonLDDocument: JsonLDDocument = JsonLDUtil.fromRdfModel(outputModel) // Compare that with the original JsonLDDocument. outputModelAsJsonLDDocument should ===(jsonLDDocument) @@ -187,7 +193,7 @@ class JsonLDUtilSpec extends AnyWordSpecLike with Matchers { val expectedTurtle = FileUtil.readTextFile(new File("test_data/resourcesR2RV2/BookReiseInsHeiligeLand.ttl")) // Parse it to an RDF4J Model. - val expectedModel = Rio.parse(new StringReader(expectedTurtle), "", RDFFormat.TURTLE, null) + val expectedModel: RdfModel = rdfFormatUtil.parseToRdfModel(rdfStr = expectedTurtle, rdfFormat = Turtle) // Compare that with the model generated by the JsonLDDocument. outputModel should ===(expectedModel) @@ -198,13 +204,13 @@ class JsonLDUtilSpec extends AnyWordSpecLike with Matchers { val turtle = FileUtil.readTextFile(new File("test_data/resourcesR2RV2/BookReiseInsHeiligeLand.ttl")) // Parse it to an RDF4J Model. - val inputModel = Rio.parse(new StringReader(turtle), "", RDFFormat.TURTLE, null) + val inputModel: RdfModel = rdfFormatUtil.parseToRdfModel(rdfStr = turtle, rdfFormat = Turtle) // Convert the model to a JsonLDDocument. - val outputJsonLD: JsonLDDocument = JsonLDUtil.fromRDF4JModel(inputModel) + val outputJsonLD: JsonLDDocument = JsonLDUtil.fromRdfModel(inputModel) // Convert the JsonLDDocument back to an RDF4J Model. - val jsonLDOutputModel: Model = outputJsonLD.toRDF4JModel + val jsonLDOutputModel: RdfModel = outputJsonLD.toRdfModel(rdfModelFactory) // Compare the generated model with the original one. jsonLDOutputModel should ===(inputModel) @@ -217,10 +223,63 @@ class JsonLDUtilSpec extends AnyWordSpecLike with Matchers { expectedJsonLDDocument.body should ===(outputJsonLD.body) // Parse the same file to an RDF4J Model. - val jsonLDExpectedModel: Model = Rio.parse(new StringReader(expectedJsonLD), "", RDFFormat.JSONLD, null) + val jsonLDExpectedModel: RdfModel = rdfFormatUtil.parseToRdfModel(rdfStr = expectedJsonLD, rdfFormat = JsonLD) // Compare that with the model generated by the JsonLDDocument. jsonLDOutputModel should ===(jsonLDExpectedModel) } + + "correctly convert an RDF model to JSON-LD if it contains a circular reference" in { + // A Turtle document with a circular reference. + val turtle = + """@prefix foo: . + |@prefix rdfs: . + | + | a foo:Foo; + | rdfs:label "foo 1"; + | foo:hasOtherFoo . + | + | a foo:Foo; + | rdfs:label "foo 2"; + | foo:hasOtherFoo . + |""".stripMargin + + // Parse it to an RDF4J Model. + val inputModel: RdfModel = rdfFormatUtil.parseToRdfModel(rdfStr = turtle, rdfFormat = Turtle) + + // Convert the model to a JsonLDDocument. + val outputJsonLD: JsonLDDocument = JsonLDUtil.fromRdfModel(inputModel) + + // The output could be nested in two different ways: + + val expectedWithFoo1AtTopLevel = JsonLDObject(value = Map( + "@id" -> JsonLDString(value = "http://rdfh.ch/foo1"), + "@type" -> JsonLDString(value = "http://example.org/foo#Foo"), + "http://www.w3.org/2000/01/rdf-schema#label" -> JsonLDString(value = "foo 1"), + "http://example.org/foo#hasOtherFoo" -> JsonLDObject(value = Map( + "@id" -> JsonLDString(value = "http://rdfh.ch/foo2"), + "@type" -> JsonLDString(value = "http://example.org/foo#Foo"), + "http://www.w3.org/2000/01/rdf-schema#label" -> JsonLDString(value = "foo 2"), + "http://example.org/foo#hasOtherFoo" -> JsonLDObject(value = Map("@id" -> JsonLDString(value = "http://rdfh.ch/foo1"))), + )), + )) + + val expectedWithFoo2AtTopLevel = JsonLDObject(value = Map( + "@id" -> JsonLDString(value = "http://rdfh.ch/foo2"), + "@type" -> JsonLDString(value = "http://example.org/foo#Foo"), + "http://www.w3.org/2000/01/rdf-schema#label" -> JsonLDString(value = "foo 2"), + "http://example.org/foo#hasOtherFoo" -> JsonLDObject(value = Map( + "@id" -> JsonLDString(value = "http://rdfh.ch/foo1"), + "@type" -> JsonLDString(value = "http://example.org/foo#Foo"), + "http://www.w3.org/2000/01/rdf-schema#label" -> JsonLDString(value = "foo 1"), + "http://example.org/foo#hasOtherFoo" -> JsonLDObject(value = Map("@id" -> JsonLDString(value = "http://rdfh.ch/foo2"))) + )) + )) + + assert( + outputJsonLD.body == expectedWithFoo1AtTopLevel || + outputJsonLD.body == expectedWithFoo2AtTopLevel + ) + } } } diff --git a/webapi/src/test/scala/org/knora/webapi/messages/util/KnoraResponseV2Spec.scala b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/KnoraResponseV2Spec.scala similarity index 73% rename from webapi/src/test/scala/org/knora/webapi/messages/util/KnoraResponseV2Spec.scala rename to webapi/src/test/scala/org/knora/webapi/messages/util/rdf/KnoraResponseV2Spec.scala index e4ccf54099..9b95b016b5 100644 --- a/webapi/src/test/scala/org/knora/webapi/messages/util/KnoraResponseV2Spec.scala +++ b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/KnoraResponseV2Spec.scala @@ -17,21 +17,27 @@ * License along with Knora. If not, see . */ -package org.knora.webapi.util +package org.knora.webapi.util.rdf import java.io.{File, StringReader} -import org.eclipse.rdf4j.model.Model -import org.eclipse.rdf4j.rio.{RDFFormat, Rio} -import org.knora.webapi.messages.util.{JsonLDDocument, JsonLDUtil} +import org.knora.webapi._ +import org.knora.webapi.feature._ +import org.knora.webapi.messages.util.rdf._ import org.knora.webapi.messages.v2.responder.{KnoraJsonLDResponseV2, KnoraTurtleResponseV2} import org.knora.webapi.settings.KnoraSettingsImpl -import org.knora.webapi._ +import org.knora.webapi.util.FileUtil /** * Tests the formatting of Knora API v2 responses. */ -class KnoraResponseV2Spec extends CoreSpec { +abstract class KnoraResponseV2Spec(featureToggle: FeatureToggle) extends CoreSpec { + private val featureFactoryConfig: FeatureFactoryConfig = new TestFeatureFactoryConfig( + testToggles = Set(featureToggle), + parent = new KnoraSettingsFeatureFactoryConfig(settings) + ) + + private val rdfFormatUtil: RdfFormatUtil = RdfFeatureFactory.getRdfFormatUtil(featureFactoryConfig) /** * A test implementation of [[KnoraTurtleResponseV2]]. @@ -59,18 +65,19 @@ class KnoraResponseV2Spec extends CoreSpec { // Ask the KnoraTurtleResponseV2 to convert the content to JSON-LD. val jsonLD: String = turtleTestMessage.format( - mediaType = RdfMediaTypes.`application/ld+json`, + rdfFormat = JsonLD, targetSchema = InternalSchema, schemaOptions = Set.empty, + featureFactoryConfig = featureFactoryConfig, settings = settings ) // Parse the JSON-LD to a JsonLDDocument. - val parsedJsonLD = JsonLDUtil.parseJsonLD(jsonLD) + val parsedJsonLD: JsonLDDocument = JsonLDUtil.parseJsonLD(jsonLD) // Read an isomorphic JSON-LD file and parse it to a JsonLDDocument. - val expectedJsonLD = FileUtil.readTextFile(new File("test_data/resourcesR2RV2/BookReiseInsHeiligeLand.jsonld")) - val parsedExpectedJsonLD = JsonLDUtil.parseJsonLD(expectedJsonLD) + val expectedJsonLD: String = FileUtil.readTextFile(new File("test_data/resourcesR2RV2/BookReiseInsHeiligeLand.jsonld")) + val parsedExpectedJsonLD: JsonLDDocument = JsonLDUtil.parseJsonLD(expectedJsonLD) // Compare the two documents. parsedJsonLD.body should ===(parsedExpectedJsonLD.body) @@ -85,18 +92,19 @@ class KnoraResponseV2Spec extends CoreSpec { // Ask the KnoraJsonLDResponseV2 to convert the content to Turtle. val turtle: String = jsonLDTestMessage.format( - mediaType = RdfMediaTypes.`text/turtle`, + rdfFormat = Turtle, targetSchema = ApiV2Complex, schemaOptions = Set.empty, + featureFactoryConfig = featureFactoryConfig, settings = settings ) // Parse the Turtle to an RDF4J Model. - val parsedTurtle = Rio.parse(new StringReader(turtle), "", RDFFormat.TURTLE, null) + val parsedTurtle: RdfModel = rdfFormatUtil.parseToRdfModel(rdfStr = turtle, rdfFormat = Turtle) // Read an isomorphic Turtle file and parse it to an RDF4J Model. val expectedTurtle: String = FileUtil.readTextFile(new File("test_data/resourcesR2RV2/BookReiseInsHeiligeLand.ttl")) - val parsedExpectedTurtle: Model = Rio.parse(new StringReader(expectedTurtle), "", RDFFormat.TURTLE, null) + val parsedExpectedTurtle: RdfModel = rdfFormatUtil.parseToRdfModel(rdfStr = expectedTurtle, rdfFormat = Turtle) // Compare the two models. parsedTurtle should ===(parsedExpectedTurtle) diff --git a/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/RdfFormatUtilSpec.scala b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/RdfFormatUtilSpec.scala new file mode 100644 index 0000000000..60bd345544 --- /dev/null +++ b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/RdfFormatUtilSpec.scala @@ -0,0 +1,149 @@ +/* + * Copyright © 2015-2019 the contributors (see Contributors.md). + * + * This file is part of Knora. + * + * Knora is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Knora is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with Knora. If not, see . + */ + +package org.knora.webapi.util.rdf + +import java.io.File + +import org.knora.webapi.{CoreSpec, IRI} +import org.knora.webapi.feature.{FeatureFactoryConfig, FeatureToggle, KnoraSettingsFeatureFactoryConfig, TestFeatureFactoryConfig} +import org.knora.webapi.messages.util.rdf._ +import org.knora.webapi.messages.{OntologyConstants, StringFormatter} +import org.knora.webapi.util.FileUtil + +/** + * Tests implementations of [[RdfFormatUtil]]. + */ +abstract class RdfFormatUtilSpec(featureToggle: FeatureToggle) extends CoreSpec { + private val featureFactoryConfig: FeatureFactoryConfig = new TestFeatureFactoryConfig( + testToggles = Set(featureToggle), + parent = new KnoraSettingsFeatureFactoryConfig(settings) + ) + + private val rdfFormatUtil: RdfFormatUtil = RdfFeatureFactory.getRdfFormatUtil(featureFactoryConfig) + private val rdfNodeFactory: RdfNodeFactory = RdfFeatureFactory.getRdfNodeFactory(featureFactoryConfig) + private val rdfModelFactory: RdfModelFactory = RdfFeatureFactory.getRdfModelFactory(featureFactoryConfig) + + StringFormatter.initForTest() + + private def checkModelForRdfTypeBook(rdfModel: RdfModel): Unit = { + val statements: Set[Statement] = rdfModel.find( + subj = Some(rdfNodeFactory.makeIriNode("http://rdfh.ch/0803/2a6221216701")), + pred = Some(rdfNodeFactory.makeIriNode(OntologyConstants.Rdf.Type)), + obj = None + ) + + assert(statements.size == 1) + assert(statements.head.obj == rdfNodeFactory.makeIriNode("http://0.0.0.0:3333/ontology/0803/incunabula/v2#book")) + } + + private def checkJsonLDDocumentForRdfTypeBook(jsonLDDocument: JsonLDDocument): Unit = { + assert(jsonLDDocument.requireString(JsonLDKeywords.TYPE) == "http://0.0.0.0:3333/ontology/0803/incunabula/v2#book") + } + + "RdfFormatUtil" should { + "parse RDF in Turtle format, producing an RdfModel, then format it as Turtle again" in { + val inputTurtle: String = FileUtil.readTextFile(new File("test_data/resourcesR2RV2/BookReiseInsHeiligeLand.ttl")) + val inputModel: RdfModel = rdfFormatUtil.parseToRdfModel(rdfStr = inputTurtle, rdfFormat = Turtle) + checkModelForRdfTypeBook(inputModel) + + val outputTurtle: String = rdfFormatUtil.format(rdfModel = inputModel, rdfFormat = Turtle) + val outputModel: RdfModel = rdfFormatUtil.parseToRdfModel(rdfStr = outputTurtle, rdfFormat = Turtle) + checkModelForRdfTypeBook(outputModel) + assert(outputModel == inputModel) + } + + "parse RDF in JSON-LD format, producing an RdfModel, then format it as JSON-LD again" in { + val inputTurtle: String = FileUtil.readTextFile(new File("test_data/resourcesR2RV2/BookReiseInsHeiligeLand.jsonld")) + val inputModel: RdfModel = rdfFormatUtil.parseToRdfModel(rdfStr = inputTurtle, rdfFormat = JsonLD) + checkModelForRdfTypeBook(inputModel) + + val outputTurtle: String = rdfFormatUtil.format(rdfModel = inputModel, rdfFormat = JsonLD) + val outputModel: RdfModel = rdfFormatUtil.parseToRdfModel(rdfStr = outputTurtle, rdfFormat = JsonLD) + checkModelForRdfTypeBook(outputModel) + assert(outputModel == inputModel) + } + + "parse RDF in Turtle format, producing a JsonLDDocument, then format it as Turtle again" in { + val inputTurtle: String = FileUtil.readTextFile(new File("test_data/resourcesR2RV2/BookReiseInsHeiligeLand.ttl")) + val inputModel: RdfModel = rdfFormatUtil.parseToRdfModel(rdfStr = inputTurtle, rdfFormat = Turtle) + val inputJsonLDDocument: JsonLDDocument = rdfFormatUtil.parseToJsonLDDocument(rdfStr = inputTurtle, rdfFormat = Turtle) + checkJsonLDDocumentForRdfTypeBook(inputJsonLDDocument) + + val jsonLDOutputModel: RdfModel = inputJsonLDDocument.toRdfModel(rdfModelFactory) + checkModelForRdfTypeBook(jsonLDOutputModel) + assert(jsonLDOutputModel == inputModel) + + val outputTurtle: String = rdfFormatUtil.format(rdfModel = jsonLDOutputModel, rdfFormat = Turtle) + val turtleOutputModel: RdfModel = rdfFormatUtil.parseToRdfModel(rdfStr = outputTurtle, rdfFormat = Turtle) + checkModelForRdfTypeBook(turtleOutputModel) + assert(turtleOutputModel == inputModel) + } + + "parse RDF in RDF/XML format, producing a JsonLDDocument, then format it as RDF/XML again" in { + val inputRdfXml: String = FileUtil.readTextFile(new File("test_data/resourcesR2RV2/BookReiseInsHeiligeLand.rdf")) + val inputModel: RdfModel = rdfFormatUtil.parseToRdfModel(rdfStr = inputRdfXml, rdfFormat = RdfXml) + val inputJsonLDDocument: JsonLDDocument = rdfFormatUtil.parseToJsonLDDocument(rdfStr = inputRdfXml, rdfFormat = RdfXml) + checkJsonLDDocumentForRdfTypeBook(inputJsonLDDocument) + + val jsonLDOutputModel: RdfModel = inputJsonLDDocument.toRdfModel(rdfModelFactory) + checkModelForRdfTypeBook(jsonLDOutputModel) + assert(jsonLDOutputModel == inputModel) + + val outputRdfXml: String = rdfFormatUtil.format(rdfModel = jsonLDOutputModel, rdfFormat = RdfXml) + val rdfXmlOutputModel: RdfModel = rdfFormatUtil.parseToRdfModel(rdfStr = outputRdfXml, rdfFormat = RdfXml) + checkModelForRdfTypeBook(rdfXmlOutputModel) + assert(rdfXmlOutputModel == inputModel) + } + + "parse RDF in JSON-LD format, producing a JsonLDDocument, then format it as JSON-LD again" in { + val inputTurtle: String = FileUtil.readTextFile(new File("test_data/resourcesR2RV2/BookReiseInsHeiligeLand.jsonld")) + val inputJsonLDDocument: JsonLDDocument = rdfFormatUtil.parseToJsonLDDocument(rdfStr = inputTurtle, rdfFormat = JsonLD) + checkJsonLDDocumentForRdfTypeBook(inputJsonLDDocument) + + val outputJsonLD: String = inputJsonLDDocument.toPrettyString + val outputJsonLDDocument: JsonLDDocument = rdfFormatUtil.parseToJsonLDDocument(rdfStr = outputJsonLD, rdfFormat = JsonLD) + checkJsonLDDocumentForRdfTypeBook(outputJsonLDDocument) + assert(inputJsonLDDocument == outputJsonLDDocument) + } + + "use prefixes and custom datatypes" in { + val inputJsonLD: String = FileUtil.readTextFile(new File("test_data/resourcesR2RV2/BookReiseInsHeiligeLandSimple.jsonld")) + val inputJsonLDDocument: JsonLDDocument = JsonLDUtil.parseJsonLD(inputJsonLD) + val outputModel: RdfModel = inputJsonLDDocument.toRdfModel(rdfModelFactory) + + // Add namespaces, which were removed by compacting the JSON-LD document when parsing it. + + val namespaces: Map[String, IRI] = Map( + "incunabula" -> "http://0.0.0.0:3333/ontology/0803/incunabula/simple/v2#", + "knora-api" -> "http://api.knora.org/ontology/knora-api/simple/v2#", + "rdf" -> "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + "rdfs" -> "http://www.w3.org/2000/01/rdf-schema#", + "xsd" -> "http://www.w3.org/2001/XMLSchema#" + ) + + for ((prefix, namespace) <- namespaces) { + outputModel.setNamespace(prefix, namespace) + } + + val outputTurtle: String = rdfFormatUtil.format(rdfModel = outputModel, rdfFormat = Turtle) + assert(outputTurtle.contains("\"JULIAN:1481 CE\"^^knora-api:Date")) + } + } +} diff --git a/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/RdfModelSpec.scala b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/RdfModelSpec.scala new file mode 100644 index 0000000000..c667a8d8a2 --- /dev/null +++ b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/RdfModelSpec.scala @@ -0,0 +1,217 @@ +/* + * Copyright © 2015-2019 the contributors (see Contributors.md). + * + * This file is part of Knora. + * + * Knora is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Knora is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with Knora. If not, see . + */ + +package org.knora.webapi.util.rdf + +import org.knora.webapi.exceptions.AssertionException +import org.knora.webapi.feature._ +import org.knora.webapi.messages.OntologyConstants +import org.knora.webapi.{CoreSpec, IRI} +import org.knora.webapi.messages.util.rdf._ + +/** + * Tests implementations of [[RdfModel]]. + * + * @param featureToggle a feature toggle specifying which implementation of [[RdfModel]] should + * be used for the test. + */ +abstract class RdfModelSpec(featureToggle: FeatureToggle) extends CoreSpec { + private val featureFactoryConfig: FeatureFactoryConfig = new TestFeatureFactoryConfig( + testToggles = Set(featureToggle), + parent = new KnoraSettingsFeatureFactoryConfig(settings) + ) + + private val model: RdfModel = RdfFeatureFactory.getRdfModelFactory(featureFactoryConfig).makeEmptyModel + private val nodeFactory: RdfNodeFactory = RdfFeatureFactory.getRdfNodeFactory(featureFactoryConfig) + + /** + * Adds a statement, then searches for it by subject and predicate. + * + * @param subj the subject. + * @param pred the predicate. + * @param obj the object. + * @param context the context. + */ + private def addAndFindBySubjAndPred(subj: RdfResource, pred: IriNode, obj: RdfNode, context: Option[IRI] = None): Unit = { + val statement: Statement = nodeFactory.makeStatement(subj = subj, pred = pred, obj = obj) + model.addStatement(statement) + assert(model.find(subj = Some(subj), pred = Some(pred), obj = None) == Set(statement)) + } + + "An RdfModel" should { + "add a triple with a datatype literal object, without first creating a Statement" in { + val subj: IriNode = nodeFactory.makeIriNode("http://example.org/1") + val pred: IriNode = nodeFactory.makeIriNode("http://example.org/int_prop") + val obj: DatatypeLiteral = nodeFactory.makeDatatypeLiteral(value = "5", datatype = OntologyConstants.Xsd.Integer) + + model.add(subj = subj, pred = pred, obj = obj) + val expectedStatement: Statement = nodeFactory.makeStatement(subj = subj, pred = pred, obj = obj) + assert(model.find(subj = Some(subj), pred = Some(pred), obj = None) == Set(expectedStatement)) + } + + "add a triple with a datatype literal object" in { + addAndFindBySubjAndPred( + subj = nodeFactory.makeIriNode("http://example.org/2"), + pred = nodeFactory.makeIriNode("http://example.org/decimal_prop"), + obj = nodeFactory.makeDatatypeLiteral(value = "123.45", datatype = OntologyConstants.Xsd.Decimal) + ) + } + + "add a triple with an IRI object" in { + addAndFindBySubjAndPred( + subj = nodeFactory.makeIriNode("http://example.org/3"), + pred = nodeFactory.makeIriNode("http://example.org/object_prop"), + obj = nodeFactory.makeIriNode("http://example.org/1") + ) + } + + "add a blank node" in { + addAndFindBySubjAndPred( + subj = nodeFactory.makeBlankNodeWithID("bnode_1"), + pred = nodeFactory.makeIriNode("http://example.org/boolean_prop"), + obj = nodeFactory.makeDatatypeLiteral(value = "true", datatype = OntologyConstants.Xsd.Boolean) + ) + } + + "add a triple with a blank node object" in { + addAndFindBySubjAndPred( + subj = nodeFactory.makeIriNode("http://example.org/4"), + pred = nodeFactory.makeIriNode("http://example.org/object_prop"), + obj = nodeFactory.makeBlankNodeWithID("bnode_1") + ) + } + + "remove a triple" in { + val subj: IriNode = nodeFactory.makeIriNode("http://example.org/1") + model.remove(subj = Some(subj), pred = None, obj = None) + assert(model.find(subj = Some(subj), pred = None, obj = None).isEmpty) + } + + "add and find several triples with the same subject" in { + val subj: IriNode = nodeFactory.makeIriNode("http://example.org/5") + + val booleanStatement: Statement = nodeFactory.makeStatement( + subj = subj, + pred = nodeFactory.makeIriNode("http://example.org/boolean_prop"), + obj = nodeFactory.makeDatatypeLiteral(value = "false", datatype = OntologyConstants.Xsd.Boolean) + ) + + val stringStatement: Statement = nodeFactory.makeStatement( + subj = subj, + pred = nodeFactory.makeIriNode("http://example.org/string_prop"), + obj = nodeFactory.makeDatatypeLiteral(value = "Hello", datatype = OntologyConstants.Xsd.String) + ) + + val stringWithLangStatement: Statement = nodeFactory.makeStatement( + subj = subj, + pred = nodeFactory.makeIriNode("http://example.org/string_with_lang_prop"), + obj = nodeFactory.makeStringWithLanguage(value = "Hello", language = "en") + ) + + val statements: Set[Statement] = Set( + booleanStatement, + stringStatement, + stringWithLangStatement + ) + + model.addStatements(statements) + assert(model.find(subj = Some(subj), pred = None, obj = None) == statements) + + val stringWithLangFindResult: Set[Statement] = model.find( + subj = Some(subj), + pred = Some(stringWithLangStatement.pred), + obj = Some(stringWithLangStatement.obj) + ) + + assert(stringWithLangFindResult.size == 1) + + // Try some matching. + stringWithLangFindResult.head match { + case statement => + statement.obj match { + case resource: RdfResource => + throw AssertionException(s"Expected a string with a language code, got $resource") + + case rdfLiteral: RdfLiteral => + rdfLiteral match { + case datatypeLiteral: DatatypeLiteral => + throw AssertionException(s"Expected a string with a language code, got $datatypeLiteral") + + case stringWithLanguage: StringWithLanguage => + assert(stringWithLanguage.value == "Hello" && stringWithLanguage.language == "en") + } + } + } + } + + "add and find quads" in { + val labelPred: IriNode = nodeFactory.makeIriNode(OntologyConstants.Rdfs.Label) + val commentPred: IriNode = nodeFactory.makeIriNode(OntologyConstants.Rdfs.Comment) + val context1 = "http://example.org/graph1" + + val graph1LabelStatement = nodeFactory.makeStatement( + subj = nodeFactory.makeIriNode("http://example.org/6"), + pred = labelPred, + obj = nodeFactory.makeDatatypeLiteral(value = "Lucky's Discount X-Wing Repair", datatype = OntologyConstants.Xsd.String), + context = Some(context1) + ) + + val graph1CommentStatement = nodeFactory.makeStatement( + subj = nodeFactory.makeIriNode("http://example.org/6"), + pred = commentPred, + obj = nodeFactory.makeDatatypeLiteral(value = "A safe flight or your money back", datatype = OntologyConstants.Xsd.String), + context = Some(context1) + ) + + val graph1 = Set( + graph1LabelStatement, + graph1CommentStatement + ) + + val context2 = "http://example.org/graph2" + + val graph2LabelStatement = nodeFactory.makeStatement( + subj = nodeFactory.makeIriNode("http://example.org/7"), + pred = labelPred, + obj = nodeFactory.makeDatatypeLiteral(value = "Mos Eisley Used Droids", datatype = OntologyConstants.Xsd.String), + context = Some(context2) + ) + + val graph2CommentStatement = nodeFactory.makeStatement( + subj = nodeFactory.makeIriNode("http://example.org/7"), + pred = commentPred, + obj = nodeFactory.makeDatatypeLiteral(value = "All droids guaranteed for 10 seconds", datatype = OntologyConstants.Xsd.String), + context = Some(context2) + ) + + val graph2 = Set( + graph2LabelStatement, + graph2CommentStatement + ) + + model.addStatements(graph1) + model.addStatements(graph2) + + assert(model.find(subj = None, pred = None, obj = None, context = Some(context1)) == graph1) + assert(model.find(subj = None, pred = None, obj = None, context = Some(context2)) == graph2) + assert(model.find(subj = None, pred = Some(labelPred), obj = None) == Set(graph1LabelStatement, graph2LabelStatement)) + assert(model.find(subj = None, pred = Some(commentPred), obj = None) == Set(graph1CommentStatement, graph2CommentStatement)) + } + } +} diff --git a/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/jenaimpl/BUILD.bazel b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/jenaimpl/BUILD.bazel new file mode 100644 index 0000000000..7234ce79f2 --- /dev/null +++ b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/jenaimpl/BUILD.bazel @@ -0,0 +1,84 @@ +package(default_visibility = ["//visibility:public"]) + +load("@io_bazel_rules_scala//scala:scala.bzl", "scala_test") +load("//third_party:dependencies.bzl", "ALL_WEBAPI_MAIN_DEPENDENCIES", "BASE_TEST_DEPENDENCIES", "BASE_TEST_DEPENDENCIES_WITH_JSON", "BASE_TEST_DEPENDENCIES_WITH_JSON_LD") + +scala_test( + name = "JenaModelSpec", + size = "small", + srcs = [ + "JenaModelSpec.scala", + "//webapi/src/test/scala/org/knora/webapi/messages/util/rdf:RdfModelSpec.scala", + ], + data = [ + "//knora-ontologies", + "//test_data", + ], + jvm_flags = ["-Dconfig.resource=fuseki.conf"], + # unused_dependency_checker_mode = "warn", + deps = ALL_WEBAPI_MAIN_DEPENDENCIES + [ + "//webapi:main_library", + "//webapi:test_library", + ] + BASE_TEST_DEPENDENCIES, +) + +scala_test( + name = "JenaFormatUtilSpec", + size = "small", + srcs = [ + "JenaFormatUtilSpec.scala", + "//webapi/src/test/scala/org/knora/webapi/messages/util/rdf:RdfFormatUtilSpec.scala", + ], + data = [ + "//knora-ontologies", + "//test_data", + ], + jvm_flags = ["-Dconfig.resource=fuseki.conf"], + # unused_dependency_checker_mode = "warn", + deps = ALL_WEBAPI_MAIN_DEPENDENCIES + [ + "//webapi:main_library", + "//webapi:test_library", + "@maven//:org_apache_jena_apache_jena_libs" + ] + BASE_TEST_DEPENDENCIES_WITH_JSON, +) + +scala_test( + name = "JenaJsonLDUtilSpec", + size = "small", + srcs = [ + "JenaJsonLDUtilSpec.scala", + "//webapi/src/test/scala/org/knora/webapi/messages/util/rdf:JsonLDUtilSpec.scala", + ], + data = [ + "//knora-ontologies", + "//test_data", + ], + jvm_flags = ["-Dconfig.resource=fuseki.conf"], + # unused_dependency_checker_mode = "warn", + deps = ALL_WEBAPI_MAIN_DEPENDENCIES + [ + "//webapi:main_library", + "//webapi:test_library", + "@maven//:org_apache_jena_apache_jena_libs" + ] + BASE_TEST_DEPENDENCIES_WITH_JSON_LD, +) + +scala_test( + name = "JenaKnoraResponseV2Spec", + size = "small", + srcs = [ + "JenaKnoraResponseV2Spec.scala", + "//webapi/src/test/scala/org/knora/webapi/messages/util/rdf:KnoraResponseV2Spec.scala", + ], + data = [ + "//knora-ontologies", + "//test_data", + ], + jvm_flags = ["-Dconfig.resource=fuseki.conf"], + # unused_dependency_checker_mode = "warn", + deps = ALL_WEBAPI_MAIN_DEPENDENCIES + [ + "//webapi:main_library", + "//webapi:test_library", + "@maven//:org_apache_jena_apache_jena_libs" + ] + BASE_TEST_DEPENDENCIES_WITH_JSON, +) + diff --git a/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/jenaimpl/JenaFormatUtilSpec.scala b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/jenaimpl/JenaFormatUtilSpec.scala new file mode 100644 index 0000000000..511c51bc71 --- /dev/null +++ b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/jenaimpl/JenaFormatUtilSpec.scala @@ -0,0 +1,28 @@ +/* + * Copyright © 2015-2019 the contributors (see Contributors.md). + * + * This file is part of Knora. + * + * Knora is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Knora is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with Knora. If not, see . + */ + +package org.knora.webapi.util.rdf.jenaimpl + +import org.knora.webapi.feature.{FeatureToggle, ToggleStateOn} +import org.knora.webapi.util.rdf.RdfFormatUtilSpec + +/** + * Tests [[org.knora.webapi.messages.util.rdf.jenaimpl.JenaFormatUtil]]. + */ +class JenaFormatUtilSpec extends RdfFormatUtilSpec(FeatureToggle("jena-rdf-library", ToggleStateOn(1))) diff --git a/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/jenaimpl/JenaJsonLDUtilSpec.scala b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/jenaimpl/JenaJsonLDUtilSpec.scala new file mode 100644 index 0000000000..921c56bbcf --- /dev/null +++ b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/jenaimpl/JenaJsonLDUtilSpec.scala @@ -0,0 +1,28 @@ +/* + * Copyright © 2015-2019 the contributors (see Contributors.md). + * + * This file is part of Knora. + * + * Knora is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Knora is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with Knora. If not, see . + */ + +package org.knora.webapi.util.rdf.jenaimpl + +import org.knora.webapi.feature.{FeatureToggle, ToggleStateOn} +import org.knora.webapi.util.rdf.JsonLDUtilSpec + +/** + * Tests [[org.knora.webapi.messages.util.rdf.JsonLDUtil]] using the Jena RDF API. + */ +class JenaJsonLDUtilSpec extends JsonLDUtilSpec(FeatureToggle("jena-rdf-library", ToggleStateOn(1))) diff --git a/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/jenaimpl/JenaKnoraResponseV2Spec.scala b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/jenaimpl/JenaKnoraResponseV2Spec.scala new file mode 100644 index 0000000000..dbb6a1a7ad --- /dev/null +++ b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/jenaimpl/JenaKnoraResponseV2Spec.scala @@ -0,0 +1,28 @@ +/* + * Copyright © 2015-2019 the contributors (see Contributors.md). + * + * This file is part of Knora. + * + * Knora is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Knora is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with Knora. If not, see . + */ + +package org.knora.webapi.util.rdf.jenaimpl + +import org.knora.webapi.feature.{FeatureToggle, ToggleStateOn} +import org.knora.webapi.util.rdf.KnoraResponseV2Spec + +/** + * Tests [[org.knora.webapi.messages.v2.responder.KnoraResponseV2]] with the Jena API. + */ +class JenaKnoraResponseV2Spec extends KnoraResponseV2Spec(FeatureToggle("jena-rdf-library", ToggleStateOn(1))) diff --git a/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/jenaimpl/JenaModelSpec.scala b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/jenaimpl/JenaModelSpec.scala new file mode 100644 index 0000000000..b69cb18224 --- /dev/null +++ b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/jenaimpl/JenaModelSpec.scala @@ -0,0 +1,28 @@ +/* + * Copyright © 2015-2019 the contributors (see Contributors.md). + * + * This file is part of Knora. + * + * Knora is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Knora is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with Knora. If not, see . + */ + +package org.knora.webapi.util.rdf.jenaimpl + +import org.knora.webapi.feature._ +import org.knora.webapi.util.rdf.RdfModelSpec + +/** + * Tests [[org.knora.webapi.messages.util.rdf.jenaimpl.JenaModel]]. + */ +class JenaModelSpec extends RdfModelSpec(FeatureToggle("jena-rdf-library", ToggleStateOn(1))) diff --git a/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/BUILD.bazel b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/BUILD.bazel new file mode 100644 index 0000000000..0a65d555e3 --- /dev/null +++ b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/BUILD.bazel @@ -0,0 +1,83 @@ +package(default_visibility = ["//visibility:public"]) + +load("@io_bazel_rules_scala//scala:scala.bzl", "scala_test") +load("//third_party:dependencies.bzl", "ALL_WEBAPI_MAIN_DEPENDENCIES", "BASE_TEST_DEPENDENCIES", "BASE_TEST_DEPENDENCIES_WITH_JSON", "BASE_TEST_DEPENDENCIES_WITH_JSON_LD") + +scala_test( + name = "RDF4JModelSpec", + size = "small", + srcs = [ + "RDF4JModelSpec.scala", + "//webapi/src/test/scala/org/knora/webapi/messages/util/rdf:RdfModelSpec.scala", + ], + data = [ + "//knora-ontologies", + "//test_data", + ], + jvm_flags = ["-Dconfig.resource=fuseki.conf"], + # unused_dependency_checker_mode = "warn", + deps = ALL_WEBAPI_MAIN_DEPENDENCIES + [ + "//webapi:main_library", + "//webapi:test_library", + ] + BASE_TEST_DEPENDENCIES, +) + +scala_test( + name = "RDF4JFormatUtilSpec", + size = "small", + srcs = [ + "RDF4JFormatUtilSpec.scala", + "//webapi/src/test/scala/org/knora/webapi/messages/util/rdf:RdfFormatUtilSpec.scala", + ], + data = [ + "//knora-ontologies", + "//test_data", + ], + jvm_flags = ["-Dconfig.resource=fuseki.conf"], + # unused_dependency_checker_mode = "warn", + deps = ALL_WEBAPI_MAIN_DEPENDENCIES + [ + "//webapi:main_library", + "//webapi:test_library", + "@maven//:org_apache_jena_apache_jena_libs" + ] + BASE_TEST_DEPENDENCIES_WITH_JSON, +) + +scala_test( + name = "RDF4JJsonLDUtilSpec", + size = "small", + srcs = [ + "RDF4JJsonLDUtilSpec.scala", + "//webapi/src/test/scala/org/knora/webapi/messages/util/rdf:JsonLDUtilSpec.scala", + ], + data = [ + "//knora-ontologies", + "//test_data", + ], + jvm_flags = ["-Dconfig.resource=fuseki.conf"], + # unused_dependency_checker_mode = "warn", + deps = ALL_WEBAPI_MAIN_DEPENDENCIES + [ + "//webapi:main_library", + "//webapi:test_library", + "@maven//:org_apache_jena_apache_jena_libs" + ] + BASE_TEST_DEPENDENCIES_WITH_JSON_LD, +) + +scala_test( + name = "RDF4JKnoraResponseV2Spec", + size = "small", + srcs = [ + "RDF4JKnoraResponseV2Spec.scala", + "//webapi/src/test/scala/org/knora/webapi/messages/util/rdf:KnoraResponseV2Spec.scala", + ], + data = [ + "//knora-ontologies", + "//test_data", + ], + jvm_flags = ["-Dconfig.resource=fuseki.conf"], + # unused_dependency_checker_mode = "warn", + deps = ALL_WEBAPI_MAIN_DEPENDENCIES + [ + "//webapi:main_library", + "//webapi:test_library", + "@maven//:org_apache_jena_apache_jena_libs" + ] + BASE_TEST_DEPENDENCIES_WITH_JSON, +) diff --git a/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/RDF4JFormatUtilSpec.scala b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/RDF4JFormatUtilSpec.scala new file mode 100644 index 0000000000..51b81c4afa --- /dev/null +++ b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/RDF4JFormatUtilSpec.scala @@ -0,0 +1,28 @@ +/* + * Copyright © 2015-2019 the contributors (see Contributors.md). + * + * This file is part of Knora. + * + * Knora is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Knora is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with Knora. If not, see . + */ + +package org.knora.webapi.util.rdf.rdf4jimpl + +import org.knora.webapi.feature.{FeatureToggle, ToggleStateOff} +import org.knora.webapi.util.rdf.RdfFormatUtilSpec + +/** + * Tests [[org.knora.webapi.messages.util.rdf.rdf4jimpl.RDF4JFormatUtil]]. + */ +class RDF4JFormatUtilSpec extends RdfFormatUtilSpec(FeatureToggle("jena-rdf-library", ToggleStateOff)) diff --git a/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/RDF4JJsonLDUtilSpec.scala b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/RDF4JJsonLDUtilSpec.scala new file mode 100644 index 0000000000..48cc56daf4 --- /dev/null +++ b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/RDF4JJsonLDUtilSpec.scala @@ -0,0 +1,28 @@ +/* + * Copyright © 2015-2019 the contributors (see Contributors.md). + * + * This file is part of Knora. + * + * Knora is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Knora is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with Knora. If not, see . + */ + +package org.knora.webapi.util.rdf.rdf4jimpl + +import org.knora.webapi.feature.{FeatureToggle, ToggleStateOff} +import org.knora.webapi.util.rdf.JsonLDUtilSpec + +/** + * Tests [[org.knora.webapi.messages.util.rdf.JsonLDUtil]] using the RDF4J API. + */ +class RDF4JJsonLDUtilSpec extends JsonLDUtilSpec(FeatureToggle("jena-rdf-library", ToggleStateOff)) diff --git a/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/RDF4JKnoraResponseV2Spec.scala b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/RDF4JKnoraResponseV2Spec.scala new file mode 100644 index 0000000000..c4c3a49e96 --- /dev/null +++ b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/RDF4JKnoraResponseV2Spec.scala @@ -0,0 +1,28 @@ +/* + * Copyright © 2015-2019 the contributors (see Contributors.md). + * + * This file is part of Knora. + * + * Knora is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Knora is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with Knora. If not, see . + */ + +package org.knora.webapi.util.rdf.rdf4jimpl + +import org.knora.webapi.feature.{FeatureToggle, ToggleStateOff} +import org.knora.webapi.util.rdf.KnoraResponseV2Spec + +/** + * Tests [[org.knora.webapi.messages.v2.responder.KnoraResponseV2]] with the RDF4J API. + */ +class RDF4JKnoraResponseV2Spec extends KnoraResponseV2Spec(FeatureToggle("jena-rdf-library", ToggleStateOff)) diff --git a/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/RDF4JModelSpec.scala b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/RDF4JModelSpec.scala new file mode 100644 index 0000000000..91b16c218f --- /dev/null +++ b/webapi/src/test/scala/org/knora/webapi/messages/util/rdf/rdf4jimpl/RDF4JModelSpec.scala @@ -0,0 +1,28 @@ +/* + * Copyright © 2015-2019 the contributors (see Contributors.md). + * + * This file is part of Knora. + * + * Knora is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Knora is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with Knora. If not, see . + */ + +package org.knora.webapi.util.rdf.rdf4jimpl + +import org.knora.webapi.feature._ +import org.knora.webapi.util.rdf.RdfModelSpec + +/** + * Tests [[org.knora.webapi.messages.util.rdf.rdf4jimpl.RDF4JModel]]. + */ +class RDF4JModelSpec extends RdfModelSpec(FeatureToggle("jena-rdf-library", ToggleStateOff)) diff --git a/webapi/src/test/scala/org/knora/webapi/messages/v2/responder/metadatamessages/MetadataMessagesV2Spec.scala b/webapi/src/test/scala/org/knora/webapi/messages/v2/responder/metadatamessages/MetadataMessagesV2Spec.scala index c44e0d5b93..1652c56e75 100644 --- a/webapi/src/test/scala/org/knora/webapi/messages/v2/responder/metadatamessages/MetadataMessagesV2Spec.scala +++ b/webapi/src/test/scala/org/knora/webapi/messages/v2/responder/metadatamessages/MetadataMessagesV2Spec.scala @@ -21,38 +21,39 @@ package org.knora.webapi.messages.v2.responder.metadatamessages import java.util.UUID -import org.apache.jena.graph.Graph -import org.knora.webapi.{CoreSpec, RdfMediaTypes} +import org.knora.webapi.CoreSpec import org.knora.webapi.exceptions.ForbiddenException -import org.knora.webapi.messages.util.RdfFormatUtil +import org.knora.webapi.messages.util.rdf.{RdfFeatureFactory, RdfFormatUtil, RdfModel, Turtle} import org.knora.webapi.sharedtestdata.SharedTestDataADM /** * Tests [[MetadataPutRequestV2]]. */ class MetadataMessagesV2Spec extends CoreSpec() { + private val rdfFormatUtil: RdfFormatUtil = RdfFeatureFactory.getRdfFormatUtil(defaultFeatureFactoryConfig) + private val graphDataContent: String = """ @prefix dsp-repo: . @prefix rdf: . - @prefix anything: . - dsp-repo:hasDescription "A project to test Knora functionalities" . - dsp-repo:hasShortcode "0001" . + dsp-repo:anything dsp-repo:hasDescription "A project to test Knora functionalities" . + dsp-repo:anything dsp-repo:hasShortcode "0001" . """ - // Parse the request to a Jena Graph. - private val requestGraph: Graph = RdfFormatUtil.parseToJenaGraph( + // Parse the request to an RdfModel. + private val requestModel: RdfModel = rdfFormatUtil.parseToRdfModel( rdfStr = graphDataContent, - mediaType = RdfMediaTypes.`text/turtle` + rdfFormat = Turtle ) "MetadataPutRequestV2" should { "return ForbiddenException if the requesting user is not the project admin or a system admin" in { assertThrows[ForbiddenException]( MetadataPutRequestV2( - graph = requestGraph, + rdfModel = requestModel, projectADM = SharedTestDataADM.anythingProject, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.anythingUser2, apiRequestID = UUID.randomUUID() ) diff --git a/webapi/src/test/scala/org/knora/webapi/messages/v2/responder/ontologymessages/InputOntologyV2Spec.scala b/webapi/src/test/scala/org/knora/webapi/messages/v2/responder/ontologymessages/InputOntologyV2Spec.scala index 55c4fb7a47..0f0606a669 100644 --- a/webapi/src/test/scala/org/knora/webapi/messages/v2/responder/ontologymessages/InputOntologyV2Spec.scala +++ b/webapi/src/test/scala/org/knora/webapi/messages/v2/responder/ontologymessages/InputOntologyV2Spec.scala @@ -25,7 +25,7 @@ import org.knora.webapi.exceptions.BadRequestException import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.StringFormatter import org.knora.webapi.messages.store.triplestoremessages.{SmartIriLiteralV2, StringLiteralV2} -import org.knora.webapi.messages.util.JsonLDUtil +import org.knora.webapi.messages.util.rdf.JsonLDUtil import org.knora.webapi.messages.v2.responder.ontologymessages.Cardinality.KnoraCardinalityInfo import org.knora.webapi.{ApiV2Complex, CoreSpec} diff --git a/webapi/src/test/scala/org/knora/webapi/other/v1/DrawingsGodsV1Spec.scala b/webapi/src/test/scala/org/knora/webapi/other/v1/DrawingsGodsV1Spec.scala index 5c4fb5eb72..028384d317 100644 --- a/webapi/src/test/scala/org/knora/webapi/other/v1/DrawingsGodsV1Spec.scala +++ b/webapi/src/test/scala/org/knora/webapi/other/v1/DrawingsGodsV1Spec.scala @@ -17,21 +17,21 @@ package org.knora.webapi.other.v1 import java.util.UUID -import com.typesafe.config.ConfigFactory +import com.typesafe.config.{Config, ConfigFactory} import org.knora.webapi._ -import org.knora.webapi.messages.admin.responder.permissionsmessages.{DefaultObjectAccessPermissionsStringForPropertyGetADM, DefaultObjectAccessPermissionsStringForResourceClassGetADM, DefaultObjectAccessPermissionsStringResponseADM} -import org.knora.webapi.messages.admin.responder.usersmessages.{UserADM, UserGetADM, UserIdentifierADM, UserInformationTypeADM} +import org.knora.webapi.messages.admin.responder.permissionsmessages._ +import org.knora.webapi.messages.admin.responder.usersmessages._ import org.knora.webapi.messages.store.triplestoremessages.{RdfDataObject, TriplestoreJsonProtocol} import org.knora.webapi.messages.util.KnoraSystemInstances -import org.knora.webapi.messages.v1.responder.resourcemessages.{ResourceCreateRequestV1, ResourceCreateResponseV1, _} -import org.knora.webapi.messages.v1.responder.valuemessages.{CreateValueV1WithComment, TextValueSimpleV1, _} +import org.knora.webapi.messages.v1.responder.resourcemessages._ +import org.knora.webapi.messages.v1.responder.valuemessages._ import org.knora.webapi.util.MutableUserADM import org.knora.webapi.messages.{OntologyConstants, StringFormatter} import scala.concurrent.duration._ object DrawingsGodsV1Spec { - val config = ConfigFactory.parseString( + val config: Config = ConfigFactory.parseString( """ akka.loglevel = "DEBUG" akka.stdout-loglevel = "DEBUG" @@ -39,8 +39,8 @@ object DrawingsGodsV1Spec { } /** - * Test specification for testing a complex permissions structure of the drawings-gods-project. - */ + * Test specification for testing a complex permissions structure of the drawings-gods-project. + */ class DrawingsGodsV1Spec extends CoreSpec(DrawingsGodsV1Spec.config) with TriplestoreJsonProtocol { private val timeout = 5.seconds @@ -55,10 +55,10 @@ class DrawingsGodsV1Spec extends CoreSpec(DrawingsGodsV1Spec.config) with Triple ) /** - * issues: - * - https://github.com/dhlab-basel/Knora/issues/416 - * - https://github.com/dhlab-basel/Knora/issues/610 - */ + * issues: + * - https://github.com/dhlab-basel/Knora/issues/416 + * - https://github.com/dhlab-basel/Knora/issues/610 + */ "Using the DrawingsGods project data" should { val drawingsGodsProjectIri = "http://rdfh.ch/projects/0105" @@ -71,13 +71,31 @@ class DrawingsGodsV1Spec extends CoreSpec(DrawingsGodsV1Spec.config) with Triple val ddd2 = new MutableUserADM "retrieve the drawings gods user's profile" in { - responderManager ! UserGetADM(UserIdentifierADM(maybeIri = Some(rootUserIri)), userInformationTypeADM = UserInformationTypeADM.FULL, requestingUser = KnoraSystemInstances.Users.SystemUser) + responderManager ! UserGetADM( + identifier = UserIdentifierADM(maybeIri = Some(rootUserIri)), + userInformationTypeADM = UserInformationTypeADM.FULL, + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) + rootUser.set(expectMsgType[Option[UserADM]](timeout).get) - responderManager ! UserGetADM(UserIdentifierADM(maybeIri = Some(ddd1UserIri)), userInformationTypeADM = UserInformationTypeADM.FULL, requestingUser = KnoraSystemInstances.Users.SystemUser) + responderManager ! UserGetADM( + identifier = UserIdentifierADM(maybeIri = Some(ddd1UserIri)), + userInformationTypeADM = UserInformationTypeADM.FULL, + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) + ddd1.set(expectMsgType[Option[UserADM]](timeout).get) - responderManager ! UserGetADM(UserIdentifierADM(maybeIri = Some(ddd2UserIri)), userInformationTypeADM = UserInformationTypeADM.FULL, requestingUser = KnoraSystemInstances.Users.SystemUser) + responderManager ! UserGetADM(UserIdentifierADM( + maybeIri = Some(ddd2UserIri)), + userInformationTypeADM = UserInformationTypeADM.FULL, + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) + ddd2.set(expectMsgType[Option[UserADM]](timeout).get) } @@ -129,6 +147,7 @@ class DrawingsGodsV1Spec extends CoreSpec(DrawingsGodsV1Spec.config) with Triple projectIri = drawingsGodsProjectIri, values = valuesToBeCreated, file = None, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = ddd1.get, apiRequestID = UUID.randomUUID ) @@ -136,7 +155,11 @@ class DrawingsGodsV1Spec extends CoreSpec(DrawingsGodsV1Spec.config) with Triple val createResponse = expectMsgType[ResourceCreateResponseV1](timeout) val resourceIri = createResponse.res_id - responderManager ! ResourceFullGetRequestV1(iri = resourceIri, userADM = ddd1.get) + responderManager ! ResourceFullGetRequestV1( + iri = resourceIri, + featureFactoryConfig = defaultFeatureFactoryConfig, + userADM = ddd1.get + ) val getResponse = expectMsgType[ResourceFullResponseV1](timeout) @@ -164,6 +187,7 @@ class DrawingsGodsV1Spec extends CoreSpec(DrawingsGodsV1Spec.config) with Triple projectIri = drawingsGodsProjectIri, values = valuesToBeCreated, file = None, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = rootUser.get, apiRequestID = UUID.randomUUID ) diff --git a/webapi/src/test/scala/org/knora/webapi/responders/admin/GroupsResponderADMSpec.scala b/webapi/src/test/scala/org/knora/webapi/responders/admin/GroupsResponderADMSpec.scala index 55eb136678..84bb175191 100644 --- a/webapi/src/test/scala/org/knora/webapi/responders/admin/GroupsResponderADMSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/responders/admin/GroupsResponderADMSpec.scala @@ -56,8 +56,6 @@ class GroupsResponderADMSpec extends CoreSpec(GroupsResponderADMSpec.config) wit private val imagesProject = SharedTestDataADM.imagesProject private val imagesReviewerGroup = SharedTestDataADM.imagesReviewerGroup - private val imagesProjectAdminGroup = SharedTestDataADM.imagesProjectAdminGroup - private val imagesProjectMemberGroup = SharedTestDataADM.imagesProjectMemberGroup private val rootUser = SharedTestDataADM.rootUser @@ -65,7 +63,11 @@ class GroupsResponderADMSpec extends CoreSpec(GroupsResponderADMSpec.config) wit "asked about all groups" should { "return a list" in { - responderManager ! GroupsGetRequestADM(SharedTestDataADM.rootUser) + responderManager ! GroupsGetRequestADM( + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = SharedTestDataADM.rootUser + ) + val response = expectMsgType[GroupsGetResponseADM](timeout) // println(response.users) response.groups.nonEmpty should be (true) @@ -75,11 +77,20 @@ class GroupsResponderADMSpec extends CoreSpec(GroupsResponderADMSpec.config) wit "asked about a group identified by 'iri' " should { "return group info if the group is known " in { - responderManager ! GroupGetRequestADM(imagesReviewerGroup.id, rootUser) + responderManager ! GroupGetRequestADM( + groupIri = imagesReviewerGroup.id, + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = rootUser + ) + expectMsg(GroupGetResponseADM(imagesReviewerGroup)) } "return 'NotFoundException' when the group is unknown " in { - responderManager ! GroupGetRequestADM("http://rdfh.ch/groups/notexisting", rootUser) + responderManager ! GroupGetRequestADM( + groupIri = "http://rdfh.ch/groups/notexisting", + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = rootUser + ) expectMsgPF(timeout) { case msg: akka.actor.Status.Failure => msg.cause.isInstanceOf[NotFoundException] should ===(true) @@ -99,8 +110,9 @@ class GroupsResponderADMSpec extends CoreSpec(GroupsResponderADMSpec.config) wit project = SharedTestDataADM.IMAGES_PROJECT_IRI, status = true, selfjoin = false), - SharedTestDataADM.imagesUser01, - UUID.randomUUID + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = SharedTestDataADM.imagesUser01, + apiRequestID = UUID.randomUUID ) val received: GroupOperationResponseADM = expectMsgType[GroupOperationResponseADM](timeout) @@ -124,8 +136,9 @@ class GroupsResponderADMSpec extends CoreSpec(GroupsResponderADMSpec.config) wit project = SharedTestDataADM.IMAGES_PROJECT_IRI, status = true, selfjoin = false), - SharedTestDataADM.imagesUser01, - UUID.randomUUID + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = SharedTestDataADM.imagesUser01, + apiRequestID = UUID.randomUUID ) expectMsgPF(timeout) { @@ -143,8 +156,9 @@ class GroupsResponderADMSpec extends CoreSpec(GroupsResponderADMSpec.config) wit project = SharedTestDataADM.IMAGES_PROJECT_IRI, status = true, selfjoin = false), - SharedTestDataADM.imagesUser01, - UUID.randomUUID + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = SharedTestDataADM.imagesUser01, + apiRequestID = UUID.randomUUID ) expectMsg(Failure(BadRequestException("Group name cannot be empty"))) @@ -156,18 +170,20 @@ class GroupsResponderADMSpec extends CoreSpec(GroupsResponderADMSpec.config) wit project = "", status = true, selfjoin = false), - SharedTestDataADM.imagesUser01, - UUID.randomUUID + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = SharedTestDataADM.imagesUser01, + apiRequestID = UUID.randomUUID ) expectMsg(Failure(BadRequestException("Project IRI cannot be empty"))) } "UPDATE a group" in { responderManager ! GroupChangeRequestADM( - newGroupIri.get, - ChangeGroupApiRequestADM(Some("UpdatedGroupName"), Some("""UpdatedDescription with "quotes" and """)), - SharedTestDataADM.imagesUser01, - UUID.randomUUID + groupIri = newGroupIri.get, + changeGroupRequest = ChangeGroupApiRequestADM(Some("UpdatedGroupName"), Some("""UpdatedDescription with "quotes" and """)), + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = SharedTestDataADM.imagesUser01, + apiRequestID = UUID.randomUUID ) val received: GroupOperationResponseADM = expectMsgType[GroupOperationResponseADM](timeout) @@ -184,8 +200,9 @@ class GroupsResponderADMSpec extends CoreSpec(GroupsResponderADMSpec.config) wit responderManager ! GroupChangeRequestADM( groupIri = "http://rdfh.ch/groups/notexisting", ChangeGroupApiRequestADM(Some("UpdatedGroupName"), Some("UpdatedDescription")), - SharedTestDataADM.imagesUser01, - UUID.randomUUID + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = SharedTestDataADM.imagesUser01, + apiRequestID = UUID.randomUUID ) expectMsgPF(timeout) { @@ -195,10 +212,11 @@ class GroupsResponderADMSpec extends CoreSpec(GroupsResponderADMSpec.config) wit "return 'BadRequest' if the new group name already exists inside the project" in { responderManager ! GroupChangeRequestADM( - newGroupIri.get, - ChangeGroupApiRequestADM(Some("Image reviewer"), Some("UpdatedDescription")), - SharedTestDataADM.imagesUser01, - UUID.randomUUID + groupIri = newGroupIri.get, + changeGroupRequest = ChangeGroupApiRequestADM(Some("Image reviewer"), Some("UpdatedDescription")), + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = SharedTestDataADM.imagesUser01, + apiRequestID = UUID.randomUUID ) expectMsgPF(timeout) { @@ -217,6 +235,7 @@ class GroupsResponderADMSpec extends CoreSpec(GroupsResponderADMSpec.config) wit "return all members of a group identified by IRI" in { responderManager ! GroupMembersGetRequestADM( groupIri = SharedTestDataADM.imagesReviewerGroup.id, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) @@ -231,6 +250,7 @@ class GroupsResponderADMSpec extends CoreSpec(GroupsResponderADMSpec.config) wit "remove all members when group is deactivated" in { responderManager ! GroupMembersGetRequestADM( groupIri = SharedTestDataADM.imagesReviewerGroup.id, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) @@ -239,9 +259,10 @@ class GroupsResponderADMSpec extends CoreSpec(GroupsResponderADMSpec.config) wit responderManager ! GroupChangeStatusRequestADM( groupIri = SharedTestDataADM.imagesReviewerGroup.id, - ChangeGroupApiRequestADM(status = Some(false)), - SharedTestDataADM.imagesUser01, - UUID.randomUUID + changeGroupRequest = ChangeGroupApiRequestADM(status = Some(false)), + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = SharedTestDataADM.imagesUser01, + apiRequestID = UUID.randomUUID ) val statusChangeResponse = expectMsgType[GroupOperationResponseADM](timeout) @@ -250,6 +271,7 @@ class GroupsResponderADMSpec extends CoreSpec(GroupsResponderADMSpec.config) wit responderManager ! GroupMembersGetRequestADM( groupIri = SharedTestDataADM.imagesReviewerGroup.id, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) @@ -259,6 +281,7 @@ class GroupsResponderADMSpec extends CoreSpec(GroupsResponderADMSpec.config) wit "return 'NotFound' when the group IRI is unknown" in { responderManager ! GroupMembersGetRequestADM( groupIri = "http://rdfh.ch/groups/notexisting", + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) diff --git a/webapi/src/test/scala/org/knora/webapi/responders/admin/ListsResponderADMSpec.scala b/webapi/src/test/scala/org/knora/webapi/responders/admin/ListsResponderADMSpec.scala index 2a1b41447a..2cbf663493 100644 --- a/webapi/src/test/scala/org/knora/webapi/responders/admin/ListsResponderADMSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/responders/admin/ListsResponderADMSpec.scala @@ -34,9 +34,10 @@ import org.knora.webapi.sharedtestdata.{SharedListsTestDataADM, SharedTestDataAD import org.knora.webapi.util.MutableTestIri import scala.concurrent.duration._ + /** - * Static data for testing [[ListsResponderADM]]. - */ + * Static data for testing [[ListsResponderADM]]. + */ object ListsResponderADMSpec { val config: Config = ConfigFactory.parseString( """ @@ -46,12 +47,12 @@ object ListsResponderADMSpec { } /** - * Tests [[ListsResponderADM]]. - */ + * Tests [[ListsResponderADM]]. + */ class ListsResponderADMSpec extends CoreSpec(ListsResponderADMSpec.config) with ImplicitSender { // The default timeout for receiving reply messages from actors. - implicit val timeout = 5.seconds + implicit private val timeout = 5.seconds override lazy val rdfDataObjects = List( RdfDataObject(path = "test_data/demo_data/images-demo-data.ttl", name = "http://www.knora.org/data/00FF/images"), @@ -64,22 +65,17 @@ class ListsResponderADMSpec extends CoreSpec(ListsResponderADMSpec.config) with private val otherTreeListInfo: ListRootNodeInfoADM = SharedListsTestDataADM.otherTreeListInfo - private val keywordChildNodes: Seq[ListNodeADM] = Seq.empty[ListNodeADM] - private val treeListChildNodes: Seq[ListNodeADM] = SharedListsTestDataADM.treeListChildNodes - private val imageCategory = Seq.empty[ListNodeADM] - - private val season = SharedListsTestDataADM.seasonListNodes - - private val nodePath = SharedListsTestDataADM.nodePath - "The Lists Responder" when { "used to query information about lists" should { "return all lists" in { - responderManager ! ListsGetRequestADM(requestingUser = SharedTestDataADM.imagesUser01) + responderManager ! ListsGetRequestADM( + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = SharedTestDataADM.imagesUser01 + ) val received: ListsGetResponseADM = expectMsgType[ListsGetResponseADM](timeout) @@ -87,7 +83,11 @@ class ListsResponderADMSpec extends CoreSpec(ListsResponderADMSpec.config) with } "return all lists belonging to the images project" in { - responderManager ! ListsGetRequestADM(projectIri = Some(IMAGES_PROJECT_IRI), requestingUser = SharedTestDataADM.imagesUser01) + responderManager ! ListsGetRequestADM( + projectIri = Some(IMAGES_PROJECT_IRI), + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = SharedTestDataADM.imagesUser01 + ) val received: ListsGetResponseADM = expectMsgType[ListsGetResponseADM](timeout) @@ -97,7 +97,11 @@ class ListsResponderADMSpec extends CoreSpec(ListsResponderADMSpec.config) with } "return all lists belonging to the anything project" in { - responderManager ! ListsGetRequestADM(projectIri = Some(ANYTHING_PROJECT_IRI), requestingUser = SharedTestDataADM.imagesUser01) + responderManager ! ListsGetRequestADM( + projectIri = Some(ANYTHING_PROJECT_IRI), + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = SharedTestDataADM.imagesUser01 + ) val received: ListsGetResponseADM = expectMsgType[ListsGetResponseADM](timeout) @@ -109,6 +113,7 @@ class ListsResponderADMSpec extends CoreSpec(ListsResponderADMSpec.config) with "return basic list information (anything list)" in { responderManager ! ListInfoGetRequestADM( iri = "http://rdfh.ch/lists/0001/treeList", + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.anythingUser1 ) @@ -122,6 +127,7 @@ class ListsResponderADMSpec extends CoreSpec(ListsResponderADMSpec.config) with "return basic list information (anything other list)" in { responderManager ! ListInfoGetRequestADM( iri = "http://rdfh.ch/lists/0001/otherTreeList", + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.anythingUser1 ) @@ -135,6 +141,7 @@ class ListsResponderADMSpec extends CoreSpec(ListsResponderADMSpec.config) with "return basic node information (images list - sommer)" in { responderManager ! ListNodeInfoGetRequestADM( iri = "http://rdfh.ch/lists/00FF/526f26ed04", + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser01 ) @@ -148,6 +155,7 @@ class ListsResponderADMSpec extends CoreSpec(ListsResponderADMSpec.config) with "return a full list response" in { responderManager ! ListGetRequestADM( iri = "http://rdfh.ch/lists/0001/treeList", + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.anythingUser1 ) @@ -176,6 +184,7 @@ class ListsResponderADMSpec extends CoreSpec(ListsResponderADMSpec.config) with labels = Seq(StringLiteralV2(value = "Neue Liste", language = Some("de"))), comments = Seq.empty[StringLiteralV2] ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser01, apiRequestID = UUID.randomUUID ) @@ -183,19 +192,19 @@ class ListsResponderADMSpec extends CoreSpec(ListsResponderADMSpec.config) with val received: ListGetResponseADM = expectMsgType[ListGetResponseADM](timeout) val listInfo = received.list.listinfo - listInfo.projectIri should be (IMAGES_PROJECT_IRI) + listInfo.projectIri should be(IMAGES_PROJECT_IRI) - listInfo.name should be (Some("neuelistename")) + listInfo.name should be(Some("neuelistename")) val labels: Seq[StringLiteralV2] = listInfo.labels.stringLiterals - labels.size should be (1) - labels.head should be (StringLiteralV2(value = "Neue Liste", language = Some("de"))) + labels.size should be(1) + labels.head should be(StringLiteralV2(value = "Neue Liste", language = Some("de"))) val comments = received.list.listinfo.comments.stringLiterals - comments.isEmpty should be (true) + comments.isEmpty should be(true) val children = received.list.children - children.size should be (0) + children.size should be(0) // store list IRI for next test newListIri.set(listInfo.id) @@ -209,6 +218,7 @@ class ListsResponderADMSpec extends CoreSpec(ListsResponderADMSpec.config) with labels = Seq(StringLiteralV2(value = "Neue Liste", language = Some("de"))), comments = Seq.empty[StringLiteralV2] ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser02, apiRequestID = UUID.randomUUID ) @@ -231,7 +241,8 @@ class ListsResponderADMSpec extends CoreSpec(ListsResponderADMSpec.config) with StringLiteralV2(value = "Neuer Kommentar", language = Some("de")), StringLiteralV2(value = "New comment", language = Some("en")) ) - )), + )), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser01, apiRequestID = UUID.randomUUID ) @@ -239,18 +250,18 @@ class ListsResponderADMSpec extends CoreSpec(ListsResponderADMSpec.config) with val received: ListInfoGetResponseADM = expectMsgType[ListInfoGetResponseADM](timeout) val listInfo = received.listinfo - listInfo.projectIri should be (IMAGES_PROJECT_IRI) - listInfo.name should be (Some("updated name")) + listInfo.projectIri should be(IMAGES_PROJECT_IRI) + listInfo.name should be(Some("updated name")) val labels: Seq[StringLiteralV2] = listInfo.labels.stringLiterals - labels.size should be (2) - labels.sorted should be (Seq( + labels.size should be(2) + labels.sorted should be(Seq( StringLiteralV2(value = "Neue geänderte Liste", language = Some("de")), StringLiteralV2(value = "Changed list", language = Some("en")) ).sorted) val comments = listInfo.comments.stringLiterals - comments.size should be (2) - comments.sorted should be (Seq( + comments.size should be(2) + comments.sorted should be(Seq( StringLiteralV2(value = "Neuer Kommentar", language = Some("de")), StringLiteralV2(value = "New comment", language = Some("en")) ).sorted) @@ -263,6 +274,7 @@ class ListsResponderADMSpec extends CoreSpec(ListsResponderADMSpec.config) with listIri = newListIri.get, projectIri = IMAGES_PROJECT_IRI, name = Some("sommer")), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser01, apiRequestID = UUID.randomUUID ) @@ -283,7 +295,8 @@ class ListsResponderADMSpec extends CoreSpec(ListsResponderADMSpec.config) with StringLiteralV2(value = "Neuer Kommentar", language = Some("de")), StringLiteralV2(value = "New comment", language = Some("en")) ) - )), + )), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser02, apiRequestID = UUID.randomUUID ) @@ -301,6 +314,7 @@ class ListsResponderADMSpec extends CoreSpec(ListsResponderADMSpec.config) with labels = Seq(StringLiteralV2(value = "New First Child List Node Value", language = Some("en"))), comments = Seq(StringLiteralV2(value = "New First Child List Node Comment", language = Some("en"))) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser01, apiRequestID = UUID.randomUUID ) @@ -316,123 +330,125 @@ class ListsResponderADMSpec extends CoreSpec(ListsResponderADMSpec.config) with // check labels val labels: Seq[StringLiteralV2] = childNodeInfo.labels.stringLiterals - labels.size should be (1) - labels.sorted should be (Seq(StringLiteralV2(value = "New First Child List Node Value", language = Some("en")))) + labels.size should be(1) + labels.sorted should be(Seq(StringLiteralV2(value = "New First Child List Node Value", language = Some("en")))) // check comments val comments = childNodeInfo.comments.stringLiterals - comments.size should be (1) - comments.sorted should be (Seq(StringLiteralV2(value = "New First Child List Node Comment", language = Some("en")))) + comments.size should be(1) + comments.sorted should be(Seq(StringLiteralV2(value = "New First Child List Node Comment", language = Some("en")))) // check position val position = childNodeInfo.position - position should be (0) + position should be(0) // check has root node val rootNode = childNodeInfo.hasRootNode - rootNode should be (newListIri.get) + rootNode should be(newListIri.get) firstChildIri.set(childNodeInfo.id) } "add second child to list - to the root node" in { responderManager ! ListChildNodeCreateRequestADM( - parentNodeIri = newListIri.get, - createChildNodeRequest = CreateChildNodeApiRequestADM( - parentNodeIri = newListIri.get, - projectIri = IMAGES_PROJECT_IRI, - name = Some("second"), - labels = Seq(StringLiteralV2(value = "New Second Child List Node Value", language = Some("en"))), - comments = Seq(StringLiteralV2(value = "New Second Child List Node Comment", language = Some("en"))) - ), - requestingUser = SharedTestDataADM.imagesUser01, - apiRequestID = UUID.randomUUID - ) - - val received: ListNodeInfoGetResponseADM = expectMsgType[ListNodeInfoGetResponseADM](timeout) - val nodeInfo = received.nodeinfo - - // check correct node info - val childNodeInfo = nodeInfo match { - case info: ListChildNodeInfoADM => info - case something => fail(s"expecting ListChildNodeInfoADM but got ${something.getClass.toString} instead.") - } - - // check labels - val labels: Seq[StringLiteralV2] = childNodeInfo.labels.stringLiterals - labels.size should be (1) - labels.sorted should be (Seq(StringLiteralV2(value = "New Second Child List Node Value", language = Some("en")))) - - - // check comments - val comments = childNodeInfo.comments.stringLiterals - comments.size should be (1) - comments.sorted should be (Seq(StringLiteralV2(value = "New Second Child List Node Comment", language = Some("en")))) - - // check position - val position = childNodeInfo.position - position should be (1) - - // check has root node - val rootNode = childNodeInfo.hasRootNode - rootNode should be (newListIri.get) - - secondChildIri.set(childNodeInfo.id) - } - - "add child to second child node" in { - responderManager ! ListChildNodeCreateRequestADM( - parentNodeIri = secondChildIri.get, - createChildNodeRequest = CreateChildNodeApiRequestADM( - parentNodeIri = secondChildIri.get, - projectIri = IMAGES_PROJECT_IRI, - name = Some("third"), - labels = Seq(StringLiteralV2(value = "New Third Child List Node Value", language = Some("en"))), - comments = Seq(StringLiteralV2(value = "New Third Child List Node Comment", language = Some("en"))) - ), - requestingUser = SharedTestDataADM.imagesUser01, - apiRequestID = UUID.randomUUID - ) - - val received: ListNodeInfoGetResponseADM = expectMsgType[ListNodeInfoGetResponseADM](timeout) - val nodeInfo = received.nodeinfo - - // check correct node info - val childNodeInfo = nodeInfo match { - case info: ListChildNodeInfoADM => info - case something => fail(s"expecting ListChildNodeInfoADM but got ${something.getClass.toString} instead.") - } - - // check labels - val labels: Seq[StringLiteralV2] = childNodeInfo.labels.stringLiterals - labels.size should be (1) - labels.sorted should be (Seq(StringLiteralV2(value = "New Third Child List Node Value", language = Some("en")))) - - - // check comments - val comments = childNodeInfo.comments.stringLiterals - comments.size should be (1) - comments.sorted should be (Seq(StringLiteralV2(value = "New Third Child List Node Comment", language = Some("en")))) - - // check position - val position = childNodeInfo.position - position should be (0) - - // check has root node - val rootNode = childNodeInfo.hasRootNode - rootNode should be (newListIri.get) - - thirdChildIri.set(childNodeInfo.id) - } - - - "change node order" ignore { - - } - - "delete node if not in use" ignore { - - } + parentNodeIri = newListIri.get, + createChildNodeRequest = CreateChildNodeApiRequestADM( + parentNodeIri = newListIri.get, + projectIri = IMAGES_PROJECT_IRI, + name = Some("second"), + labels = Seq(StringLiteralV2(value = "New Second Child List Node Value", language = Some("en"))), + comments = Seq(StringLiteralV2(value = "New Second Child List Node Comment", language = Some("en"))) + ), + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = SharedTestDataADM.imagesUser01, + apiRequestID = UUID.randomUUID + ) + + val received: ListNodeInfoGetResponseADM = expectMsgType[ListNodeInfoGetResponseADM](timeout) + val nodeInfo = received.nodeinfo + + // check correct node info + val childNodeInfo = nodeInfo match { + case info: ListChildNodeInfoADM => info + case something => fail(s"expecting ListChildNodeInfoADM but got ${something.getClass.toString} instead.") + } + + // check labels + val labels: Seq[StringLiteralV2] = childNodeInfo.labels.stringLiterals + labels.size should be(1) + labels.sorted should be(Seq(StringLiteralV2(value = "New Second Child List Node Value", language = Some("en")))) + + + // check comments + val comments = childNodeInfo.comments.stringLiterals + comments.size should be(1) + comments.sorted should be(Seq(StringLiteralV2(value = "New Second Child List Node Comment", language = Some("en")))) + + // check position + val position = childNodeInfo.position + position should be(1) + + // check has root node + val rootNode = childNodeInfo.hasRootNode + rootNode should be(newListIri.get) + + secondChildIri.set(childNodeInfo.id) + } + + "add child to second child node" in { + responderManager ! ListChildNodeCreateRequestADM( + parentNodeIri = secondChildIri.get, + createChildNodeRequest = CreateChildNodeApiRequestADM( + parentNodeIri = secondChildIri.get, + projectIri = IMAGES_PROJECT_IRI, + name = Some("third"), + labels = Seq(StringLiteralV2(value = "New Third Child List Node Value", language = Some("en"))), + comments = Seq(StringLiteralV2(value = "New Third Child List Node Comment", language = Some("en"))) + ), + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = SharedTestDataADM.imagesUser01, + apiRequestID = UUID.randomUUID + ) + + val received: ListNodeInfoGetResponseADM = expectMsgType[ListNodeInfoGetResponseADM](timeout) + val nodeInfo = received.nodeinfo + + // check correct node info + val childNodeInfo = nodeInfo match { + case info: ListChildNodeInfoADM => info + case something => fail(s"expecting ListChildNodeInfoADM but got ${something.getClass.toString} instead.") + } + + // check labels + val labels: Seq[StringLiteralV2] = childNodeInfo.labels.stringLiterals + labels.size should be(1) + labels.sorted should be(Seq(StringLiteralV2(value = "New Third Child List Node Value", language = Some("en")))) + + + // check comments + val comments = childNodeInfo.comments.stringLiterals + comments.size should be(1) + comments.sorted should be(Seq(StringLiteralV2(value = "New Third Child List Node Comment", language = Some("en")))) + + // check position + val position = childNodeInfo.position + position should be(0) + + // check has root node + val rootNode = childNodeInfo.hasRootNode + rootNode should be(newListIri.get) + + thirdChildIri.set(childNodeInfo.id) + } + + + "change node order" ignore { + + } + + "delete node if not in use" ignore { + + } } } diff --git a/webapi/src/test/scala/org/knora/webapi/responders/admin/PermissionsResponderADMSpec.scala b/webapi/src/test/scala/org/knora/webapi/responders/admin/PermissionsResponderADMSpec.scala index c56d3fb6e8..31e7ea373c 100644 --- a/webapi/src/test/scala/org/knora/webapi/responders/admin/PermissionsResponderADMSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/responders/admin/PermissionsResponderADMSpec.scala @@ -21,7 +21,7 @@ package org.knora.webapi.responders.admin import java.util.UUID -import akka.actor.Status.{Failure, Success} +import akka.actor.Status.Failure import akka.testkit.ImplicitSender import com.typesafe.config.{Config, ConfigFactory} import org.knora.webapi._ @@ -32,7 +32,7 @@ import org.knora.webapi.messages.util.KnoraSystemInstances import org.knora.webapi.messages.{OntologyConstants, StringFormatter} import org.knora.webapi.sharedtestdata.SharedOntologyTestDataADM._ import org.knora.webapi.sharedtestdata.SharedPermissionsTestData._ -import org.knora.webapi.sharedtestdata.SharedTestDataADM.{ANYTHING_PROJECT_IRI, _} +import org.knora.webapi.sharedtestdata.SharedTestDataADM._ import org.knora.webapi.sharedtestdata.{SharedOntologyTestDataADM, SharedTestDataADM, SharedTestDataV1} import org.knora.webapi.util.cache.CacheUtil import org.scalatest.PrivateMethodTester @@ -83,6 +83,7 @@ class PermissionsResponderADMSpec extends CoreSpec(PermissionsResponderADMSpec.c groupIris = SharedTestDataV1.rootUser.groups, isInProjectAdminGroups = Seq.empty[IRI], isInSystemAdminGroup = true, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser ) expectMsg(SharedTestDataV1.rootUser.permissionData) @@ -94,6 +95,7 @@ class PermissionsResponderADMSpec extends CoreSpec(PermissionsResponderADMSpec.c groupIris = SharedTestDataV1.multiuserUser.groups, isInProjectAdminGroups = Seq(INCUNABULA_PROJECT_IRI, IMAGES_PROJECT_IRI), isInSystemAdminGroup = false, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser ) expectMsg(SharedTestDataV1.multiuserUser.permissionData) @@ -105,6 +107,7 @@ class PermissionsResponderADMSpec extends CoreSpec(PermissionsResponderADMSpec.c groupIris = SharedTestDataV1.incunabulaProjectAdminUser.groups, isInProjectAdminGroups = Seq(INCUNABULA_PROJECT_IRI), isInSystemAdminGroup = false, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser ) expectMsg(SharedTestDataV1.incunabulaProjectAdminUser.permissionData) @@ -116,6 +119,7 @@ class PermissionsResponderADMSpec extends CoreSpec(PermissionsResponderADMSpec.c groupIris = SharedTestDataV1.incunabulaCreatorUser.groups, isInProjectAdminGroups = Seq.empty[IRI], isInSystemAdminGroup = false, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser ) expectMsg(SharedTestDataV1.incunabulaCreatorUser.permissionData) @@ -127,6 +131,7 @@ class PermissionsResponderADMSpec extends CoreSpec(PermissionsResponderADMSpec.c groupIris = SharedTestDataV1.incunabulaMemberUser.groups, isInProjectAdminGroups = Seq.empty[IRI], isInSystemAdminGroup = false, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser ) expectMsg(SharedTestDataV1.incunabulaMemberUser.permissionData) @@ -138,6 +143,7 @@ class PermissionsResponderADMSpec extends CoreSpec(PermissionsResponderADMSpec.c groupIris = SharedTestDataV1.imagesUser01.groups, isInProjectAdminGroups = Seq(IMAGES_PROJECT_IRI), isInSystemAdminGroup = false, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser ) expectMsg(SharedTestDataV1.imagesUser01.permissionData) @@ -149,6 +155,7 @@ class PermissionsResponderADMSpec extends CoreSpec(PermissionsResponderADMSpec.c groupIris = SharedTestDataV1.imagesReviewerUser.groups, isInProjectAdminGroups = Seq.empty[IRI], isInSystemAdminGroup = false, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser ) expectMsg(SharedTestDataV1.imagesReviewerUser.permissionData) @@ -160,6 +167,7 @@ class PermissionsResponderADMSpec extends CoreSpec(PermissionsResponderADMSpec.c groupIris = SharedTestDataV1.anythingUser1.groups, isInProjectAdminGroups = Seq.empty[IRI], isInSystemAdminGroup = false, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser ) expectMsg(SharedTestDataV1.anythingUser1.permissionData) @@ -213,6 +221,7 @@ class PermissionsResponderADMSpec extends CoreSpec(PermissionsResponderADMSpec.c forGroup = OntologyConstants.KnoraAdmin.ProjectMember, hasPermissions = Set(PermissionADM.ProjectResourceCreateAllPermission) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = rootUser, apiRequestID = UUID.randomUUID() ) @@ -227,6 +236,7 @@ class PermissionsResponderADMSpec extends CoreSpec(PermissionsResponderADMSpec.c forGroup = SharedTestDataADM.thingSearcherGroup.id, hasPermissions = Set(PermissionADM.ProjectResourceCreateAllPermission) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = rootUser, apiRequestID = UUID.randomUUID() ) @@ -348,6 +358,7 @@ class PermissionsResponderADMSpec extends CoreSpec(PermissionsResponderADMSpec.c forGroup = Some(SharedTestDataADM.thingSearcherGroup.id), hasPermissions = Set(PermissionADM.restrictedViewPermission(SharedTestDataADM.thingSearcherGroup.id)) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = rootUser, apiRequestID = UUID.randomUUID() ) @@ -365,6 +376,7 @@ class PermissionsResponderADMSpec extends CoreSpec(PermissionsResponderADMSpec.c forGroup = Some(OntologyConstants.KnoraAdmin.UnknownUser), hasPermissions = Set(PermissionADM.restrictedViewPermission(OntologyConstants.KnoraAdmin.UnknownUser)) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = rootUser, apiRequestID = UUID.randomUUID() ) @@ -382,6 +394,7 @@ class PermissionsResponderADMSpec extends CoreSpec(PermissionsResponderADMSpec.c forResourceClass = Some(SharedOntologyTestDataADM.IMAGES_BILD_RESOURCE_CLASS), hasPermissions = Set(PermissionADM.modifyPermission(OntologyConstants.KnoraAdmin.KnownUser)) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = rootUser, apiRequestID = UUID.randomUUID() ) @@ -399,6 +412,7 @@ class PermissionsResponderADMSpec extends CoreSpec(PermissionsResponderADMSpec.c forProperty = Some(SharedOntologyTestDataADM.IMAGES_TITEL_PROPERTY), hasPermissions = Set(PermissionADM.changeRightsPermission(OntologyConstants.KnoraAdmin.Creator)) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = rootUser, apiRequestID = UUID.randomUUID() ) @@ -415,6 +429,7 @@ class PermissionsResponderADMSpec extends CoreSpec(PermissionsResponderADMSpec.c forGroup = Some(OntologyConstants.KnoraAdmin.ProjectMember), hasPermissions = Set(PermissionADM.changeRightsPermission(OntologyConstants.KnoraAdmin.ProjectMember)) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = rootUser, apiRequestID = UUID.randomUUID() ) @@ -427,6 +442,7 @@ class PermissionsResponderADMSpec extends CoreSpec(PermissionsResponderADMSpec.c "return all permissions for 'image' project " in { responderManager ! PermissionsForProjectGetRequestADM( projectIri = IMAGES_PROJECT_IRI, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = rootUser, apiRequestID = UUID.randomUUID() ) @@ -437,6 +453,7 @@ class PermissionsResponderADMSpec extends CoreSpec(PermissionsResponderADMSpec.c "return all permissions for 'incunabula' project " in { responderManager ! PermissionsForProjectGetRequestADM( projectIri = INCUNABULA_PROJECT_IRI, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = rootUser, apiRequestID = UUID.randomUUID() ) diff --git a/webapi/src/test/scala/org/knora/webapi/responders/admin/ProjectsResponderADMSpec.scala b/webapi/src/test/scala/org/knora/webapi/responders/admin/ProjectsResponderADMSpec.scala index df0b717a6a..8c868c4ba5 100644 --- a/webapi/src/test/scala/org/knora/webapi/responders/admin/ProjectsResponderADMSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/responders/admin/ProjectsResponderADMSpec.scala @@ -18,9 +18,9 @@ */ /** - * To be able to test UsersResponder, we need to be able to start UsersResponder isolated. Now the UsersResponder - * extend ResponderADM which messes up testing, as we cannot inject the TestActor system. - */ + * To be able to test UsersResponder, we need to be able to start UsersResponder isolated. Now the UsersResponder + * extend ResponderADM which messes up testing, as we cannot inject the TestActor system. + */ package org.knora.webapi.responders.admin import java.util.UUID @@ -30,12 +30,12 @@ import akka.testkit.ImplicitSender import com.typesafe.config.{Config, ConfigFactory} import org.knora.webapi._ import org.knora.webapi.exceptions.{BadRequestException, DuplicateValueException, NotFoundException} +import org.knora.webapi.messages.StringFormatter import org.knora.webapi.messages.admin.responder.projectsmessages._ import org.knora.webapi.messages.admin.responder.usersmessages.UserInformationTypeADM import org.knora.webapi.messages.store.triplestoremessages._ -import org.knora.webapi.util.MutableTestIri -import org.knora.webapi.messages.StringFormatter import org.knora.webapi.sharedtestdata.SharedTestDataADM +import org.knora.webapi.util.MutableTestIri import scala.concurrent.duration._ @@ -50,14 +50,14 @@ object ProjectsResponderADMSpec { } /** - * This spec is used to test the messages received by the [[ProjectsResponderADM]] actor. - */ + * This spec is used to test the messages received by the [[ProjectsResponderADM]] actor. + */ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) with ImplicitSender { private implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance private val timeout = 5.seconds - private val rootUser= SharedTestDataADM.rootUser + private val rootUser = SharedTestDataADM.rootUser "The ProjectsResponderADM" when { @@ -65,7 +65,10 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "return information for every project" in { - responderManager ! ProjectsGetRequestADM(rootUser) + responderManager ! ProjectsGetRequestADM( + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = rootUser + ) val received = expectMsgType[ProjectsGetResponseADM](timeout) assert(received.projects.contains(SharedTestDataADM.imagesProject)) @@ -76,21 +79,24 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) /* Incunabula project */ responderManager ! ProjectGetRequestADM( - ProjectIdentifierADM(maybeIri = Some(SharedTestDataADM.incunabulaProject.id)), + identifier = ProjectIdentifierADM(maybeIri = Some(SharedTestDataADM.incunabulaProject.id)), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) expectMsg(ProjectGetResponseADM(SharedTestDataADM.incunabulaProject)) /* Images project */ responderManager ! ProjectGetRequestADM( - ProjectIdentifierADM(maybeIri = Some(SharedTestDataADM.imagesProject.id)), + identifier = ProjectIdentifierADM(maybeIri = Some(SharedTestDataADM.imagesProject.id)), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) expectMsg(ProjectGetResponseADM(SharedTestDataADM.imagesProject)) /* 'SystemProject' */ responderManager ! ProjectGetRequestADM( - ProjectIdentifierADM(maybeIri = Some(SharedTestDataADM.systemProject.id)), + identifier = ProjectIdentifierADM(maybeIri = Some(SharedTestDataADM.systemProject.id)), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) expectMsg(ProjectGetResponseADM(SharedTestDataADM.systemProject)) @@ -99,7 +105,8 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "return information about a project identified by shortname" in { responderManager ! ProjectGetRequestADM( - ProjectIdentifierADM(maybeShortname = Some(SharedTestDataADM.incunabulaProject.shortname)), + identifier = ProjectIdentifierADM(maybeShortname = Some(SharedTestDataADM.incunabulaProject.shortname)), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) expectMsg(ProjectGetResponseADM(SharedTestDataADM.incunabulaProject)) @@ -108,7 +115,8 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "return 'NotFoundException' when the project IRI is unknown" in { responderManager ! ProjectGetRequestADM( - ProjectIdentifierADM(maybeIri = Some("http://rdfh.ch/projects/notexisting")), + identifier = ProjectIdentifierADM(maybeIri = Some("http://rdfh.ch/projects/notexisting")), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) expectMsg(Failure(NotFoundException(s"Project 'http://rdfh.ch/projects/notexisting' not found"))) @@ -117,7 +125,8 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "return 'NotFoundException' when the project shortname is unknown " in { responderManager ! ProjectGetRequestADM( - ProjectIdentifierADM(maybeShortname = Some("wrongshortname")), + identifier = ProjectIdentifierADM(maybeShortname = Some("wrongshortname")), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) expectMsg(Failure(NotFoundException(s"Project 'wrongshortname' not found"))) @@ -125,7 +134,8 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "return 'NotFoundException' when the project shortcode is unknown " in { responderManager ! ProjectGetRequestADM( - ProjectIdentifierADM(maybeShortcode = Some("9999")), + identifier = ProjectIdentifierADM(maybeShortcode = Some("9999")), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) expectMsg(Failure(NotFoundException(s"Project '9999' not found"))) @@ -139,6 +149,7 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "return restricted view settings using project IRI" in { responderManager ! ProjectRestrictedViewSettingsGetADM( identifier = ProjectIdentifierADM(maybeIri = Some(SharedTestDataADM.imagesProject.id)), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) expectMsg(Some(expectedResult)) @@ -147,6 +158,7 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "return restricted view settings using project SHORTNAME" in { responderManager ! ProjectRestrictedViewSettingsGetADM( identifier = ProjectIdentifierADM(maybeShortname = Some(SharedTestDataADM.imagesProject.shortname)), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) expectMsg(Some(expectedResult)) @@ -155,6 +167,7 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "return restricted view settings using project SHORTCODE" in { responderManager ! ProjectRestrictedViewSettingsGetADM( identifier = ProjectIdentifierADM(maybeShortcode = Some(SharedTestDataADM.imagesProject.shortcode)), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) expectMsg(Some(expectedResult)) @@ -163,6 +176,7 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "return 'NotFoundException' when the project IRI is unknown" in { responderManager ! ProjectRestrictedViewSettingsGetRequestADM( identifier = ProjectIdentifierADM(maybeIri = Some("http://rdfh.ch/projects/notexisting")), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) expectMsg(Failure(NotFoundException(s"Project 'http://rdfh.ch/projects/notexisting' not found."))) @@ -171,6 +185,7 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "return 'NotFoundException' when the project SHORTCODE is unknown" in { responderManager ! ProjectRestrictedViewSettingsGetRequestADM( identifier = ProjectIdentifierADM(maybeShortcode = Some("9999")), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) expectMsg(Failure(NotFoundException(s"Project '9999' not found."))) @@ -179,6 +194,7 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "return 'NotFoundException' when the project SHORTNAME is unknown" in { responderManager ! ProjectRestrictedViewSettingsGetRequestADM( identifier = ProjectIdentifierADM(maybeShortname = Some("wrongshortname")), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) expectMsg(Failure(NotFoundException(s"Project 'wrongshortname' not found."))) @@ -202,6 +218,7 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) status = true, selfjoin = false ), + featureFactoryConfig = defaultFeatureFactoryConfig, SharedTestDataADM.rootUser, UUID.randomUUID() ) @@ -228,6 +245,7 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) status = true, selfjoin = false ), + featureFactoryConfig = defaultFeatureFactoryConfig, SharedTestDataADM.rootUser, UUID.randomUUID() ) @@ -253,6 +271,7 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) status = true, selfjoin = false ), + featureFactoryConfig = defaultFeatureFactoryConfig, SharedTestDataADM.rootUser, UUID.randomUUID() ) @@ -271,6 +290,7 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) status = true, selfjoin = false ), + featureFactoryConfig = defaultFeatureFactoryConfig, SharedTestDataADM.rootUser, UUID.randomUUID() ) @@ -290,6 +310,7 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) status = true, selfjoin = false ), + featureFactoryConfig = defaultFeatureFactoryConfig, SharedTestDataADM.rootUser, UUID.randomUUID() ) @@ -309,6 +330,7 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) status = true, selfjoin = false ), + featureFactoryConfig = defaultFeatureFactoryConfig, SharedTestDataADM.rootUser, UUID.randomUUID() ) @@ -327,24 +349,26 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) status = Some(false), selfjoin = Some(true) ), + featureFactoryConfig = defaultFeatureFactoryConfig, SharedTestDataADM.rootUser, UUID.randomUUID() ) val received: ProjectOperationResponseADM = expectMsgType[ProjectOperationResponseADM](timeout) received.project.shortname should be("newproject") received.project.shortcode should be("111C") - received.project.longname should be (Some("updated project longname")) - received.project.description should be (Seq(StringLiteralV2(value = """updated project description with "quotes" and """, language = Some("en")))) - received.project.keywords.sorted should be (Seq("updated", "keywords").sorted) - received.project.logo should be (Some("/fu/bar/baz-updated.jpg")) - received.project.status should be (false) - received.project.selfjoin should be (true) + received.project.longname should be(Some("updated project longname")) + received.project.description should be(Seq(StringLiteralV2(value = """updated project description with "quotes" and """, language = Some("en")))) + received.project.keywords.sorted should be(Seq("updated", "keywords").sorted) + received.project.logo should be(Some("/fu/bar/baz-updated.jpg")) + received.project.status should be(false) + received.project.selfjoin should be(true) } "return 'NotFound' if a not existing project IRI is submitted during update" in { responderManager ! ProjectChangeRequestADM( projectIri = "http://rdfh.ch/projects/notexisting", changeProjectRequest = ChangeProjectApiRequestADM(longname = Some("new long name")), + featureFactoryConfig = defaultFeatureFactoryConfig, SharedTestDataADM.rootUser, UUID.randomUUID() ) @@ -353,7 +377,7 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "return 'BadRequest' if nothing would be changed during the update" in { - an [BadRequestException] should be thrownBy ChangeProjectApiRequestADM(None, None, None, None, None, None, None) + an[BadRequestException] should be thrownBy ChangeProjectApiRequestADM(None, None, None, None, None, None, None) /* actorUnderTest ! ProjectChangeRequestADM( @@ -380,6 +404,7 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) actorUnderTest ! ProjectOntologyAddADM( projectIri = IMAGES_PROJECT_IRI, ontologyIri = "http://wwww.knora.org/ontology/00FF/blabla1", + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser, apiRequestID = UUID.randomUUID() ) @@ -399,12 +424,13 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "return all members of a project identified by IRI" in { responderManager ! ProjectMembersGetRequestADM( ProjectIdentifierADM(maybeIri = Some(SharedTestDataADM.imagesProject.id)), + featureFactoryConfig = defaultFeatureFactoryConfig, SharedTestDataADM.rootUser ) val received: ProjectMembersGetResponseADM = expectMsgType[ProjectMembersGetResponseADM](timeout) val members = received.members - members.size should be (4) + members.size should be(4) members.map(_.id) should contain allElementsOf Seq( SharedTestDataADM.imagesUser01.ofType(UserInformationTypeADM.RESTRICTED), @@ -417,12 +443,13 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "return all members of a project identified by shortname" in { responderManager ! ProjectMembersGetRequestADM( ProjectIdentifierADM(maybeShortname = Some(SharedTestDataADM.imagesProject.shortname)), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) val received: ProjectMembersGetResponseADM = expectMsgType[ProjectMembersGetResponseADM](timeout) val members = received.members - members.size should be (4) + members.size should be(4) members.map(_.id) should contain allElementsOf Seq( SharedTestDataADM.imagesUser01.ofType(UserInformationTypeADM.SHORT), @@ -435,12 +462,13 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "return all members of a project identified by shortcode" in { responderManager ! ProjectMembersGetRequestADM( ProjectIdentifierADM(maybeShortcode = Some(SharedTestDataADM.imagesProject.shortcode)), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) val received: ProjectMembersGetResponseADM = expectMsgType[ProjectMembersGetResponseADM](timeout) val members = received.members - members.size should be (4) + members.size should be(4) members.map(_.id) should contain allElementsOf Seq( SharedTestDataADM.imagesUser01.ofType(UserInformationTypeADM.SHORT), @@ -453,6 +481,7 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "return 'NotFound' when the project IRI is unknown (project membership)" in { responderManager ! ProjectMembersGetRequestADM( ProjectIdentifierADM(maybeIri = Some("http://rdfh.ch/projects/notexisting")), + featureFactoryConfig = defaultFeatureFactoryConfig, SharedTestDataADM.rootUser ) expectMsg(Failure(NotFoundException(s"Project 'http://rdfh.ch/projects/notexisting' not found."))) @@ -461,6 +490,7 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "return 'NotFound' when the project shortname is unknown (project membership)" in { responderManager ! ProjectMembersGetRequestADM( ProjectIdentifierADM(maybeShortname = Some("wrongshortname")), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) expectMsg(Failure(NotFoundException(s"Project 'wrongshortname' not found."))) @@ -469,6 +499,7 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "return 'NotFound' when the project shortcode is unknown (project membership)" in { responderManager ! ProjectMembersGetRequestADM( ProjectIdentifierADM(maybeShortcode = Some("9999")), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) expectMsg(Failure(NotFoundException(s"Project '9999' not found."))) @@ -477,12 +508,13 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "return all project admin members of a project identified by IRI" in { responderManager ! ProjectAdminMembersGetRequestADM( ProjectIdentifierADM(maybeIri = Some(SharedTestDataADM.imagesProject.id)), + featureFactoryConfig = defaultFeatureFactoryConfig, SharedTestDataADM.rootUser ) val received: ProjectAdminMembersGetResponseADM = expectMsgType[ProjectAdminMembersGetResponseADM](timeout) val members = received.members - members.size should be (2) + members.size should be(2) members.map(_.id) should contain allElementsOf Seq( SharedTestDataADM.imagesUser01.ofType(UserInformationTypeADM.SHORT), @@ -493,12 +525,13 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "return all project admin members of a project identified by shortname" in { responderManager ! ProjectAdminMembersGetRequestADM( ProjectIdentifierADM(maybeShortname = Some(SharedTestDataADM.imagesProject.shortname)), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) val received: ProjectAdminMembersGetResponseADM = expectMsgType[ProjectAdminMembersGetResponseADM](timeout) val members = received.members - members.size should be (2) + members.size should be(2) members.map(_.id) should contain allElementsOf Seq( SharedTestDataADM.imagesUser01.ofType(UserInformationTypeADM.SHORT), @@ -509,12 +542,13 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "return all project admin members of a project identified by shortcode" in { responderManager ! ProjectAdminMembersGetRequestADM( ProjectIdentifierADM(maybeShortcode = Some(SharedTestDataADM.imagesProject.shortcode)), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) val received: ProjectAdminMembersGetResponseADM = expectMsgType[ProjectAdminMembersGetResponseADM](timeout) val members = received.members - members.size should be (2) + members.size should be(2) members.map(_.id) should contain allElementsOf Seq( SharedTestDataADM.imagesUser01.ofType(UserInformationTypeADM.SHORT), @@ -525,6 +559,7 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "return 'NotFound' when the project IRI is unknown (project admin membership)" in { responderManager ! ProjectAdminMembersGetRequestADM( ProjectIdentifierADM(maybeIri = Some("http://rdfh.ch/projects/notexisting")), + featureFactoryConfig = defaultFeatureFactoryConfig, SharedTestDataADM.rootUser ) expectMsg(Failure(NotFoundException(s"Project 'http://rdfh.ch/projects/notexisting' not found."))) @@ -533,6 +568,7 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "return 'NotFound' when the project shortname is unknown (project admin membership)" in { responderManager ! ProjectAdminMembersGetRequestADM( ProjectIdentifierADM(maybeShortname = Some("wrongshortname")), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) expectMsg(Failure(NotFoundException(s"Project 'wrongshortname' not found."))) @@ -541,6 +577,7 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "return 'NotFound' when the project shortcode is unknown (project admin membership)" in { responderManager ! ProjectAdminMembersGetRequestADM( ProjectIdentifierADM(maybeShortcode = Some("9999")), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) expectMsg(Failure(NotFoundException(s"Project '9999' not found."))) @@ -550,32 +587,38 @@ class ProjectsResponderADMSpec extends CoreSpec(ProjectsResponderADMSpec.config) "used to query keywords" should { "return all unique keywords for all projects" in { - responderManager ! ProjectsKeywordsGetRequestADM(SharedTestDataADM.rootUser) + responderManager ! ProjectsKeywordsGetRequestADM( + featureFactoryConfig = defaultFeatureFactoryConfig, + SharedTestDataADM.rootUser + ) val received: ProjectsKeywordsGetResponseADM = expectMsgType[ProjectsKeywordsGetResponseADM](timeout) - received.keywords.size should be (20) + received.keywords.size should be(20) } "return all keywords for a single project" in { responderManager ! ProjectKeywordsGetRequestADM( projectIri = SharedTestDataADM.incunabulaProject.id, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) val received: ProjectKeywordsGetResponseADM = expectMsgType[ProjectKeywordsGetResponseADM](timeout) - received.keywords should be (SharedTestDataADM.incunabulaProject.keywords) + received.keywords should be(SharedTestDataADM.incunabulaProject.keywords) } "return empty list for a project without keywords" in { responderManager ! ProjectKeywordsGetRequestADM( projectIri = SharedTestDataADM.dokubibProject.id, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser ) val received: ProjectKeywordsGetResponseADM = expectMsgType[ProjectKeywordsGetResponseADM](timeout) - received.keywords should be (Seq.empty[String]) + received.keywords should be(Seq.empty[String]) } "return 'NotFound' when the project IRI is unknown" in { responderManager ! ProjectKeywordsGetRequestADM( projectIri = "http://rdfh.ch/projects/notexisting", + featureFactoryConfig = defaultFeatureFactoryConfig, SharedTestDataADM.rootUser ) diff --git a/webapi/src/test/scala/org/knora/webapi/responders/admin/SipiResponderADMSpec.scala b/webapi/src/test/scala/org/knora/webapi/responders/admin/SipiResponderADMSpec.scala index 3259fbfb97..b1dc537aea 100644 --- a/webapi/src/test/scala/org/knora/webapi/responders/admin/SipiResponderADMSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/responders/admin/SipiResponderADMSpec.scala @@ -38,8 +38,8 @@ object SipiResponderADMSpec { } /** - * Tests [[SipiResponderADM]]. - */ + * Tests [[SipiResponderADM]]. + */ class SipiResponderADMSpec extends CoreSpec(SipiResponderADMSpec.config) with ImplicitSender { override lazy val rdfDataObjects = List( @@ -53,9 +53,10 @@ class SipiResponderADMSpec extends CoreSpec(SipiResponderADMSpec.config) with Im "return details of a full quality file value" in { // http://localhost:3333/v1/files/http%3A%2F%2Frdfh.ch%2F8a0b1e75%2Freps%2F7e4ba672 responderManager ! SipiFileInfoGetRequestADM( - requestingUser = SharedTestDataADM.incunabulaMemberUser, projectID = "0803", - filename = "incunabula_0000003328.jp2" + filename = "incunabula_0000003328.jp2", + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = SharedTestDataADM.incunabulaMemberUser ) expectMsg(timeout, SipiFileInfoGetResponseADM(permissionCode = 6, None)) @@ -64,12 +65,13 @@ class SipiResponderADMSpec extends CoreSpec(SipiResponderADMSpec.config) with Im "return details of a restricted view file value" in { // http://localhost:3333/v1/files/http%3A%2F%2Frdfh.ch%2F8a0b1e75%2Freps%2F7e4ba672 responderManager ! SipiFileInfoGetRequestADM( - requestingUser = SharedTestDataADM.anonymousUser, projectID = "0803", - filename = "incunabula_0000003328.jp2" + filename = "incunabula_0000003328.jp2", + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = SharedTestDataADM.anonymousUser ) - expectMsg(timeout, SipiFileInfoGetResponseADM(permissionCode = 1, Some(ProjectRestrictedViewSettingsADM(size=Some("!512,512"), watermark = Some("path_to_image"))))) + expectMsg(timeout, SipiFileInfoGetResponseADM(permissionCode = 1, Some(ProjectRestrictedViewSettingsADM(size = Some("!512,512"), watermark = Some("path_to_image"))))) } } } diff --git a/webapi/src/test/scala/org/knora/webapi/responders/admin/UsersResponderADMSpec.scala b/webapi/src/test/scala/org/knora/webapi/responders/admin/UsersResponderADMSpec.scala index 722432aa0c..d14edc56c8 100644 --- a/webapi/src/test/scala/org/knora/webapi/responders/admin/UsersResponderADMSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/responders/admin/UsersResponderADMSpec.scala @@ -17,10 +17,6 @@ * License along with Knora. If not, see . */ -/** - * To be able to test UsersResponder, we need to be able to start UsersResponder isolated. Now the UsersResponder - * extend ResponderADM which messes up testing, as we cannot inject the TestActor system. - */ package org.knora.webapi.responders.admin import java.util.UUID @@ -53,8 +49,8 @@ object UsersResponderADMSpec { } /** - * This spec is used to test the messages received by the [[UsersResponderADM]] actor. - */ + * This spec is used to test the messages received by the [[UsersResponderADM]] actor. + */ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with ImplicitSender with Authenticator { private val timeout: FiniteDuration = 8.seconds @@ -74,31 +70,35 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with "asked about all users" should { "return a list if asked by SystemAdmin" in { - responderManager ! UsersGetRequestADM(requestingUser = rootUser) + responderManager ! UsersGetRequestADM(featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = rootUser) val response = expectMsgType[UsersGetResponseADM](timeout) - response.users.nonEmpty should be (true) - response.users.size should be (18) + response.users.nonEmpty should be(true) + response.users.size should be(18) } "return a list if asked by ProjectAdmin" in { - responderManager ! UsersGetRequestADM(requestingUser = anythingAdminUser) + responderManager ! UsersGetRequestADM(featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = anythingAdminUser) val response = expectMsgType[UsersGetResponseADM](timeout) - response.users.nonEmpty should be (true) - response.users.size should be (18) + response.users.nonEmpty should be(true) + response.users.size should be(18) } "return 'ForbiddenException' if asked by normal user'" in { - responderManager ! UsersGetRequestADM(requestingUser = normalUser) + responderManager ! UsersGetRequestADM(featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = normalUser) expectMsg(timeout, Failure(ForbiddenException("ProjectAdmin or SystemAdmin permissions are required."))) } "not return the system and anonymous users" in { - responderManager ! UsersGetRequestADM(requestingUser = rootUser) + responderManager ! UsersGetRequestADM(featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = rootUser) val response = expectMsgType[UsersGetResponseADM](timeout) - response.users.nonEmpty should be (true) - response.users.size should be (18) - response.users.count(_.id == KnoraSystemInstances.Users.AnonymousUser.id) should be (0) - response.users.count(_.id == KnoraSystemInstances.Users.SystemUser.id) should be (0) + response.users.nonEmpty should be(true) + response.users.size should be(18) + response.users.count(_.id == KnoraSystemInstances.Users.AnonymousUser.id) should be(0) + response.users.count(_.id == KnoraSystemInstances.Users.SystemUser.id) should be(0) } } @@ -108,6 +108,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with responderManager ! UserGetADM( identifier = UserIdentifierADM(maybeIri = Some(rootUser.id)), userInformationTypeADM = UserInformationTypeADM.FULL, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser ) expectMsg(Some(rootUser.ofType(UserInformationTypeADM.FULL))) @@ -117,6 +118,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with responderManager ! UserGetADM( identifier = UserIdentifierADM(maybeIri = Some(incunabulaUser.id)), userInformationTypeADM = UserInformationTypeADM.FULL, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser ) expectMsg(Some(incunabulaUser.ofType(UserInformationTypeADM.FULL))) @@ -126,6 +128,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with responderManager ! UserGetRequestADM( identifier = UserIdentifierADM(maybeIri = Some("http://rdfh.ch/users/notexisting")), userInformationTypeADM = UserInformationTypeADM.FULL, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser ) expectMsg(Failure(NotFoundException(s"User 'http://rdfh.ch/users/notexisting' not found"))) @@ -135,6 +138,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with responderManager ! UserGetADM( identifier = UserIdentifierADM(maybeIri = Some("http://rdfh.ch/users/notexisting")), userInformationTypeADM = UserInformationTypeADM.FULL, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser ) expectMsg(None) @@ -147,6 +151,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with responderManager ! UserGetADM( identifier = UserIdentifierADM(maybeEmail = Some(rootUser.email)), userInformationTypeADM = UserInformationTypeADM.FULL, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser ) expectMsg(Some(rootUser.ofType(UserInformationTypeADM.FULL))) @@ -156,6 +161,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with responderManager ! UserGetADM( identifier = UserIdentifierADM(maybeEmail = Some(incunabulaUser.email)), userInformationTypeADM = UserInformationTypeADM.FULL, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser ) expectMsg(Some(incunabulaUser.ofType(UserInformationTypeADM.FULL))) @@ -165,6 +171,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with responderManager ! UserGetRequestADM( identifier = UserIdentifierADM(maybeEmail = Some("userwrong@example.com")), userInformationTypeADM = UserInformationTypeADM.FULL, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser ) expectMsg(Failure(NotFoundException(s"User 'userwrong@example.com' not found"))) @@ -174,6 +181,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with responderManager ! UserGetADM( identifier = UserIdentifierADM(maybeEmail = Some("userwrong@example.com")), userInformationTypeADM = UserInformationTypeADM.FULL, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser ) expectMsg(None) @@ -186,6 +194,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with responderManager ! UserGetADM( identifier = UserIdentifierADM(maybeUsername = Some(rootUser.username)), userInformationTypeADM = UserInformationTypeADM.FULL, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser ) expectMsg(Some(rootUser.ofType(UserInformationTypeADM.FULL))) @@ -195,6 +204,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with responderManager ! UserGetADM( identifier = UserIdentifierADM(maybeUsername = Some(incunabulaUser.username)), userInformationTypeADM = UserInformationTypeADM.FULL, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser ) expectMsg(Some(incunabulaUser.ofType(UserInformationTypeADM.FULL))) @@ -204,6 +214,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with responderManager ! UserGetRequestADM( identifier = UserIdentifierADM(maybeUsername = Some("userwrong")), userInformationTypeADM = UserInformationTypeADM.FULL, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser ) expectMsg(Failure(NotFoundException(s"User 'userwrong' not found"))) @@ -213,6 +224,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with responderManager ! UserGetADM( identifier = UserIdentifierADM(maybeUsername = Some("userwrong")), userInformationTypeADM = UserInformationTypeADM.FULL, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser ) expectMsg(None) @@ -233,6 +245,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with lang = "en", systemAdmin = false ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.anonymousUser, apiRequestID = UUID.randomUUID ) @@ -257,6 +270,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with lang = "en", systemAdmin = false ), + featureFactoryConfig = defaultFeatureFactoryConfig, SharedTestDataADM.anonymousUser, UUID.randomUUID ) @@ -275,6 +289,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with lang = "en", systemAdmin = false ), + featureFactoryConfig = defaultFeatureFactoryConfig, SharedTestDataADM.anonymousUser, UUID.randomUUID ) @@ -293,6 +308,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with lang = "en", systemAdmin = false ), + featureFactoryConfig = defaultFeatureFactoryConfig, SharedTestDataADM.anonymousUser, UUID.randomUUID ) @@ -311,6 +327,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with lang = "en", systemAdmin = false ), + featureFactoryConfig = defaultFeatureFactoryConfig, SharedTestDataADM.anonymousUser, UUID.randomUUID ) @@ -329,6 +346,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with lang = "en", systemAdmin = false ), + featureFactoryConfig = defaultFeatureFactoryConfig, SharedTestDataADM.anonymousUser, UUID.randomUUID ) @@ -350,12 +368,13 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with familyName = None, lang = None ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.normalUser, UUID.randomUUID ) val response1 = expectMsgType[UserOperationResponseADM](timeout) - response1.user.givenName should equal ("Donald") + response1.user.givenName should equal("Donald") /* User information is updated by a system admin */ responderManager ! UserChangeBasicUserInformationRequestADM( @@ -366,12 +385,13 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with familyName = Some("Duck"), lang = None ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.superUser, UUID.randomUUID ) val response2 = expectMsgType[UserOperationResponseADM](timeout) - response2.user.familyName should equal ("Duck") + response2.user.familyName should equal("Duck") /* User information is updated by a system admin */ responderManager ! UserChangeBasicUserInformationRequestADM( @@ -382,22 +402,24 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with familyName = Some(SharedTestDataADM.normalUser.familyName), lang = None ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.superUser, UUID.randomUUID ) val response3 = expectMsgType[UserOperationResponseADM](timeout) - response3.user.givenName should equal (SharedTestDataADM.normalUser.givenName) - response3.user.familyName should equal (SharedTestDataADM.normalUser.familyName) + response3.user.givenName should equal(SharedTestDataADM.normalUser.givenName) + response3.user.familyName should equal(SharedTestDataADM.normalUser.familyName) } - + "return a 'DuplicateValueException' if the supplied 'username' is not unique" in { responderManager ! UserChangeBasicUserInformationRequestADM( userIri = SharedTestDataADM.normalUser.id, changeUserRequest = ChangeUserApiRequestADM( username = Some("root") ), + featureFactoryConfig = defaultFeatureFactoryConfig, SharedTestDataADM.superUser, UUID.randomUUID ) @@ -410,6 +432,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with changeUserRequest = ChangeUserApiRequestADM( email = Some("root@example.com") ), + featureFactoryConfig = defaultFeatureFactoryConfig, SharedTestDataADM.superUser, UUID.randomUUID ) @@ -423,6 +446,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with changeUserRequest = ChangeUserApiRequestADM( username = Some("donald.duck2@example.com") ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.superUser, UUID.randomUUID() ) @@ -437,6 +461,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with changeUserRequest = ChangeUserApiRequestADM( username = Some("donald-duck") ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.superUser, UUID.randomUUID() ) @@ -452,6 +477,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with changeUserRequest = ChangeUserApiRequestADM( email = Some("root3") ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.superUser, UUID.randomUUID() ) @@ -466,6 +492,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with requesterPassword = Some("test"), // of the requesting user newPassword = Some("test123456") ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.normalUser, apiRequestID = UUID.randomUUID() ) @@ -473,7 +500,10 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with expectMsgType[UserOperationResponseADM](timeout) // need to be able to authenticate credentials with new password - val resF = Authenticator.authenticateCredentialsV2(Some(KnoraPasswordCredentialsV2(UserIdentifierADM(maybeEmail = Some(normalUser.email)), "test123456")))(system, responderManager, executionContext) + val resF = Authenticator.authenticateCredentialsV2( + credentials = Some(KnoraPasswordCredentialsV2(UserIdentifierADM(maybeEmail = Some(normalUser.email)), "test123456")), + featureFactoryConfig = defaultFeatureFactoryConfig, + )(system, responderManager, executionContext) resF map { res => assert(res) } } @@ -485,6 +515,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with requesterPassword = Some("test"), // of the requesting user newPassword = Some("test654321") ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser, apiRequestID = UUID.randomUUID() ) @@ -492,7 +523,10 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with expectMsgType[UserOperationResponseADM](timeout) // need to be able to authenticate credentials with new password - val resF = Authenticator.authenticateCredentialsV2(Some(KnoraPasswordCredentialsV2(UserIdentifierADM(maybeEmail = Some(normalUser.email)), "test654321")))(system, responderManager, executionContext) + val resF = Authenticator.authenticateCredentialsV2( + credentials = Some(KnoraPasswordCredentialsV2(UserIdentifierADM(maybeEmail = Some(normalUser.email)), "test654321")), + featureFactoryConfig = defaultFeatureFactoryConfig, + )(system, responderManager, executionContext) resF map { res => assert(res) } } @@ -501,44 +535,48 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with responderManager ! UserChangeStatusRequestADM( userIri = SharedTestDataADM.normalUser.id, changeUserRequest = ChangeUserApiRequestADM(status = Some(false)), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.superUser, UUID.randomUUID() ) val response1 = expectMsgType[UserOperationResponseADM](timeout) - response1.user.status should equal (false) + response1.user.status should equal(false) responderManager ! UserChangeStatusRequestADM( userIri = SharedTestDataADM.normalUser.id, changeUserRequest = ChangeUserApiRequestADM(status = Some(true)), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.superUser, UUID.randomUUID() ) val response2 = expectMsgType[UserOperationResponseADM](timeout) - response2.user.status should equal (true) + response2.user.status should equal(true) } "UPDATE the user's system admin membership" in { responderManager ! UserChangeSystemAdminMembershipStatusRequestADM( userIri = SharedTestDataADM.normalUser.id, changeUserRequest = ChangeUserApiRequestADM(systemAdmin = Some(true)), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.superUser, UUID.randomUUID() ) val response1 = expectMsgType[UserOperationResponseADM](timeout) - response1.user.isSystemAdmin should equal (true) + response1.user.isSystemAdmin should equal(true) responderManager ! UserChangeSystemAdminMembershipStatusRequestADM( userIri = SharedTestDataADM.normalUser.id, changeUserRequest = ChangeUserApiRequestADM(systemAdmin = Some(false)), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.superUser, UUID.randomUUID() ) val response2 = expectMsgType[UserOperationResponseADM](timeout) - response2.user.permissions.isSystemAdmin should equal (false) + response2.user.permissions.isSystemAdmin should equal(false) } @@ -553,6 +591,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with familyName = None, lang = None ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.normalUser, UUID.randomUUID ) @@ -565,6 +604,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with requesterPassword = Some("test"), newPassword = Some("test123456") ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.normalUser, UUID.randomUUID ) @@ -574,6 +614,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with responderManager ! UserChangeStatusRequestADM( userIri = SharedTestDataADM.superUser.id, changeUserRequest = ChangeUserApiRequestADM(status = Some(false)), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.normalUser, UUID.randomUUID ) @@ -583,6 +624,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with responderManager ! UserChangeSystemAdminMembershipStatusRequestADM( userIri = SharedTestDataADM.normalUser.id, changeUserRequest = ChangeUserApiRequestADM(systemAdmin = Some(true)), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.normalUser, UUID.randomUUID() ) @@ -594,6 +636,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with responderManager ! UserChangeStatusRequestADM( userIri = KnoraSystemInstances.Users.SystemUser.id, changeUserRequest = ChangeUserApiRequestADM(status = Some(false)), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.superUser, UUID.randomUUID() ) @@ -606,6 +649,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with responderManager ! UserChangeStatusRequestADM( userIri = KnoraSystemInstances.Users.AnonymousUser.id, changeUserRequest = ChangeUserApiRequestADM(status = Some(false)), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.superUser, UUID.randomUUID() ) @@ -615,7 +659,7 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with "return 'BadRequest' if nothing would be changed during the update" in { - an [BadRequestException] should be thrownBy ChangeUserApiRequestADM(None, None, None, None, None, None, None, None) + an[BadRequestException] should be thrownBy ChangeUserApiRequestADM(None, None, None, None, None, None, None, None) } } @@ -623,42 +667,44 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with "ADD user to project" in { - responderManager ! UserProjectMembershipsGetRequestADM(normalUser.id, rootUser, UUID.randomUUID()) + responderManager ! UserProjectMembershipsGetRequestADM(normalUser.id, defaultFeatureFactoryConfig, rootUser) val membershipsBeforeUpdate = expectMsgType[UserProjectMembershipsGetResponseADM](timeout) - membershipsBeforeUpdate.projects should equal (Seq()) + membershipsBeforeUpdate.projects should equal(Seq()) - responderManager ! UserProjectMembershipAddRequestADM(normalUser.id, imagesProject.id, rootUser, UUID.randomUUID()) + responderManager ! UserProjectMembershipAddRequestADM(normalUser.id, imagesProject.id, defaultFeatureFactoryConfig, rootUser, UUID.randomUUID()) val membershipUpdateResponse = expectMsgType[UserOperationResponseADM](timeout) - responderManager ! UserProjectMembershipsGetRequestADM(normalUser.id, rootUser, UUID.randomUUID()) + responderManager ! UserProjectMembershipsGetRequestADM(normalUser.id, defaultFeatureFactoryConfig, rootUser) val membershipsAfterUpdate = expectMsgType[UserProjectMembershipsGetResponseADM](timeout) - membershipsAfterUpdate.projects should equal (Seq(imagesProject)) + membershipsAfterUpdate.projects should equal(Seq(imagesProject)) responderManager ! ProjectMembersGetRequestADM( ProjectIdentifierADM( - maybeIri = Some(imagesProject.id)), + maybeIri = Some(imagesProject.id)), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = KnoraSystemInstances.Users.SystemUser ) val received: ProjectMembersGetResponseADM = expectMsgType[ProjectMembersGetResponseADM](timeout) - received.members.map(_.id) should contain (normalUser.id) + received.members.map(_.id) should contain(normalUser.id) } "DELETE user from project" in { - responderManager ! UserProjectMembershipsGetRequestADM(normalUser.id, rootUser, UUID.randomUUID()) + responderManager ! UserProjectMembershipsGetRequestADM(normalUser.id, defaultFeatureFactoryConfig, rootUser) val membershipsBeforeUpdate = expectMsgType[UserProjectMembershipsGetResponseADM](timeout) - membershipsBeforeUpdate.projects should equal (Seq(imagesProject)) + membershipsBeforeUpdate.projects should equal(Seq(imagesProject)) - responderManager ! UserProjectMembershipRemoveRequestADM(normalUser.id, imagesProject.id, rootUser, UUID.randomUUID()) + responderManager ! UserProjectMembershipRemoveRequestADM(normalUser.id, imagesProject.id, defaultFeatureFactoryConfig, rootUser, UUID.randomUUID()) expectMsgType[UserOperationResponseADM](timeout) - responderManager ! UserProjectMembershipsGetRequestADM(normalUser.id, rootUser, UUID.randomUUID()) + responderManager ! UserProjectMembershipsGetRequestADM(normalUser.id, defaultFeatureFactoryConfig, rootUser) val membershipsAfterUpdate = expectMsgType[UserProjectMembershipsGetResponseADM](timeout) - membershipsAfterUpdate.projects should equal (Seq()) + membershipsAfterUpdate.projects should equal(Seq()) responderManager ! ProjectMembersGetRequestADM( ProjectIdentifierADM(maybeIri = Some(imagesProject.id)), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = rootUser ) val received: ProjectMembersGetResponseADM = expectMsgType[ProjectMembersGetResponseADM](timeout) @@ -669,11 +715,11 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with "return a 'ForbiddenException' if the user requesting update is not the project or system admin" in { /* User is added to a project by a normal user */ - responderManager ! UserProjectMembershipAddRequestADM(normalUser.id, imagesProject.id, normalUser, UUID.randomUUID()) + responderManager ! UserProjectMembershipAddRequestADM(normalUser.id, imagesProject.id, defaultFeatureFactoryConfig, normalUser, UUID.randomUUID()) expectMsg(timeout, Failure(ForbiddenException("User's project membership can only be changed by a project or system administrator"))) /* User is removed from a project by a normal user */ - responderManager ! UserProjectMembershipRemoveRequestADM(normalUser.id, imagesProject.id, normalUser, UUID.randomUUID()) + responderManager ! UserProjectMembershipRemoveRequestADM(normalUser.id, imagesProject.id, defaultFeatureFactoryConfig, normalUser, UUID.randomUUID()) expectMsg(timeout, Failure(ForbiddenException("User's project membership can only be changed by a project or system administrator"))) } @@ -683,40 +729,42 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with "ADD user to project admin group" in { - responderManager ! UserProjectAdminMembershipsGetRequestADM(normalUser.id, rootUser, UUID.randomUUID()) + responderManager ! UserProjectAdminMembershipsGetRequestADM(normalUser.id, defaultFeatureFactoryConfig, rootUser, UUID.randomUUID()) val membershipsBeforeUpdate = expectMsgType[UserProjectAdminMembershipsGetResponseADM](timeout) - membershipsBeforeUpdate.projects should equal (Seq()) + membershipsBeforeUpdate.projects should equal(Seq()) - responderManager ! UserProjectAdminMembershipAddRequestADM(normalUser.id, imagesProject.id, rootUser, UUID.randomUUID()) + responderManager ! UserProjectAdminMembershipAddRequestADM(normalUser.id, imagesProject.id, defaultFeatureFactoryConfig, rootUser, UUID.randomUUID()) expectMsgType[UserOperationResponseADM](timeout) - responderManager ! UserProjectAdminMembershipsGetRequestADM(normalUser.id, rootUser, UUID.randomUUID()) + responderManager ! UserProjectAdminMembershipsGetRequestADM(normalUser.id, defaultFeatureFactoryConfig, rootUser, UUID.randomUUID()) val membershipsAfterUpdate = expectMsgType[UserProjectAdminMembershipsGetResponseADM](timeout) - membershipsAfterUpdate.projects should equal (Seq(imagesProject)) + membershipsAfterUpdate.projects should equal(Seq(imagesProject)) responderManager ! ProjectAdminMembersGetRequestADM( ProjectIdentifierADM(maybeIri = Some(imagesProject.id)), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = rootUser ) val received: ProjectAdminMembersGetResponseADM = expectMsgType[ProjectAdminMembersGetResponseADM](timeout) - received.members should contain (normalUser.ofType(UserInformationTypeADM.RESTRICTED)) + received.members should contain(normalUser.ofType(UserInformationTypeADM.RESTRICTED)) } "DELETE user from project admin group" in { - responderManager ! UserProjectAdminMembershipsGetRequestADM(normalUser.id, rootUser, UUID.randomUUID()) + responderManager ! UserProjectAdminMembershipsGetRequestADM(normalUser.id, defaultFeatureFactoryConfig, rootUser, UUID.randomUUID()) val membershipsBeforeUpdate = expectMsgType[UserProjectAdminMembershipsGetResponseADM](timeout) - membershipsBeforeUpdate.projects should equal (Seq(imagesProject)) + membershipsBeforeUpdate.projects should equal(Seq(imagesProject)) - responderManager ! UserProjectAdminMembershipRemoveRequestADM(normalUser.id, imagesProject.id, rootUser, UUID.randomUUID()) + responderManager ! UserProjectAdminMembershipRemoveRequestADM(normalUser.id, imagesProject.id, defaultFeatureFactoryConfig, rootUser, UUID.randomUUID()) expectMsgType[UserOperationResponseADM](timeout) - responderManager ! UserProjectAdminMembershipsGetRequestADM(normalUser.id, rootUser, UUID.randomUUID()) + responderManager ! UserProjectAdminMembershipsGetRequestADM(normalUser.id, defaultFeatureFactoryConfig, rootUser, UUID.randomUUID()) val membershipsAfterUpdate = expectMsgType[UserProjectAdminMembershipsGetResponseADM](timeout) - membershipsAfterUpdate.projects should equal (Seq()) + membershipsAfterUpdate.projects should equal(Seq()) responderManager ! ProjectAdminMembersGetRequestADM( ProjectIdentifierADM(maybeIri = Some(imagesProject.id)), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = rootUser ) val received: ProjectAdminMembersGetResponseADM = expectMsgType[ProjectAdminMembersGetResponseADM](timeout) @@ -727,11 +775,11 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with "return a 'ForbiddenException' if the user requesting update is not the project or system admin" in { /* User is added to a project by a normal user */ - responderManager ! UserProjectAdminMembershipAddRequestADM(normalUser.id, imagesProject.id, normalUser, UUID.randomUUID()) + responderManager ! UserProjectAdminMembershipAddRequestADM(normalUser.id, imagesProject.id, defaultFeatureFactoryConfig, normalUser, UUID.randomUUID()) expectMsg(timeout, Failure(ForbiddenException("User's project admin membership can only be changed by a project or system administrator"))) /* User is removed from a project by a normal user */ - responderManager ! UserProjectAdminMembershipRemoveRequestADM(normalUser.id, imagesProject.id, normalUser, UUID.randomUUID()) + responderManager ! UserProjectAdminMembershipRemoveRequestADM(normalUser.id, imagesProject.id, defaultFeatureFactoryConfig, normalUser, UUID.randomUUID()) expectMsg(timeout, Failure(ForbiddenException("User's project admin membership can only be changed by a project or system administrator"))) } @@ -740,40 +788,42 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with "asked to update the user's group membership" should { "ADD user to group" in { - responderManager ! UserGroupMembershipsGetRequestADM(normalUser.id, rootUser, UUID.randomUUID()) + responderManager ! UserGroupMembershipsGetRequestADM(normalUser.id, defaultFeatureFactoryConfig, rootUser) val membershipsBeforeUpdate = expectMsgType[UserGroupMembershipsGetResponseADM](timeout) - membershipsBeforeUpdate.groups should equal (Seq()) + membershipsBeforeUpdate.groups should equal(Seq()) - responderManager ! UserGroupMembershipAddRequestADM(normalUser.id, imagesReviewerGroup.id, rootUser, UUID.randomUUID()) + responderManager ! UserGroupMembershipAddRequestADM(normalUser.id, imagesReviewerGroup.id, defaultFeatureFactoryConfig, rootUser, UUID.randomUUID()) expectMsgType[UserOperationResponseADM](timeout) - responderManager ! UserGroupMembershipsGetRequestADM(normalUser.id, rootUser, UUID.randomUUID()) + responderManager ! UserGroupMembershipsGetRequestADM(normalUser.id, defaultFeatureFactoryConfig, rootUser) val membershipsAfterUpdate = expectMsgType[UserGroupMembershipsGetResponseADM](timeout) - membershipsAfterUpdate.groups.map(_.id) should equal (Seq(imagesReviewerGroup.id)) + membershipsAfterUpdate.groups.map(_.id) should equal(Seq(imagesReviewerGroup.id)) responderManager ! GroupMembersGetRequestADM( groupIri = imagesReviewerGroup.id, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = rootUser ) val received: GroupMembersGetResponseADM = expectMsgType[GroupMembersGetResponseADM](timeout) - received.members.map(_.id) should contain (normalUser.id) + received.members.map(_.id) should contain(normalUser.id) } "DELETE user from group" in { - responderManager ! UserGroupMembershipsGetRequestADM(normalUser.id, rootUser, UUID.randomUUID()) + responderManager ! UserGroupMembershipsGetRequestADM(normalUser.id, defaultFeatureFactoryConfig, rootUser) val membershipsBeforeUpdate = expectMsgType[UserGroupMembershipsGetResponseADM](timeout) - membershipsBeforeUpdate.groups.map(_.id) should equal (Seq(imagesReviewerGroup.id)) + membershipsBeforeUpdate.groups.map(_.id) should equal(Seq(imagesReviewerGroup.id)) - responderManager ! UserGroupMembershipRemoveRequestADM(normalUser.id, imagesReviewerGroup.id, rootUser, UUID.randomUUID()) + responderManager ! UserGroupMembershipRemoveRequestADM(normalUser.id, imagesReviewerGroup.id, defaultFeatureFactoryConfig, rootUser, UUID.randomUUID()) expectMsgType[UserOperationResponseADM](timeout) - responderManager ! UserGroupMembershipsGetRequestADM(normalUser.id, rootUser, UUID.randomUUID()) + responderManager ! UserGroupMembershipsGetRequestADM(normalUser.id, defaultFeatureFactoryConfig, rootUser) val membershipsAfterUpdate = expectMsgType[UserGroupMembershipsGetResponseADM](timeout) - membershipsAfterUpdate.groups should equal (Seq()) + membershipsAfterUpdate.groups should equal(Seq()) responderManager ! GroupMembersGetRequestADM( groupIri = imagesReviewerGroup.id, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = rootUser ) val received: GroupMembersGetResponseADM = expectMsgType[GroupMembersGetResponseADM](timeout) @@ -784,11 +834,11 @@ class UsersResponderADMSpec extends CoreSpec(UsersResponderADMSpec.config) with "return a 'ForbiddenException' if the user requesting update is not the project or system admin" in { /* User is added to a project by a normal user */ - responderManager ! UserGroupMembershipAddRequestADM(normalUser.id, imagesReviewerGroup.id, normalUser, UUID.randomUUID()) + responderManager ! UserGroupMembershipAddRequestADM(normalUser.id, imagesReviewerGroup.id, defaultFeatureFactoryConfig, normalUser, UUID.randomUUID()) expectMsg(timeout, Failure(ForbiddenException("User's group membership can only be changed by a project or system administrator"))) /* User is removed from a project by a normal user */ - responderManager ! UserGroupMembershipRemoveRequestADM(normalUser.id, imagesReviewerGroup.id, normalUser, UUID.randomUUID()) + responderManager ! UserGroupMembershipRemoveRequestADM(normalUser.id, imagesReviewerGroup.id, defaultFeatureFactoryConfig, normalUser, UUID.randomUUID()) expectMsg(timeout, Failure(ForbiddenException("User's group membership can only be changed by a project or system administrator"))) } diff --git a/webapi/src/test/scala/org/knora/webapi/responders/v1/OntologyResponderV1Spec.scala b/webapi/src/test/scala/org/knora/webapi/responders/v1/OntologyResponderV1Spec.scala index bab7651bb9..9df3942571 100644 --- a/webapi/src/test/scala/org/knora/webapi/responders/v1/OntologyResponderV1Spec.scala +++ b/webapi/src/test/scala/org/knora/webapi/responders/v1/OntologyResponderV1Spec.scala @@ -31,8 +31,8 @@ import org.knora.webapi.sharedtestdata.{SharedOntologyTestDataADM, SharedTestDat import scala.concurrent.duration._ /** - * Static data for testing [[OntologyResponderV1]]. - */ + * Static data for testing [[OntologyResponderV1]]. + */ object OntologyResponderV1Spec { // A test user that prefers responses in German. @@ -45,8 +45,8 @@ object OntologyResponderV1Spec { /** - * Tests [[OntologyResponderV1]]. - */ + * Tests [[OntologyResponderV1]]. + */ class OntologyResponderV1Spec extends CoreSpec() with ImplicitSender { // The default timeout for receiving reply messages from actors. @@ -1070,6 +1070,7 @@ class OntologyResponderV1Spec extends CoreSpec() with ImplicitSender { "get all the vocabularies" in { responderManager ! NamedGraphsGetRequestV1( + featureFactoryConfig = defaultFeatureFactoryConfig, userADM = OntologyResponderV1Spec.userProfileWithEnglish ) @@ -1082,6 +1083,7 @@ class OntologyResponderV1Spec extends CoreSpec() with ImplicitSender { "get all the resource classes with their property types for incunabula named graph" in { responderManager ! ResourceTypesForNamedGraphGetRequestV1( namedGraph = Some("http://www.knora.org/ontology/0803/incunabula"), + featureFactoryConfig = defaultFeatureFactoryConfig, userADM = OntologyResponderV1Spec.userProfileWithEnglish ) @@ -1095,6 +1097,7 @@ class OntologyResponderV1Spec extends CoreSpec() with ImplicitSender { "get all the properties for the named graph incunabula" in { responderManager ! PropertyTypesForNamedGraphGetRequestV1( namedGraph = Some("http://www.knora.org/ontology/0803/incunabula"), + featureFactoryConfig = defaultFeatureFactoryConfig, userADM = OntologyResponderV1Spec.userProfileWithEnglish ) @@ -1107,6 +1110,7 @@ class OntologyResponderV1Spec extends CoreSpec() with ImplicitSender { "get all the properties for all vocabularies" in { responderManager ! PropertyTypesForNamedGraphGetRequestV1( namedGraph = None, + featureFactoryConfig = defaultFeatureFactoryConfig, userADM = OntologyResponderV1Spec.userProfileWithEnglish ) diff --git a/webapi/src/test/scala/org/knora/webapi/responders/v1/ProjectsResponderV1Spec.scala b/webapi/src/test/scala/org/knora/webapi/responders/v1/ProjectsResponderV1Spec.scala index 01da0df1ee..39c820e50c 100644 --- a/webapi/src/test/scala/org/knora/webapi/responders/v1/ProjectsResponderV1Spec.scala +++ b/webapi/src/test/scala/org/knora/webapi/responders/v1/ProjectsResponderV1Spec.scala @@ -24,12 +24,11 @@ package org.knora.webapi.responders.v1 import akka.actor.Status.Failure -import akka.testkit.{ImplicitSender, TestActorRef} +import akka.testkit.ImplicitSender import com.typesafe.config.{Config, ConfigFactory} import org.knora.webapi._ import org.knora.webapi.exceptions.NotFoundException import org.knora.webapi.messages.v1.responder.projectmessages._ -import org.knora.webapi.messages.v1.responder.usermessages.UserProfileTypeV1 import org.knora.webapi.sharedtestdata.SharedTestDataV1 import scala.concurrent.duration._ @@ -59,7 +58,10 @@ class ProjectsResponderV1Spec extends CoreSpec(ProjectsResponderV1Spec.config) w "return information for every project" in { - responderManager ! ProjectsGetRequestV1(Some(rootUserProfileV1)) + responderManager ! ProjectsGetRequestV1( + featureFactoryConfig = defaultFeatureFactoryConfig, + userProfile = Some(rootUserProfileV1) + ) val received = expectMsgType[ProjectsResponseV1](timeout) assert(received.projects.contains(SharedTestDataV1.imagesProjectInfo)) @@ -70,41 +72,56 @@ class ProjectsResponderV1Spec extends CoreSpec(ProjectsResponderV1Spec.config) w /* Incunabula project */ responderManager ! ProjectInfoByIRIGetRequestV1( - SharedTestDataV1.incunabulaProjectInfo.id, - Some(SharedTestDataV1.rootUser) + iri = SharedTestDataV1.incunabulaProjectInfo.id, + featureFactoryConfig = defaultFeatureFactoryConfig, + userProfileV1 = Some(SharedTestDataV1.rootUser) ) expectMsg(ProjectInfoResponseV1(SharedTestDataV1.incunabulaProjectInfo)) /* Images project */ responderManager ! ProjectInfoByIRIGetRequestV1( - SharedTestDataV1.imagesProjectInfo.id, - Some(SharedTestDataV1.rootUser) + iri = SharedTestDataV1.imagesProjectInfo.id, + featureFactoryConfig = defaultFeatureFactoryConfig, + userProfileV1 = Some(SharedTestDataV1.rootUser) ) expectMsg(ProjectInfoResponseV1(SharedTestDataV1.imagesProjectInfo)) /* 'SystemProject' */ responderManager ! ProjectInfoByIRIGetRequestV1( - SharedTestDataV1.systemProjectInfo.id, - Some(SharedTestDataV1.rootUser) + iri = SharedTestDataV1.systemProjectInfo.id, + featureFactoryConfig = defaultFeatureFactoryConfig, + userProfileV1 = Some(SharedTestDataV1.rootUser) ) expectMsg(ProjectInfoResponseV1(SharedTestDataV1.systemProjectInfo)) } "return information about a project identified by shortname" in { - responderManager ! ProjectInfoByShortnameGetRequestV1(SharedTestDataV1.incunabulaProjectInfo.shortname, Some(rootUserProfileV1)) + responderManager ! ProjectInfoByShortnameGetRequestV1( + SharedTestDataV1.incunabulaProjectInfo.shortname, + featureFactoryConfig = defaultFeatureFactoryConfig, + Some(rootUserProfileV1) + ) expectMsg(ProjectInfoResponseV1(SharedTestDataV1.incunabulaProjectInfo)) } "return 'NotFoundException' when the project IRI is unknown" in { - responderManager ! ProjectInfoByIRIGetRequestV1("http://rdfh.ch/projects/notexisting", Some(rootUserProfileV1)) + responderManager ! ProjectInfoByIRIGetRequestV1( + iri = "http://rdfh.ch/projects/notexisting", + featureFactoryConfig = defaultFeatureFactoryConfig, + userProfileV1 = Some(rootUserProfileV1) + ) expectMsg(Failure(NotFoundException(s"Project 'http://rdfh.ch/projects/notexisting' not found"))) } "return 'NotFoundException' when the project shortname unknown " in { - responderManager ! ProjectInfoByShortnameGetRequestV1("projectwrong", Some(rootUserProfileV1)) + responderManager ! ProjectInfoByShortnameGetRequestV1( + shortname = "projectwrong", + featureFactoryConfig = defaultFeatureFactoryConfig, + userProfileV1 = Some(rootUserProfileV1) + ) expectMsg(Failure(NotFoundException(s"Project 'projectwrong' not found"))) } } diff --git a/webapi/src/test/scala/org/knora/webapi/responders/v1/ResourcesResponderV1Spec.scala b/webapi/src/test/scala/org/knora/webapi/responders/v1/ResourcesResponderV1Spec.scala index 98074198c7..d11f4dd05c 100644 --- a/webapi/src/test/scala/org/knora/webapi/responders/v1/ResourcesResponderV1Spec.scala +++ b/webapi/src/test/scala/org/knora/webapi/responders/v1/ResourcesResponderV1Spec.scala @@ -44,16 +44,16 @@ import spray.json.JsValue import scala.concurrent.duration._ /** - * Static data for testing [[ResourcesResponderV1]]. - */ + * Static data for testing [[ResourcesResponderV1]]. + */ object ResourcesResponderV1Spec { - val config: Config = ConfigFactory.parseString( + private val config: Config = ConfigFactory.parseString( """ akka.loglevel = "DEBUG" akka.stdout-loglevel = "DEBUG" """.stripMargin) - val ReiseInsHeiligelandThreeValues = ResourceSearchResponseV1( + private val ReiseInsHeiligelandThreeValues: ResourceSearchResponseV1 = ResourceSearchResponseV1( resources = Vector(ResourceSearchResultRowV1( id = "http://rdfh.ch/0803/2a6221216701", value = Vector("Reise ins Heilige Land", "Reysen und wanderschafften durch das Gelobte Land", "Itinerarius"), @@ -61,7 +61,7 @@ object ResourcesResponderV1Spec { )) ) - val ReiseInsHeiligelandOneValueRestrictedToBook = ResourceSearchResponseV1( + private val ReiseInsHeiligelandOneValueRestrictedToBook: ResourceSearchResponseV1 = ResourceSearchResponseV1( resources = Vector(ResourceSearchResultRowV1( id = "http://rdfh.ch/0803/2a6221216701", value = Vector("Reise ins Heilige Land"), @@ -616,9 +616,10 @@ object ResourcesResponderV1Spec { /** - * Tests [[ResourcesResponderV1]]. - */ + * Tests [[ResourcesResponderV1]]. + */ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) with ImplicitSender { + import ResourcesResponderV1Spec._ implicit private val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance @@ -855,7 +856,7 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) "The resources responder" should { "return a full description of the book 'Zeitglöcklein des Lebens und Leidens Christi' in the Incunabula test data" in { // http://0.0.0.0:3333/v1/resources/http%3A%2F%2Frdfh.ch%2F0803%2Fc5058f3a - responderManager ! ResourceFullGetRequestV1(iri = "http://rdfh.ch/0803/c5058f3a", userADM = SharedTestDataADM.incunabulaMemberUser) + responderManager ! ResourceFullGetRequestV1(iri = "http://rdfh.ch/0803/c5058f3a", featureFactoryConfig = defaultFeatureFactoryConfig, userADM = SharedTestDataADM.incunabulaMemberUser) expectMsgPF(timeout) { case response: ResourceFullResponseV1 => compareResourceFullResponses(received = response, expected = ResourcesResponderV1SpecFullData.expectedBookResourceFullResponse) @@ -864,7 +865,7 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) "return a full description of the first page of the book 'Zeitglöcklein des Lebens und Leidens Christi' in the Incunabula test data" in { // http://0.0.0.0:3333/v1/resources/http%3A%2F%2Frdfh.ch%2F0803%2F8a0b1e75 - responderManager ! ResourceFullGetRequestV1(iri = "http://rdfh.ch/0803/8a0b1e75", userADM = SharedTestDataADM.incunabulaMemberUser) + responderManager ! ResourceFullGetRequestV1(iri = "http://rdfh.ch/0803/8a0b1e75", featureFactoryConfig = defaultFeatureFactoryConfig, userADM = SharedTestDataADM.incunabulaMemberUser) expectMsgPF(timeout) { case response: ResourceFullResponseV1 => compareResourceFullResponses(received = response, expected = ResourcesResponderV1SpecFullData.expectedPageResourceFullResponse) @@ -873,16 +874,16 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) "return the context (describing 402 pages) of the book 'Zeitglöcklein des Lebens und Leidens Christi' in the Incunabula test data" in { // http://0.0.0.0:3333/v1/resources/http%3A%2F%2Frdfh.ch%2F0803%2Fc5058f3a?reqtype=context&resinfo=true - responderManager ! ResourceContextGetRequestV1(iri = "http://rdfh.ch/0803/c5058f3a", resinfo = true, userProfile = SharedTestDataADM.incunabulaProjectAdminUser) + responderManager ! ResourceContextGetRequestV1(iri = "http://rdfh.ch/0803/c5058f3a", resinfo = true, featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = SharedTestDataADM.incunabulaProjectAdminUser) val response: JsValue = expectMsgType[ResourceContextResponseV1](timeout).toJsValue - response should be (ResourcesResponderV1SpecContextData.expectedBookResourceContextResponse) + response should be(ResourcesResponderV1SpecContextData.expectedBookResourceContextResponse) } "return the context of a page of the book 'Zeitglöcklein des Lebens und Leidens Christi' in the Incunabula test data" in { // http://0.0.0.0:3333/v1/resources/http%3A%2F%2Frdfh.ch%2F0803%2F8a0b1e75?reqtype=context&resinfo=true - responderManager ! ResourceContextGetRequestV1(iri = "http://rdfh.ch/0803/8a0b1e75", resinfo = true, userProfile = SharedTestDataADM.incunabulaProjectAdminUser) + responderManager ! ResourceContextGetRequestV1(iri = "http://rdfh.ch/0803/8a0b1e75", resinfo = true, featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = SharedTestDataADM.incunabulaProjectAdminUser) expectMsgPF(timeout) { case response: ResourceContextResponseV1 => compareResourcePartOfContextResponses(received = response, expected = ResourcesResponderV1SpecContextData.expectedPageResourceContextResponse) @@ -1021,6 +1022,7 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) label = "Test-Misc", projectIri = "http://rdfh.ch/projects/0803", values = valuesToBeCreated, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = SharedTestDataADM.incunabulaProjectAdminUser, apiRequestID = UUID.randomUUID ) @@ -1059,6 +1061,7 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) label = "Test-Book", projectIri = "http://rdfh.ch/projects/0803", values = valuesToBeCreated, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = SharedTestDataADM.incunabulaProjectAdminUser, apiRequestID = UUID.randomUUID ) @@ -1112,6 +1115,7 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) label = "Book with reference to nonexistent resource", projectIri = "http://rdfh.ch/projects/0803", values = valuesToBeCreated, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = SharedTestDataADM.incunabulaProjectAdminUser, apiRequestID = UUID.randomUUID ) @@ -1158,7 +1162,7 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) val publoc = TextValueSimpleV1("Entenhausen") val pubdateRequest = DateUtilV1.createJDNValueV1FromDateString("GREGORIAN:2015-12-03") - val pubdateResponse = DateValueV1(dateval1 = "2015-12-03", dateval2 = "2015-12-03", era1="CE",era2="CE", calendar = KnoraCalendarV1.GREGORIAN) + val pubdateResponse = DateValueV1(dateval1 = "2015-12-03", dateval2 = "2015-12-03", era1 = "CE", era2 = "CE", calendar = KnoraCalendarV1.GREGORIAN) val valuesToBeCreated: Map[IRI, Seq[CreateValueV1WithComment]] = Map( "http://www.knora.org/ontology/0803/incunabula#title" -> Vector(CreateValueV1WithComment(title1)), @@ -1185,6 +1189,7 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) label = "Test-Book", projectIri = SharedTestDataADM.INCUNABULA_PROJECT_IRI, values = valuesToBeCreated, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = SharedTestDataADM.incunabulaProjectAdminUser, apiRequestID = UUID.randomUUID ) @@ -1204,7 +1209,7 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) // See if we can query the resource. - responderManager ! ResourceFullGetRequestV1(iri = newBookResourceIri.get, userADM = SharedTestDataADM.incunabulaProjectAdminUser) + responderManager ! ResourceFullGetRequestV1(iri = newBookResourceIri.get, featureFactoryConfig = defaultFeatureFactoryConfig, userADM = SharedTestDataADM.incunabulaProjectAdminUser) expectMsgPF(timeout) { case response: ResourceFullResponseV1 => () // If we got a ResourceFullResponseV1, the operation succeeded. } @@ -1250,6 +1255,7 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) projectIri = SharedTestDataADM.INCUNABULA_PROJECT_IRI, values = valuesToBeCreated, file = Some(fileValue), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = SharedTestDataADM.incunabulaProjectAdminUser, apiRequestID = UUID.randomUUID ) @@ -1272,6 +1278,7 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) val pageGetContext = ResourceContextGetRequestV1( iri = resIri, resinfo = true, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = SharedTestDataADM.incunabulaProjectAdminUser ) @@ -1289,6 +1296,7 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) val resourceDeleteRequest = ResourceDeleteRequestV1( resourceIri = newPageResourceIri.get, deleteComment = Some("This page was deleted as a test"), + featureFactoryConfig = defaultFeatureFactoryConfig, userADM = SharedTestDataADM.incunabulaProjectAdminUser, apiRequestID = UUID.randomUUID ) @@ -1298,7 +1306,11 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) expectMsg(timeout, ResourceDeleteResponseV1(id = newPageResourceIri.get)) // Check that the resource is marked as deleted. - responderManager ! ResourceInfoGetRequestV1(iri = newPageResourceIri.get, userProfile = SharedTestDataADM.incunabulaProjectAdminUser) + responderManager ! ResourceInfoGetRequestV1( + iri = newPageResourceIri.get, + featureFactoryConfig = defaultFeatureFactoryConfig, + userProfile = SharedTestDataADM.incunabulaProjectAdminUser + ) expectMsgPF(timeout) { case msg: akka.actor.Status.Failure => msg.cause.isInstanceOf[NotFoundException] should ===(true) @@ -1312,8 +1324,9 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) "get the properties of a resource" in { val propertiesGetRequest = PropertiesGetRequestV1( - "http://rdfh.ch/0803/021ec18f1735", - SharedTestDataADM.incunabulaProjectAdminUser + iri = "http://rdfh.ch/0803/021ec18f1735", + featureFactoryConfig = defaultFeatureFactoryConfig, + userProfile = SharedTestDataADM.incunabulaProjectAdminUser ) responderManager ! propertiesGetRequest @@ -1325,7 +1338,12 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) "get the regions of a page pointed to by regions" in { - val resourceContextPage = ResourceContextGetRequestV1(iri = "http://rdfh.ch/0803/9d626dc76c03", resinfo = true, userProfile = SharedTestDataADM.incunabulaProjectAdminUser) + val resourceContextPage = ResourceContextGetRequestV1( + iri = "http://rdfh.ch/0803/9d626dc76c03", + resinfo = true, + featureFactoryConfig = defaultFeatureFactoryConfig, + userProfile = SharedTestDataADM.incunabulaProjectAdminUser + ) responderManager ! resourceContextPage @@ -1337,7 +1355,11 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) "show incoming standoff links if the user has view permission on both resources, but show other incoming links only if the user also has view permission on the link" in { // The link's owner, anythingUser1, should see the hasOtherThing link as well as the hasStandoffLinkTo link. - responderManager ! ResourceFullGetRequestV1(iri = "http://rdfh.ch/0001/project-thing-2", userADM = SharedTestDataADM.anythingUser1) + responderManager ! ResourceFullGetRequestV1( + iri = "http://rdfh.ch/0001/project-thing-2", + featureFactoryConfig = defaultFeatureFactoryConfig, + userADM = SharedTestDataADM.anythingUser1 + ) expectMsgPF(timeout) { case response: ResourceFullResponseV1 => @@ -1348,7 +1370,7 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) // But another user should see only the hasStandoffLinkTo link. - responderManager ! ResourceFullGetRequestV1(iri = "http://rdfh.ch/0001/project-thing-2", userADM = SharedTestDataADM.anythingUser2) + responderManager ! ResourceFullGetRequestV1(iri = "http://rdfh.ch/0001/project-thing-2", featureFactoryConfig = defaultFeatureFactoryConfig, userADM = SharedTestDataADM.anythingUser2) expectMsgPF(timeout) { case response: ResourceFullResponseV1 => @@ -1360,7 +1382,7 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) "show outgoing standoff links if the user has view permission on both resources, but show other outgoing links only if the user also has view permission on the link" in { // The link's owner, anythingUser1, should see the hasOtherThing link as well as the hasStandoffLinkTo link. - responderManager ! ResourceFullGetRequestV1(iri = "http://rdfh.ch/0001/project-thing-1", userADM = SharedTestDataADM.anythingUser1) + responderManager ! ResourceFullGetRequestV1(iri = "http://rdfh.ch/0001/project-thing-1", featureFactoryConfig = defaultFeatureFactoryConfig, userADM = SharedTestDataADM.anythingUser1) expectMsgPF(timeout) { case response: ResourceFullResponseV1 => @@ -1376,7 +1398,7 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) // But another user should see only the hasStandoffLinkTo link. - responderManager ! ResourceFullGetRequestV1(iri = "http://rdfh.ch/0001/project-thing-1", userADM = SharedTestDataADM.anythingUser2) + responderManager ! ResourceFullGetRequestV1(iri = "http://rdfh.ch/0001/project-thing-1", featureFactoryConfig = defaultFeatureFactoryConfig, userADM = SharedTestDataADM.anythingUser2) expectMsgPF(timeout) { case response: ResourceFullResponseV1 => @@ -1393,7 +1415,7 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) "show a contained resource in a context request only if the user has permission to see the containing resource, the contained resource, and the link value" in { // The owner of the resources and the link should see two contained resources. - responderManager ! ResourceContextGetRequestV1(iri = "http://rdfh.ch/0001/containing-thing", resinfo = true, userProfile = SharedTestDataADM.anythingUser1) + responderManager ! ResourceContextGetRequestV1(iri = "http://rdfh.ch/0001/containing-thing", resinfo = true, featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = SharedTestDataADM.anythingUser1) expectMsgPF(timeout) { case response: ResourceContextResponseV1 => @@ -1405,7 +1427,7 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) // Another user in the project, who doesn't have permission to see the second link, should see only one contained resource. - responderManager ! ResourceContextGetRequestV1(iri = "http://rdfh.ch/0001/containing-thing", resinfo = true, userProfile = SharedTestDataADM.anythingUser2) + responderManager ! ResourceContextGetRequestV1(iri = "http://rdfh.ch/0001/containing-thing", resinfo = true, featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = SharedTestDataADM.anythingUser2) expectMsgPF(timeout) { case response: ResourceContextResponseV1 => @@ -1414,7 +1436,7 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) // A user who's not in the project shouldn't see any contained resources. - responderManager ! ResourceContextGetRequestV1(iri = "http://rdfh.ch/0001/containing-thing", resinfo = true, userProfile = SharedTestDataADM.incunabulaProjectAdminUser) + responderManager ! ResourceContextGetRequestV1(iri = "http://rdfh.ch/0001/containing-thing", resinfo = true, featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = SharedTestDataADM.incunabulaProjectAdminUser) expectMsgPF(timeout) { case response: ResourceContextResponseV1 => @@ -1429,6 +1451,7 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) projectIri = "http://rdfh.ch/projects/0803", values = Map.empty[IRI, Seq[CreateValueV1WithComment]], file = None, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = SharedTestDataADM.incunabulaProjectAdminUser, apiRequestID = UUID.randomUUID ) @@ -1445,6 +1468,7 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) projectIri = "http://rdfh.ch/projects/0803", values = Map.empty[IRI, Seq[CreateValueV1WithComment]], file = None, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = SharedTestDataADM.incunabulaProjectAdminUser, apiRequestID = UUID.randomUUID ) @@ -1461,6 +1485,7 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) projectIri = OntologyConstants.KnoraAdmin.DefaultSharedOntologiesProject, values = Map.empty[IRI, Seq[CreateValueV1WithComment]], file = None, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = SharedTestDataADM.superUser, apiRequestID = UUID.randomUUID ) @@ -1476,6 +1501,7 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) responderManager ! ChangeResourceLabelRequestV1( resourceIri = "http://rdfh.ch/0803/c5058f3a", label = myNewLabel, + featureFactoryConfig = defaultFeatureFactoryConfig, userADM = SharedTestDataADM.incunabulaProjectAdminUser, apiRequestID = UUID.randomUUID ) @@ -1498,6 +1524,7 @@ class ResourcesResponderV1Spec extends CoreSpec(ResourcesResponderV1Spec.config) projectIri = "http://rdfh.ch/projects/0001", values = valuesToBeCreated, file = None, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = SharedTestDataADM.anythingUser1, apiRequestID = UUID.randomUUID ) diff --git a/webapi/src/test/scala/org/knora/webapi/responders/v1/UsersResponderV1Spec.scala b/webapi/src/test/scala/org/knora/webapi/responders/v1/UsersResponderV1Spec.scala index a14b62e7ce..f65adb0844 100644 --- a/webapi/src/test/scala/org/knora/webapi/responders/v1/UsersResponderV1Spec.scala +++ b/webapi/src/test/scala/org/knora/webapi/responders/v1/UsersResponderV1Spec.scala @@ -18,9 +18,9 @@ */ /** - * To be able to test UsersResponder, we need to be able to start UsersResponder isolated. Now the UsersResponder - * extend ResponderV1 which messes up testing, as we cannot inject the TestActor system. - */ + * To be able to test UsersResponder, we need to be able to start UsersResponder isolated. Now the UsersResponder + * extend ResponderV1 which messes up testing, as we cannot inject the TestActor system. + */ package org.knora.webapi.responders.v1 @@ -45,8 +45,8 @@ object UsersResponderV1Spec { } /** - * This spec is used to test the messages received by the [[UsersResponderV1]] actor. - */ + * This spec is used to test the messages received by the [[UsersResponderV1]] actor. + */ class UsersResponderV1Spec extends CoreSpec(UsersResponderV1Spec.config) with ImplicitSender { private val timeout = 5.seconds @@ -71,32 +71,49 @@ class UsersResponderV1Spec extends CoreSpec(UsersResponderV1Spec.config) with Im responderManager ! UsersGetRequestV1(rootUser) val response = expectMsgType[UsersGetResponseV1](timeout) // println(response.users) - response.users.nonEmpty should be (true) - response.users.size should be (20) + response.users.nonEmpty should be(true) + response.users.size should be(20) } } "asked about an user identified by 'iri' " should { "return a profile if the user (root user) is known" in { - responderManager ! UserProfileByIRIGetV1(rootUserIri, UserProfileTypeV1.FULL) + responderManager ! UserProfileByIRIGetV1( + userIri = rootUserIri, + UserProfileTypeV1.FULL, + featureFactoryConfig = defaultFeatureFactoryConfig + ) val response = expectMsgType[Option[UserProfileV1]](timeout) // println(response) response should equal(Some(rootUser.ofType(UserProfileTypeV1.FULL))) } "return a profile if the user (incunabula user) is known" in { - responderManager ! UserProfileByIRIGetV1(incunabulaUserIri, UserProfileTypeV1.FULL) + responderManager ! UserProfileByIRIGetV1( + incunabulaUserIri, + UserProfileTypeV1.FULL, + featureFactoryConfig = defaultFeatureFactoryConfig + ) expectMsg(Some(incunabulaUser.ofType(UserProfileTypeV1.FULL))) } "return 'NotFoundException' when the user is unknown " in { - responderManager ! UserProfileByIRIGetRequestV1("http://rdfh.ch/users/notexisting", UserProfileTypeV1.RESTRICTED, rootUser) + responderManager ! UserProfileByIRIGetRequestV1( + userIri = "http://rdfh.ch/users/notexisting", + userProfileType = UserProfileTypeV1.RESTRICTED, + featureFactoryConfig = defaultFeatureFactoryConfig, + userProfile = rootUser + ) expectMsg(Failure(NotFoundException(s"User 'http://rdfh.ch/users/notexisting' not found"))) } "return 'None' when the user is unknown " in { - responderManager ! UserProfileByIRIGetV1("http://rdfh.ch/users/notexisting", UserProfileTypeV1.RESTRICTED) + responderManager ! UserProfileByIRIGetV1( + userIri = "http://rdfh.ch/users/notexisting", + userProfileType = UserProfileTypeV1.RESTRICTED, + featureFactoryConfig = defaultFeatureFactoryConfig + ) expectMsg(None) } } @@ -104,22 +121,39 @@ class UsersResponderV1Spec extends CoreSpec(UsersResponderV1Spec.config) with Im "asked about an user identified by 'email'" should { "return a profile if the user (root user) is known" in { - responderManager ! UserProfileByEmailGetV1(rootUserEmail, UserProfileTypeV1.RESTRICTED) + responderManager ! UserProfileByEmailGetV1( + email = rootUserEmail, + userProfileType = UserProfileTypeV1.RESTRICTED, + featureFactoryConfig = defaultFeatureFactoryConfig + ) expectMsg(Some(rootUser.ofType(UserProfileTypeV1.RESTRICTED))) } "return a profile if the user (incunabula user) is known" in { - responderManager ! UserProfileByEmailGetV1(incunabulaUserEmail, UserProfileTypeV1.RESTRICTED) + responderManager ! UserProfileByEmailGetV1( + email = incunabulaUserEmail, + userProfileType = UserProfileTypeV1.RESTRICTED, + featureFactoryConfig = defaultFeatureFactoryConfig + ) expectMsg(Some(incunabulaUser.ofType(UserProfileTypeV1.RESTRICTED))) } "return 'NotFoundException' when the user is unknown" in { - responderManager ! UserProfileByEmailGetRequestV1("userwrong@example.com", UserProfileTypeV1.RESTRICTED, rootUser) + responderManager ! UserProfileByEmailGetRequestV1( + email = "userwrong@example.com", + userProfileType = UserProfileTypeV1.RESTRICTED, + featureFactoryConfig = defaultFeatureFactoryConfig, + userProfile = rootUser + ) expectMsg(Failure(NotFoundException(s"User 'userwrong@example.com' not found"))) } "return 'None' when the user is unknown" in { - responderManager ! UserProfileByEmailGetV1("userwrong@example.com", UserProfileTypeV1.RESTRICTED) + responderManager ! UserProfileByEmailGetV1( + email = "userwrong@example.com", + userProfileType = UserProfileTypeV1.RESTRICTED, + featureFactoryConfig = defaultFeatureFactoryConfig + ) expectMsg(None) } } diff --git a/webapi/src/test/scala/org/knora/webapi/responders/v1/ValuesResponderV1Spec.scala b/webapi/src/test/scala/org/knora/webapi/responders/v1/ValuesResponderV1Spec.scala index 3e488e09dc..2747eb82a3 100644 --- a/webapi/src/test/scala/org/knora/webapi/responders/v1/ValuesResponderV1Spec.scala +++ b/webapi/src/test/scala/org/knora/webapi/responders/v1/ValuesResponderV1Spec.scala @@ -42,8 +42,8 @@ import org.knora.webapi.util.MutableTestIri import scala.concurrent.duration._ /** - * Static data for testing [[ValuesResponderV1]]. - */ + * Static data for testing [[ValuesResponderV1]]. + */ object ValuesResponderV1Spec { val config: Config = ConfigFactory.parseString( """ @@ -63,8 +63,8 @@ object ValuesResponderV1Spec { } /** - * Tests [[ValuesResponderV1]]. - */ + * Tests [[ValuesResponderV1]]. + */ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with ImplicitSender { implicit private val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance @@ -249,6 +249,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with resourceIri = zeitglöckleinIri, propertyIri = "http://www.knora.org/ontology/0803/incunabula#book_comment", value = TextValueSimpleV1(utf8str = utf8str), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -270,6 +271,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with resourceIri = zeitglöckleinIri, propertyIri = "http://www.knora.org/ontology/0803/incunabula#book_comment", value = TextValueSimpleV1(utf8str = utf8str), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -284,6 +286,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with "query a text value without Standoff" in { responderManager ! ValueGetRequestV1( valueIri = commentIri.get, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser ) @@ -295,6 +298,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with "query a text value containing Standoff" in { responderManager ! ValueGetRequestV1( valueIri = "http://rdfh.ch/0803/e41ab5695c/values/d3398239089e04", + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser ) @@ -307,6 +311,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with "query a standoff link as an ordinary value" in { responderManager ! ValueGetRequestV1( valueIri = "http://rdfh.ch/0001/a-thing-with-text-values/values/0", + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = anythingUser ) @@ -320,6 +325,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with subjectIri = "http://rdfh.ch/0803/8a0b1e75", predicateIri = "http://www.knora.org/ontology/0803/incunabula#partOf", objectIri = zeitglöckleinIri, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser ) @@ -346,6 +352,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! ChangeValueRequestV1( valueIri = commentIri.get, value = TextValueSimpleV1(utf8str = utf8str), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -394,6 +401,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! ChangeValueRequestV1( valueIri = commentIri.get, value = TextValueSimpleV1(utf8str = utf8str), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -410,6 +418,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with resourceIri = zeitglöckleinIri, propertyIri = "http://www.knora.org/ontology/0803/incunabula#book_comment", value = TextValueSimpleV1(utf8str = utf8str), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -425,6 +434,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! ChangeValueRequestV1( valueIri = "http://rdfh.ch/0803/c5058f3a/values/184e99ca01", value = TextValueSimpleV1(utf8str = utf8str), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -439,6 +449,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with resourceIri = zeitglöckleinIri, propertyIri = "http://www.knora.org/ontology/0803/incunabula#book_comment", value = TextValueSimpleV1("Comment 2"), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -449,6 +460,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! ResourceFullGetRequestV1( iri = zeitglöckleinIri, + featureFactoryConfig = defaultFeatureFactoryConfig, userADM = incunabulaUser ) @@ -475,6 +487,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! DeleteValueRequestV1( valueIri = commentIri.get, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -485,6 +498,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! ValueGetRequestV1( valueIri = commentIri.get, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser ) @@ -502,6 +516,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with resourceIri = "http://rdfh.ch/0803/nonexistent", propertyIri = "http://www.knora.org/ontology/0803/incunabula#book_comment", value = TextValueSimpleV1("Comment 1"), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -516,6 +531,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with resourceIri = "http://rdfh.ch/0803/9935159f67", propertyIri = "http://www.knora.org/ontology/0803/incunabula#book_comment", value = TextValueSimpleV1("Comment 1"), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -529,6 +545,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! ChangeValueRequestV1( valueIri = commentIri.get, value = TextValueSimpleV1("Comment 1c"), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -543,6 +560,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with resourceIri = "http://rdfh.ch/0803/e41ab5695c", propertyIri = "http://www.knora.org/ontology/0803/incunabula#book_comment", value = TextValueSimpleV1("Comment 1"), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -557,6 +575,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with resourceIri = "http://rdfh.ch/0803/21abac2162", propertyIri = "http://www.knora.org/ontology/0803/incunabula#pubdate", value = TextValueSimpleV1("this is not a date"), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -570,6 +589,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! ChangeValueRequestV1( valueIri = "http://rdfh.ch/0803/c5058f3a/values/c3295339", value = TextValueSimpleV1("Zeitglöcklein des Lebens und Leidens Christi modified"), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -583,6 +603,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! ChangeValueRequestV1( valueIri = "http://rdfh.ch/0803/c5058f3a/values/cfd09f1e01", value = TextValueSimpleV1("this is not a date"), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -599,6 +620,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with resourceIri = "http://rdfh.ch/0803/4f11adaf", propertyIri = "http://www.knora.org/ontology/0803/incunabula#partOf", value = LinkUpdateV1(targetResourceIri = "http://rdfh.ch/0803/e41ab5695c"), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -612,6 +634,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with resourceIri = "http://rdfh.ch/0803/4f11adaf", propertyIri = "http://www.knora.org/ontology/0803/incunabula#seqnum", value = IntegerValueV1(1), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -629,6 +652,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with resourceIri = miscResourceIri, propertyIri = "http://www.knora.org/ontology/0803/incunabula#miscHasColor", value = ColorValueV1(color), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID) @@ -645,6 +669,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! ChangeValueRequestV1( value = ColorValueV1(color), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, valueIri = currentColorValueIri.get, apiRequestID = UUID.randomUUID @@ -665,6 +690,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with resourceIri = miscResourceIri, propertyIri = "http://www.knora.org/ontology/0803/incunabula#miscHasGeometry", value = GeomValueV1(geom), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID) @@ -683,6 +709,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! ChangeValueRequestV1( value = GeomValueV1(geom), valueIri = currentGeomValueIri.get, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -702,6 +729,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with resourceIri = zeitglöckleinIri, propertyIri = "http://www.knora.org/ontology/0803/incunabula#book_comment", value = TextValueWithStandoffV1(utf8str = utf8str, standoff = sampleStandoff, mapping = dummyMapping, mappingIri = "http://rdfh.ch/standoff/mappings/StandardMapping"), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -719,6 +747,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with resourceIri = zeitglöckleinIri, propertyIri = "http://www.knora.org/ontology/0803/incunabula#book_comment", value = TextValueWithStandoffV1(utf8str = utf8str, standoff = sampleStandoff, mapping = dummyMapping, mappingIri = "http://rdfh.ch/standoff/mappings/StandardMapping"), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -736,6 +765,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! ChangeValueRequestV1( valueIri = commentIri.get, value = TextValueWithStandoffV1(utf8str = utf8str, standoff = sampleStandoff, mapping = dummyMapping, mappingIri = "http://rdfh.ch/standoff/mappings/StandardMapping"), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -752,6 +782,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! ChangeValueRequestV1( valueIri = commentIri.get, value = TextValueWithStandoffV1(utf8str = utf8str, standoff = sampleStandoff, mapping = dummyMapping, mappingIri = "http://rdfh.ch/standoff/mappings/StandardMapping"), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -786,6 +817,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with resourceIri = "http://rdfh.ch/0803/21abac2162", propertyIri = "http://www.knora.org/ontology/0803/incunabula#book_comment", value = textValueWithResourceRef, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -800,6 +832,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with subjectIri = "http://rdfh.ch/0803/21abac2162", predicateIri = OntologyConstants.KnoraBase.HasStandoffLinkTo, objectIri = zeitglöckleinIri, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser ) @@ -873,6 +906,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! ChangeValueRequestV1( valueIri = firstValueIriWithResourceRef.get, value = textValueWithResourceRef, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -887,6 +921,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with subjectIri = "http://rdfh.ch/0803/21abac2162", predicateIri = OntologyConstants.KnoraBase.HasStandoffLinkTo, objectIri = zeitglöckleinIri, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser ) @@ -949,6 +984,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with resourceIri = "http://rdfh.ch/0803/21abac2162", propertyIri = "http://www.knora.org/ontology/0803/incunabula#book_comment", value = textValueWithResourceRef, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -963,6 +999,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with subjectIri = "http://rdfh.ch/0803/21abac2162", predicateIri = OntologyConstants.KnoraBase.HasStandoffLinkTo, objectIri = zeitglöckleinIri, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser ) @@ -1008,6 +1045,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! ChangeValueRequestV1( valueIri = firstValueIriWithResourceRef.get, value = textValue, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -1022,6 +1060,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with subjectIri = "http://rdfh.ch/0803/21abac2162", predicateIri = OntologyConstants.KnoraBase.HasStandoffLinkTo, objectIri = zeitglöckleinIri, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser ) @@ -1079,6 +1118,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! ChangeValueRequestV1( valueIri = secondValueIriWithResourceRef.get, value = textValue, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -1095,6 +1135,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with subjectIri = "http://rdfh.ch/0803/21abac2162", predicateIri = OntologyConstants.KnoraBase.HasStandoffLinkTo, objectIri = zeitglöckleinIri, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser ) @@ -1148,6 +1189,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! ChangeValueRequestV1( valueIri = firstValueIriWithResourceRef.get, value = textValueWithResourceRef, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -1162,6 +1204,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with subjectIri = "http://rdfh.ch/0803/21abac2162", predicateIri = OntologyConstants.KnoraBase.HasStandoffLinkTo, objectIri = zeitglöckleinIri, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser ) @@ -1206,6 +1249,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with resourceIri = "http://rdfh.ch/0803/8a0b1e75", propertyIri = "http://www.knora.org/ontology/0803/incunabula#seqnum", value = IntegerValueV1(seqnum), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -1223,6 +1267,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! ChangeValueRequestV1( value = IntegerValueV1(seqnum), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, valueIri = currentSeqnumValueIri.get, apiRequestID = UUID.randomUUID @@ -1242,6 +1287,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with resourceIri = "http://rdfh.ch/0001/a-thing", propertyIri = "http://www.knora.org/ontology/0001/anything#hasTimeStamp", value = TimeValueV1(timeStamp), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = anythingUser, apiRequestID = UUID.randomUUID ) @@ -1259,6 +1305,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! ChangeValueRequestV1( value = TimeValueV1(timeStamp), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = anythingUser, valueIri = currentTimeValueIri.get, apiRequestID = UUID.randomUUID @@ -1284,6 +1331,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with dateprecision2 = KnoraPrecisionV1.DAY, calendar = KnoraCalendarV1.GREGORIAN ), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -1305,6 +1353,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with dateprecision2 = KnoraPrecisionV1.DAY, calendar = KnoraCalendarV1.JULIAN ), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, valueIri = currentPubdateValueIri.get, apiRequestID = UUID.randomUUID @@ -1328,6 +1377,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with value = LinkUpdateV1( targetResourceIri = zeitglöckleinIri ), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -1372,6 +1422,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with value = LinkUpdateV1( targetResourceIri = zeitglöckleinIri ), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -1390,6 +1441,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with value = LinkUpdateV1( targetResourceIri = "http://rdfh.ch/0803/8a0b1e75" // an incunabula:page, not an incunabula:book ), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -1408,6 +1460,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with value = LinkUpdateV1( targetResourceIri = linkTargetIri ), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, valueIri = linkObjLinkValueIri.get, apiRequestID = UUID.randomUUID @@ -1477,6 +1530,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! DeleteValueRequestV1( valueIri = linkObjLinkValueIri.get, deleteComment = Some(comment), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -1523,6 +1577,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with value = LinkUpdateV1( targetResourceIri = linkTargetIri ), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = userProfile, valueIri = partOfLinkValueIri.get, apiRequestID = UUID.randomUUID @@ -1550,6 +1605,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with value = LinkUpdateV1( targetResourceIri = linkTargetIri ), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = userProfile, valueIri = partOfLinkValueIri.get, // use valueIri from previous test apiRequestID = UUID.randomUUID @@ -1572,6 +1628,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with propertyIri = "http://www.knora.org/ontology/0803/incunabula#book_comment", value = TextValueSimpleV1(utf8str = comment), comment = Some(metaComment), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -1591,6 +1648,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with val changeCommentRequest = ChangeCommentRequestV1( valueIri = "http://rdfh.ch/0803/c5058f3a/values/8653a672", comment = comment, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -1624,7 +1682,9 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with resourceIri = "http://rdfh.ch/0803/8a0b1e75", file = fileValue, apiRequestID = UUID.randomUUID, - userProfile = incunabulaUser) + featureFactoryConfig = defaultFeatureFactoryConfig, + userProfile = incunabulaUser + ) responderManager ! fileChangeRequest @@ -1640,6 +1700,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! ChangeValueRequestV1( value = HierarchicalListValueV1(winter), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = imagesUser, valueIri = "http://rdfh.ch/00FF/d208fb9357d5/values/bc90a9c5091004", apiRequestID = UUID.randomUUID @@ -1658,6 +1719,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! CreateValueRequestV1( value = HierarchicalListValueV1(summer), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = imagesUser, propertyIri = s"$IMAGES_ONTOLOGY_IRI#jahreszeit", resourceIri = "http://rdfh.ch/00FF/691e7e2244d5", @@ -1676,6 +1738,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! CreateValueRequestV1( value = decimalValue, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = anythingUser, propertyIri = "http://www.knora.org/ontology/0001/anything#hasDecimal", resourceIri = aThingIri, @@ -1693,6 +1756,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! CreateValueRequestV1( value = intervalValue, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = anythingUser, propertyIri = "http://www.knora.org/ontology/0001/anything#hasInterval", resourceIri = aThingIri, @@ -1710,6 +1774,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! CreateValueRequestV1( value = colorValue, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = anythingUser, propertyIri = "http://www.knora.org/ontology/0001/anything#hasColor", resourceIri = aThingIri, @@ -1764,6 +1829,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! CreateValueRequestV1( value = booleanValue, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = anythingUser, propertyIri = "http://www.knora.org/ontology/0001/anything#hasBoolean", resourceIri = aThingIri, @@ -1781,6 +1847,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! CreateValueRequestV1( value = uriValue, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = anythingUser, propertyIri = "http://www.knora.org/ontology/0001/anything#hasUri", resourceIri = aThingIri, @@ -1805,6 +1872,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with subjectIri = thingWithTextValues, predicateIri = OntologyConstants.KnoraBase.HasStandoffLinkTo, objectIri = aThingIri, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = anythingUser ) @@ -1843,6 +1911,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! DeleteValueRequestV1( valueIri = firstTextValue, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = anythingUser, apiRequestID = UUID.randomUUID ) @@ -1853,6 +1922,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! ValueGetRequestV1( valueIri = deletedFirstTextValue, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = anythingUser ) @@ -1870,6 +1940,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with subjectIri = thingWithTextValues, predicateIri = OntologyConstants.KnoraBase.HasStandoffLinkTo, objectIri = aThingIri, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = anythingUser ) @@ -1908,6 +1979,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! DeleteValueRequestV1( valueIri = secondTextValue, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = anythingUser, apiRequestID = UUID.randomUUID ) @@ -1918,6 +1990,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! ValueGetRequestV1( valueIri = deletedSecondTextValue, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = anythingUser ) @@ -1935,6 +2008,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with subjectIri = thingWithTextValues, predicateIri = OntologyConstants.KnoraBase.HasStandoffLinkTo, objectIri = aThingIri, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = anythingUser ) @@ -1991,6 +2065,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with resourceIri = zeitglöckleinIri, propertyIri = "http://www.knora.org/ontology/0803/incunabula#book_comment", value = textValueWithResourceRef, + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -2005,6 +2080,7 @@ class ValuesResponderV1Spec extends CoreSpec(ValuesResponderV1Spec.config) with responderManager ! CreateValueRequestV1( value = TextValueSimpleV1(utf8str = "Hello World!", language = Some("en")), + featureFactoryConfig = defaultFeatureFactoryConfig, userProfile = anythingUser, propertyIri = "http://www.knora.org/ontology/0001/anything#hasText", resourceIri = "http://rdfh.ch/0001/a-thing-with-text-valuesLanguage", diff --git a/webapi/src/test/scala/org/knora/webapi/responders/v2/ListsResponderV2Spec.scala b/webapi/src/test/scala/org/knora/webapi/responders/v2/ListsResponderV2Spec.scala index a22f6288a0..892160cccc 100644 --- a/webapi/src/test/scala/org/knora/webapi/responders/v2/ListsResponderV2Spec.scala +++ b/webapi/src/test/scala/org/knora/webapi/responders/v2/ListsResponderV2Spec.scala @@ -55,7 +55,11 @@ class ListsResponderV2Spec extends CoreSpec() with ImplicitSender { "return a list" in { - responderManager ! ListGetRequestV2("http://rdfh.ch/lists/0001/treeList", userProfile) + responderManager ! ListGetRequestV2( + listIri = "http://rdfh.ch/lists/0001/treeList", + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = userProfile + ) expectMsgPF(timeout) { case response: ListGetResponseV2 => @@ -66,7 +70,11 @@ class ListsResponderV2Spec extends CoreSpec() with ImplicitSender { "return a node" in { - responderManager ! NodeGetRequestV2("http://rdfh.ch/lists/0001/treeList11", userProfile) + responderManager ! NodeGetRequestV2( + nodeIri = "http://rdfh.ch/lists/0001/treeList11", + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = userProfile + ) expectMsgPF(timeout) { case response: NodeGetResponseV2 => diff --git a/webapi/src/test/scala/org/knora/webapi/responders/v2/MetadataResponderV2Spec.scala b/webapi/src/test/scala/org/knora/webapi/responders/v2/MetadataResponderV2Spec.scala index b1962f5910..5aa23f24da 100644 --- a/webapi/src/test/scala/org/knora/webapi/responders/v2/MetadataResponderV2Spec.scala +++ b/webapi/src/test/scala/org/knora/webapi/responders/v2/MetadataResponderV2Spec.scala @@ -22,13 +22,12 @@ package org.knora.webapi.responders.v2 import java.util.UUID import akka.testkit.ImplicitSender -import org.apache.jena.graph.Graph +import org.knora.webapi.CoreSpec import org.knora.webapi.messages.StringFormatter -import org.knora.webapi.messages.util.RdfFormatUtil +import org.knora.webapi.messages.util.rdf._ import org.knora.webapi.messages.v2.responder.SuccessResponseV2 -import org.knora.webapi.messages.v2.responder.metadatamessages.{MetadataGetRequestV2, MetadataGetResponseV2, MetadataPutRequestV2} +import org.knora.webapi.messages.v2.responder.metadatamessages._ import org.knora.webapi.sharedtestdata.SharedTestDataADM -import org.knora.webapi.{CoreSpec, RdfMediaTypes} import scala.concurrent.duration._ @@ -37,6 +36,7 @@ import scala.concurrent.duration._ */ class MetadataResponderV2Spec extends CoreSpec() with ImplicitSender { private implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance + private val rdfFormatUtil: RdfFormatUtil = RdfFeatureFactory.getRdfFormatUtil(defaultFeatureFactoryConfig) // The default timeout for receiving reply messages from actors. private val timeout = 10.seconds @@ -93,42 +93,42 @@ class MetadataResponderV2Spec extends CoreSpec() with ImplicitSender { | dsp-repo:hasAlternateName "beol" . |""".stripMargin - // Parse the request to a Jena Graph. - private val requestGraph: Graph = RdfFormatUtil.parseToJenaGraph( + // Parse the request to an RdfModel. + private val requestModel: RdfModel = rdfFormatUtil.parseToRdfModel( rdfStr = metadataContent, - mediaType = RdfMediaTypes.`text/turtle` + rdfFormat = Turtle ) "The metadata responder v2" should { "save a metadata graph in the triplestore" in { - responderManager ! MetadataPutRequestV2( - graph = requestGraph, + rdfModel = requestModel, projectADM = SharedTestDataADM.beolProject, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.beolUser, apiRequestID = UUID.randomUUID ) val response = expectMsgType[SuccessResponseV2](timeout) assert(response.message.contains(s"<${SharedTestDataADM.beolProject.id}>")) - } "get the metadata graph of a project" in { responderManager ! MetadataGetRequestV2( projectADM = SharedTestDataADM.beolProject, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.beolUser ) val response = expectMsgType[MetadataGetResponseV2](timeout) - val receivedGraph: Graph = RdfFormatUtil.parseToJenaGraph( + val receivedModel: RdfModel = rdfFormatUtil.parseToRdfModel( rdfStr = response.turtle, - mediaType = RdfMediaTypes.`text/turtle` + rdfFormat = Turtle ) - assert(receivedGraph.isIsomorphicWith(requestGraph)) + assert(receivedModel.isIsomorphicWith(requestModel)) } } } diff --git a/webapi/src/test/scala/org/knora/webapi/responders/v2/OntologyResponderV2Spec.scala b/webapi/src/test/scala/org/knora/webapi/responders/v2/OntologyResponderV2Spec.scala index b2f2e2e5fb..6a6d7a702e 100644 --- a/webapi/src/test/scala/org/knora/webapi/responders/v2/OntologyResponderV2Spec.scala +++ b/webapi/src/test/scala/org/knora/webapi/responders/v2/OntologyResponderV2Spec.scala @@ -37,9 +37,10 @@ import org.knora.webapi.util.MutableTestIri import scala.concurrent.duration._ import scala.language.postfixOps + /** - * Tests [[OntologyResponderV2]]. - */ + * Tests [[OntologyResponderV2]]. + */ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { private implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance @@ -78,13 +79,16 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { storeManager ! ResetRepositoryContent(rdfDataObjs) expectMsg(5 minutes, ResetRepositoryContentACK()) - responderManager ! LoadOntologiesRequestV2(KnoraSystemInstances.Users.SystemUser) + responderManager ! LoadOntologiesRequestV2( + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) if (expectOK) { expectMsgType[SuccessResponseV2](10.seconds) } } - + "The ontology responder v2" should { "not allow a user to create an ontology if they are not a sysadmin or an admin in the ontology's project" in { responderManager ! CreateOntologyRequestV2( @@ -92,6 +96,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { projectIri = imagesProjectIri, label = "The foo ontology", apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser02 ) @@ -108,6 +113,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { projectIri = imagesProjectIri, label = "The foo ontology", apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = imagesUser ) @@ -127,6 +133,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { label = Some(newLabel), lastModificationDate = fooLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = imagesUser ) @@ -148,6 +155,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { comment = Some(aComment), lastModificationDate = fooLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = imagesUser ) @@ -168,6 +176,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { label = "The bar ontology", comment = Some("some comment"), apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = imagesUser ) @@ -189,6 +198,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { comment = Some(newComment), lastModificationDate = barLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = imagesUser ) @@ -208,6 +218,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { projectIri = imagesProjectIri, label = "The foo ontology", apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = imagesUser ) @@ -223,6 +234,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { ontologyIri = "http://0.0.0.0:3333/ontology/1234/nonexistent/v2".toSmartIri, lastModificationDate = fooLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = imagesUser ) @@ -238,6 +250,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { ontologyIri = fooIri.get.toSmartIri.toOntologySchema(ApiV2Complex), lastModificationDate = fooLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser02 ) @@ -253,6 +266,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { ontologyIri = fooIri.get.toSmartIri.toOntologySchema(ApiV2Complex), lastModificationDate = fooLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = imagesUser ) @@ -269,7 +283,11 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { // Reload the ontologies from the triplestore and check again. - responderManager ! LoadOntologiesRequestV2(KnoraSystemInstances.Users.SystemUser) + responderManager ! LoadOntologiesRequestV2( + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) + expectMsgType[SuccessResponseV2](10.seconds) responderManager ! OntologyMetadataGetByProjectRequestV2( @@ -294,6 +312,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { ontologyIri = AnythingOntologyIri, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -322,6 +341,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { projectIri = imagesProjectIri, label = "The rdfs ontology", apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = imagesUser ) @@ -339,6 +359,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { projectIri = imagesProjectIri, label = "The 0000 ontology", apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = imagesUser ) @@ -356,6 +377,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { projectIri = imagesProjectIri, label = "The -foo ontology", apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = imagesUser ) @@ -373,6 +395,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { projectIri = imagesProjectIri, label = "The v3 ontology", apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = imagesUser ) @@ -390,6 +413,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { projectIri = imagesProjectIri, label = "The ontology ontology", apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = imagesUser ) @@ -407,6 +431,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { projectIri = imagesProjectIri, label = "The wrong knora ontology", apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = imagesUser ) @@ -424,6 +449,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { projectIri = imagesProjectIri, label = "The simple ontology", apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = imagesUser ) @@ -441,6 +467,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { projectIri = imagesProjectIri, label = "The invalid shared ontology", apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = imagesUser ) @@ -459,6 +486,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { isShared = true, label = "The invalid shared ontology", apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = imagesUser ) @@ -475,6 +503,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { projectIri = OntologyConstants.KnoraAdmin.DefaultSharedOntologiesProject.toSmartIri, label = "The invalid non-shared ontology", apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.superUser ) @@ -492,6 +521,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { isShared = true, label = "a chaired ontology", apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.superUser ) @@ -554,6 +584,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingNonAdminUser ) @@ -615,6 +646,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -631,7 +663,11 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { // Reload the ontology cache and see if we get the same result. - responderManager ! LoadOntologiesRequestV2(KnoraSystemInstances.Users.SystemUser) + responderManager ! LoadOntologiesRequestV2( + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) + expectMsgType[SuccessResponseV2](10.seconds) responderManager ! PropertiesGetRequestV2( @@ -698,6 +734,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -736,7 +773,11 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { // Reload the ontology cache and see if we get the same result. - responderManager ! LoadOntologiesRequestV2(KnoraSystemInstances.Users.SystemUser) + responderManager ! LoadOntologiesRequestV2( + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) + expectMsgType[SuccessResponseV2](10.seconds) responderManager ! PropertiesGetRequestV2( @@ -809,6 +850,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -859,6 +901,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -909,6 +952,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -959,6 +1003,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -1009,6 +1054,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -1062,6 +1108,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -1112,6 +1159,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -1162,6 +1210,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -1212,6 +1261,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -1262,6 +1312,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -1312,6 +1363,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -1362,6 +1414,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -1412,6 +1465,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -1462,6 +1516,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -1512,6 +1567,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -1562,6 +1618,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -1612,6 +1669,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -1663,6 +1721,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -1722,6 +1781,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -1780,6 +1840,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -1806,6 +1867,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { newObjects = newObjects, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingNonAdminUser ) @@ -1832,6 +1894,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { newObjects = newObjects, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -1865,6 +1928,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { newObjects = newObjects, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingNonAdminUser ) @@ -1896,6 +1960,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { newObjects = newObjects, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -1945,6 +2010,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingNonAdminUser ) @@ -1986,6 +2052,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -2027,6 +2094,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -2067,6 +2135,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -2092,6 +2161,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { label = Some(newLabel), lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -2112,6 +2182,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classIri = classIri, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -2156,6 +2227,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -2243,6 +2315,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -2281,6 +2354,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { newObjects = newObjects, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingNonAdminUser ) @@ -2304,6 +2378,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { newObjects = newObjects, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -2336,6 +2411,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { newObjects = newObjects, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingNonAdminUser ) @@ -2364,6 +2440,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { newObjects = newObjects, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -2412,6 +2489,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -2453,6 +2531,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -2494,6 +2573,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -2535,6 +2615,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -2577,6 +2658,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -2619,6 +2701,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -2661,6 +2744,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -2711,6 +2795,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -2729,6 +2814,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyIri = hasInterestingThingValue, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -2748,6 +2834,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyIri = linkPropIri, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -2794,7 +2881,11 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { // Reload the ontology cache and see if we get the same result. - responderManager ! LoadOntologiesRequestV2(KnoraSystemInstances.Users.SystemUser) + responderManager ! LoadOntologiesRequestV2( + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) + expectMsgType[SuccessResponseV2](10.seconds) responderManager ! linkPropGetRequest @@ -2860,6 +2951,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -2916,6 +3008,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -2957,6 +3050,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -2994,6 +3088,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -3032,6 +3127,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -3049,6 +3145,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classIri = classIri, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingNonAdminUser ) @@ -3065,6 +3162,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classIri = classIri, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -3100,6 +3198,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingNonAdminUser ) @@ -3149,6 +3248,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -3179,6 +3279,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -3236,6 +3337,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -3289,6 +3391,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -3340,6 +3443,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -3378,6 +3482,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -3434,6 +3539,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingNonAdminUser ) @@ -3464,6 +3570,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -3501,6 +3608,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classIri = classIri, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -3518,6 +3626,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyIri = hasNothingness, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -3538,6 +3647,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyIri = hasNothingness, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -3567,6 +3677,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingNonAdminUser ) @@ -3595,6 +3706,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -3625,6 +3737,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyIri = hasEmptiness, lastModificationDate = anythingLastModDate.minusSeconds(60), apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -3642,6 +3755,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyIri = hasEmptiness, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingNonAdminUser ) @@ -3659,6 +3773,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyIri = hasOtherNothing, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -3677,6 +3792,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyIri = hasEmptiness, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -3697,6 +3813,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classIri = classIri, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -3737,6 +3854,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -3775,6 +3893,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -3821,6 +3940,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -3871,6 +3991,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -3917,6 +4038,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -3954,6 +4076,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -3978,6 +4101,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classIri = classIri, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -4019,6 +4143,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classInfoContent = classInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -4043,6 +4168,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { classIri = classIri, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -4087,6 +4213,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -4111,6 +4238,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyIri = propertyIri, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -4159,6 +4287,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -4183,6 +4312,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyIri = propertyIri, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -4227,6 +4357,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyInfoContent = propertyInfoContent, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) @@ -4251,6 +4382,7 @@ class OntologyResponderV2Spec extends CoreSpec() with ImplicitSender { propertyIri = propertyIri, lastModificationDate = anythingLastModDate, apiRequestID = UUID.randomUUID, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingAdminUser ) diff --git a/webapi/src/test/scala/org/knora/webapi/responders/v2/ResourcesResponderV2Spec.scala b/webapi/src/test/scala/org/knora/webapi/responders/v2/ResourcesResponderV2Spec.scala index 8c800a9c58..7b9b67e98b 100644 --- a/webapi/src/test/scala/org/knora/webapi/responders/v2/ResourcesResponderV2Spec.scala +++ b/webapi/src/test/scala/org/knora/webapi/responders/v2/ResourcesResponderV2Spec.scala @@ -470,14 +470,19 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { ) private def getResource(resourceIri: IRI, requestingUser: UserADM): ReadResourceV2 = { - responderManager ! ResourcesGetRequestV2(resourceIris = Seq(resourceIri), targetSchema = ApiV2Complex, requestingUser = anythingUserProfile) + responderManager ! ResourcesGetRequestV2( + resourceIris = Seq(resourceIri), + targetSchema = ApiV2Complex, + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = anythingUserProfile + ) expectMsgPF(timeout) { case response: ReadResourcesSequenceV2 => response.toResource(resourceIri).toOntologySchema(ApiV2Complex) } } - private def checkCreateResource(inputResourceIri :IRI, + private def checkCreateResource(inputResourceIri: IRI, inputResource: CreateResourceV2, outputResource: ReadResourceV2, defaultResourcePermissions: String, @@ -549,7 +554,11 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { private val timeout = 10.seconds "Load test data" in { - responderManager ! GetMappingRequestV2(mappingIri = "http://rdfh.ch/standoff/mappings/StandardMapping", requestingUser = KnoraSystemInstances.Users.SystemUser) + responderManager ! GetMappingRequestV2( + mappingIri = "http://rdfh.ch/standoff/mappings/StandardMapping", + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) expectMsgPF(timeout) { case mappingResponse: GetMappingResponseV2 => @@ -564,6 +573,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { resourceIris = Seq("http://rdfh.ch/0803/c5058f3a"), versionDate = None, targetSchema = ApiV2Complex, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUserProfile ) @@ -576,7 +586,12 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { "return a preview descriptions of the book 'Zeitglöcklein des Lebens und Leidens Christi' in the Incunabula test data" in { - responderManager ! ResourcesPreviewGetRequestV2(Seq("http://rdfh.ch/0803/c5058f3a"), ApiV2Complex, incunabulaUserProfile) + responderManager ! ResourcesPreviewGetRequestV2( + Seq("http://rdfh.ch/0803/c5058f3a"), + ApiV2Complex, + featureFactoryConfig = defaultFeatureFactoryConfig, + incunabulaUserProfile + ) expectMsgPF(timeout) { case response: ReadResourcesSequenceV2 => @@ -591,6 +606,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { resourceIris = Seq("http://rdfh.ch/0803/2a6221216701"), versionDate = None, targetSchema = ApiV2Complex, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUserProfile ) @@ -603,7 +619,13 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { "return two full descriptions of the book 'Zeitglöcklein des Lebens und Leidens Christi' and the book 'Reise ins Heilige Land' in the Incunabula test data" in { - responderManager ! ResourcesGetRequestV2(resourceIris = Seq("http://rdfh.ch/0803/c5058f3a", "http://rdfh.ch/0803/2a6221216701"), versionDate = None, targetSchema = ApiV2Complex, requestingUser = incunabulaUserProfile) + responderManager ! ResourcesGetRequestV2( + resourceIris = Seq("http://rdfh.ch/0803/c5058f3a", "http://rdfh.ch/0803/2a6221216701"), + versionDate = None, + targetSchema = ApiV2Complex, + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = incunabulaUserProfile + ) expectMsgPF(timeout) { case response: ReadResourcesSequenceV2 => @@ -614,7 +636,12 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { "return two preview descriptions of the book 'Zeitglöcklein des Lebens und Leidens Christi' and the book 'Reise ins Heilige Land' in the Incunabula test data" in { - responderManager ! ResourcesPreviewGetRequestV2(Seq("http://rdfh.ch/0803/c5058f3a", "http://rdfh.ch/0803/2a6221216701"), ApiV2Complex, incunabulaUserProfile) + responderManager ! ResourcesPreviewGetRequestV2( + resourceIris = Seq("http://rdfh.ch/0803/c5058f3a", "http://rdfh.ch/0803/2a6221216701"), + targetSchema = ApiV2Complex, + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = incunabulaUserProfile + ) expectMsgPF(timeout) { case response: ReadResourcesSequenceV2 => @@ -629,6 +656,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { resourceIris = Seq("http://rdfh.ch/0803/2a6221216701", "http://rdfh.ch/0803/c5058f3a"), versionDate = None, targetSchema = ApiV2Complex, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUserProfile ) @@ -645,6 +673,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { resourceIris = Seq("http://rdfh.ch/0803/c5058f3a", "http://rdfh.ch/0803/c5058f3a", "http://rdfh.ch/0803/2a6221216701"), versionDate = None, targetSchema = ApiV2Complex, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUserProfile ) @@ -658,7 +687,14 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { "return a resource of type thing with text as TEI/XML" in { - responderManager ! ResourceTEIGetRequestV2(resourceIri = "http://rdfh.ch/0001/thing_with_richtext_with_markup", textProperty = "http://www.knora.org/ontology/0001/anything#hasRichtext".toSmartIri, mappingIri = None, gravsearchTemplateIri = None, headerXSLTIri = None, requestingUser = anythingUserProfile) + responderManager ! ResourceTEIGetRequestV2( + resourceIri = "http://rdfh.ch/0001/thing_with_richtext_with_markup", + textProperty = "http://www.knora.org/ontology/0001/anything#hasRichtext".toSmartIri, + mappingIri = None, gravsearchTemplateIri = None, + headerXSLTIri = None, + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = anythingUserProfile + ) expectMsgPF(timeout) { case response: ResourceTEIGetResponseV2 => @@ -676,7 +712,14 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { "return a resource of type Something with text with standoff as TEI/XML" in { - responderManager ! ResourceTEIGetRequestV2(resourceIri = "http://rdfh.ch/0001/qN1igiDRSAemBBktbRHn6g", textProperty = "http://www.knora.org/ontology/0001/anything#hasRichtext".toSmartIri, mappingIri = None, gravsearchTemplateIri = None, headerXSLTIri = None, requestingUser = anythingUserProfile) + responderManager ! ResourceTEIGetRequestV2( + resourceIri = "http://rdfh.ch/0001/qN1igiDRSAemBBktbRHn6g", + textProperty = "http://www.knora.org/ontology/0001/anything#hasRichtext".toSmartIri, + mappingIri = None, gravsearchTemplateIri = None, + headerXSLTIri = None, + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = anythingUserProfile + ) expectMsgPF(timeout) { case response: ResourceTEIGetResponseV2 => @@ -700,6 +743,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { resourceIris = Seq(resourceIri), versionDate = Some(versionDate), targetSchema = ApiV2Complex, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile ) @@ -717,6 +761,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { resourceIri = resourceIri, startDate = None, endDate = None, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile ) @@ -735,6 +780,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { resourceIri = resourceIri, startDate = Some(startDate), endDate = Some(endDate), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile ) @@ -749,6 +795,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { resourceIris = Seq("http://rdfh.ch/0001/thing-with-history"), valueUuid = Some(stringFormatter.decodeUuid("pLlW4ODASumZfZFbJdpw1g")), targetSchema = ApiV2Complex, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile ) @@ -764,6 +811,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { valueUuid = Some(stringFormatter.decodeUuid("pLlW4ODASumZfZFbJdpw1g")), versionDate = Some(Instant.parse("2019-02-12T09:05:10Z")), targetSchema = ApiV2Complex, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile ) @@ -854,6 +902,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile, apiRequestID = UUID.randomUUID ) @@ -904,6 +953,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile, apiRequestID = UUID.randomUUID ) @@ -1062,6 +1112,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile, apiRequestID = UUID.randomUUID ) @@ -1115,6 +1166,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile, apiRequestID = UUID.randomUUID ) @@ -1148,6 +1200,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUserProfile, apiRequestID = UUID.randomUUID ) @@ -1195,6 +1248,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUserProfile, apiRequestID = UUID.randomUUID ) @@ -1236,6 +1290,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUserProfile, apiRequestID = UUID.randomUUID ) @@ -1281,6 +1336,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUserProfile, apiRequestID = UUID.randomUUID ) @@ -1314,6 +1370,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile, apiRequestID = UUID.randomUUID ) @@ -1347,6 +1404,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile, apiRequestID = UUID.randomUUID ) @@ -1414,6 +1472,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile, apiRequestID = UUID.randomUUID ) @@ -1447,6 +1506,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile, apiRequestID = UUID.randomUUID ) @@ -1480,6 +1540,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile, apiRequestID = UUID.randomUUID ) @@ -1513,6 +1574,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile, apiRequestID = UUID.randomUUID ) @@ -1536,6 +1598,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile, apiRequestID = UUID.randomUUID ) @@ -1571,6 +1634,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile, apiRequestID = UUID.randomUUID ) @@ -1593,6 +1657,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUserProfile, apiRequestID = UUID.randomUUID ) @@ -1607,6 +1672,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { resourceIri = aThingIri, resourceClassIri = "http://0.0.0.0:3333/ontology/0001/anything/v2#Thing".toSmartIri, maybeLabel = Some("new test label"), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUserProfile, apiRequestID = UUID.randomUUID ) @@ -1623,6 +1689,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { resourceIri = aThingIri, resourceClassIri = "http://0.0.0.0:3333/ontology/0001/anything/v2#BlueThing".toSmartIri, maybeLabel = Some("new test label"), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile, apiRequestID = UUID.randomUUID ) @@ -1644,6 +1711,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { resourceClassIri = "http://0.0.0.0:3333/ontology/0001/anything/v2#Thing".toSmartIri, maybeLabel = Some(newLabel), maybePermissions = Some(newPermissions), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile, apiRequestID = UUID.randomUUID ) @@ -1666,6 +1734,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { resourceIri = aThingIri, resourceClassIri = "http://0.0.0.0:3333/ontology/0001/anything/v2#Thing".toSmartIri, maybeLabel = Some("another new test label"), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile, apiRequestID = UUID.randomUUID ) @@ -1683,6 +1752,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { resourceClassIri = "http://0.0.0.0:3333/ontology/0001/anything/v2#Thing".toSmartIri, maybeLastModificationDate = Some(Instant.MIN), maybeLabel = Some("another new test label"), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile, apiRequestID = UUID.randomUUID ) @@ -1702,6 +1772,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { resourceClassIri = "http://0.0.0.0:3333/ontology/0001/anything/v2#Thing".toSmartIri, maybeLastModificationDate = Some(aThingLastModificationDate), maybeLabel = Some(newLabel), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile, apiRequestID = UUID.randomUUID ) @@ -1725,6 +1796,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { resourceClassIri = "http://0.0.0.0:3333/ontology/0001/anything/v2#Thing".toSmartIri, maybeLastModificationDate = Some(aThingLastModificationDate), maybeNewModificationDate = Some(Instant.MIN), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile, apiRequestID = UUID.randomUUID ) @@ -1744,6 +1816,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { resourceClassIri = "http://0.0.0.0:3333/ontology/0001/anything/v2#Thing".toSmartIri, maybeLastModificationDate = Some(aThingLastModificationDate), maybeNewModificationDate = Some(newModificationDate), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile, apiRequestID = UUID.randomUUID ) @@ -1769,6 +1842,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { maybeDeleteComment = Some("This resource is too boring."), maybeDeleteDate = Some(deleteDate), maybeLastModificationDate = Some(aThingLastModificationDate), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.anythingUser1, apiRequestID = UUID.randomUUID ) @@ -1786,6 +1860,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { resourceClassIri = "http://0.0.0.0:3333/ontology/0001/anything/v2#Thing".toSmartIri, maybeDeleteComment = Some("This resource is too boring."), maybeLastModificationDate = Some(aThingLastModificationDate), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.anythingUser1, apiRequestID = UUID.randomUUID ) @@ -1796,7 +1871,12 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { // We should now be unable to request the resource. - responderManager ! ResourcesGetRequestV2(resourceIris = Seq(aThingIri), targetSchema = ApiV2Complex, requestingUser = SharedTestDataADM.anythingUser1) + responderManager ! ResourcesGetRequestV2( + resourceIris = Seq(aThingIri), + targetSchema = ApiV2Complex, + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = SharedTestDataADM.anythingUser1 + ) expectMsgPF(timeout) { case msg: akka.actor.Status.Failure => msg.cause.isInstanceOf[NotFoundException] should ===(true) @@ -1813,6 +1893,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { maybeDeleteComment = Some("This resource is too boring."), maybeDeleteDate = Some(deleteDate), maybeLastModificationDate = None, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.superUser, apiRequestID = UUID.randomUUID ) @@ -1823,7 +1904,12 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { // We should now be unable to request the resource. - responderManager ! ResourcesGetRequestV2(resourceIris = Seq(resourceIri), targetSchema = ApiV2Complex, requestingUser = SharedTestDataADM.anythingUser1) + responderManager ! ResourcesGetRequestV2( + resourceIris = Seq(resourceIri), + targetSchema = ApiV2Complex, + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = SharedTestDataADM.anythingUser1 + ) expectMsgPF(timeout) { case msg: akka.actor.Status.Failure => msg.cause.isInstanceOf[NotFoundException] should ===(true) @@ -1847,6 +1933,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesReviewerUser, apiRequestID = UUID.randomUUID ) @@ -1871,6 +1958,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser, apiRequestID = UUID.randomUUID ) @@ -1892,6 +1980,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser01, apiRequestID = UUID.randomUUID ) @@ -1925,6 +2014,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesReviewerUser, apiRequestID = UUID.randomUUID ) @@ -1961,11 +2051,12 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser, apiRequestID = UUID.randomUUID ) - expectMsgClass(timeout,(classOf[ReadResourcesSequenceV2])) + expectMsgClass(timeout, (classOf[ReadResourcesSequenceV2])) } "accept custom value permissions that would give the requesting user a higher permission on a value than the default if the user is a project admin" in { @@ -1994,6 +2085,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser01, apiRequestID = UUID.randomUUID ) @@ -2034,6 +2126,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile, apiRequestID = UUID.randomUUID ) @@ -2063,6 +2156,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { mapping = standardMapping ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile, apiRequestID = UUID.randomUUID ) @@ -2099,6 +2193,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { resourceClassIri = "http://0.0.0.0:3333/ontology/0001/anything/v2#Thing".toSmartIri, maybeLastModificationDate = Some(resourceToEraseLastModificationDate), erase = true, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile, apiRequestID = UUID.randomUUID ) @@ -2140,6 +2235,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile, apiRequestID = UUID.randomUUID ) @@ -2155,6 +2251,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { resourceClassIri = "http://0.0.0.0:3333/ontology/0001/anything/v2#Thing".toSmartIri, maybeLastModificationDate = Some(resourceToEraseLastModificationDate), erase = true, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.anythingAdminUser, apiRequestID = UUID.randomUUID ) @@ -2175,6 +2272,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { propertyIri = linkValuePropertyIri, valueIri = linkValue.valueIri, valueTypeIri = OntologyConstants.KnoraApiV2Complex.LinkValue.toSmartIri, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUserProfile, apiRequestID = UUID.randomUUID ) @@ -2190,6 +2288,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { resourceClassIri = "http://0.0.0.0:3333/ontology/0001/anything/v2#Thing".toSmartIri, maybeLastModificationDate = Some(resourceToEraseLastModificationDate), erase = true, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.anythingAdminUser, apiRequestID = UUID.randomUUID ) @@ -2200,11 +2299,11 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { // Check that all parts of the resource were erased. val erasedIrisToCheck: Set[SmartIri] = ( - standoffTagIrisToErase.toSet + - resourceIriToErase.get + - firstValueIriToErase.get + - secondValueIriToErase.get - ).map(_.toSmartIri) + standoffTagIrisToErase.toSet + + resourceIriToErase.get + + firstValueIriToErase.get + + secondValueIriToErase.get + ).map(_.toSmartIri) for (erasedIriToCheck <- erasedIrisToCheck) { val sparqlQuery = org.knora.webapi.messages.twirl.queries.sparql.admin.txt.checkIriExists( @@ -2215,7 +2314,7 @@ class ResourcesResponderV2Spec extends CoreSpec() with ImplicitSender { expectMsgPF(timeout) { case entityExistsResponse: SparqlAskResponse => - entityExistsResponse.result should be (false) + entityExistsResponse.result should be(false) } } diff --git a/webapi/src/test/scala/org/knora/webapi/responders/v2/SearchResponderV2Spec.scala b/webapi/src/test/scala/org/knora/webapi/responders/v2/SearchResponderV2Spec.scala index 847f11c194..999920f51e 100644 --- a/webapi/src/test/scala/org/knora/webapi/responders/v2/SearchResponderV2Spec.scala +++ b/webapi/src/test/scala/org/knora/webapi/responders/v2/SearchResponderV2Spec.scala @@ -20,20 +20,20 @@ package org.knora.webapi.responders.v2 import akka.testkit.ImplicitSender +import org.knora.webapi.messages.IriConversions._ +import org.knora.webapi.messages.StringFormatter import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject import org.knora.webapi.messages.v2.responder.resourcemessages._ import org.knora.webapi.messages.v2.responder.searchmessages._ import org.knora.webapi.responders.v2.ResourcesResponseCheckerV2.compareReadResourcesSequenceV2Response -import org.knora.webapi.messages.IriConversions._ -import org.knora.webapi.{ApiV2Complex, CoreSpec, MarkupAsXml, SchemaOptions} -import org.knora.webapi.messages.StringFormatter import org.knora.webapi.sharedtestdata.SharedTestDataADM +import org.knora.webapi.{ApiV2Complex, CoreSpec, SchemaOptions} import scala.concurrent.duration._ /** - * Tests [[SearchResponderV2]]. - */ + * Tests [[SearchResponderV2]]. + */ class SearchResponderV2Spec extends CoreSpec() with ImplicitSender { private implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance @@ -60,6 +60,7 @@ class SearchResponderV2Spec extends CoreSpec() with ImplicitSender { limitToStandoffClass = None, targetSchema = ApiV2Complex, schemaOptions = SchemaOptions.ForStandoffWithTextValues, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.anonymousUser ) @@ -83,6 +84,7 @@ class SearchResponderV2Spec extends CoreSpec() with ImplicitSender { limitToStandoffClass = None, targetSchema = ApiV2Complex, schemaOptions = SchemaOptions.ForStandoffWithTextValues, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.anythingUser1 ) @@ -100,6 +102,7 @@ class SearchResponderV2Spec extends CoreSpec() with ImplicitSender { constructQuery = searchResponderV2SpecFullData.constructQueryForBooksWithTitleZeitgloecklein, targetSchema = ApiV2Complex, schemaOptions = SchemaOptions.ForStandoffWithTextValues, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.anonymousUser ) @@ -117,6 +120,7 @@ class SearchResponderV2Spec extends CoreSpec() with ImplicitSender { constructQuery = searchResponderV2SpecFullData.constructQueryForBooksWithoutTitleZeitgloecklein, targetSchema = ApiV2Complex, schemaOptions = SchemaOptions.ForStandoffWithTextValues, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.anonymousUser ) @@ -137,6 +141,7 @@ class SearchResponderV2Spec extends CoreSpec() with ImplicitSender { limitToProject = None, limitToResourceClass = Some("http://www.knora.org/ontology/0803/incunabula#book".toSmartIri), // internal Iri! targetSchema = ApiV2Complex, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.anonymousUser ) @@ -155,6 +160,7 @@ class SearchResponderV2Spec extends CoreSpec() with ImplicitSender { limitToProject = None, limitToResourceClass = Some("http://www.knora.org/ontology/0803/incunabula#book".toSmartIri), // internal Iri! targetSchema = ApiV2Complex, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.anonymousUser ) @@ -171,6 +177,7 @@ class SearchResponderV2Spec extends CoreSpec() with ImplicitSender { searchValue = "Narrenschiff", limitToProject = None, limitToResourceClass = Some("http://www.knora.org/ontology/0803/incunabula#book".toSmartIri), // internal Iri! + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.anonymousUser ) @@ -187,6 +194,7 @@ class SearchResponderV2Spec extends CoreSpec() with ImplicitSender { searchValue = "Das Narrenschiff", limitToProject = None, limitToResourceClass = Some("http://www.knora.org/ontology/0803/incunabula#book".toSmartIri), // internal Iri! + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.anonymousUser ) @@ -205,6 +213,7 @@ class SearchResponderV2Spec extends CoreSpec() with ImplicitSender { schemaOptions = SchemaOptions.ForStandoffWithTextValues, page = 0, targetSchema = ApiV2Complex, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.incunabulaProjectAdminUser ) diff --git a/webapi/src/test/scala/org/knora/webapi/responders/v2/ValuesResponderV2Spec.scala b/webapi/src/test/scala/org/knora/webapi/responders/v2/ValuesResponderV2Spec.scala index 42b29d4f0b..fcb03ac659 100644 --- a/webapi/src/test/scala/org/knora/webapi/responders/v2/ValuesResponderV2Spec.scala +++ b/webapi/src/test/scala/org/knora/webapi/responders/v2/ValuesResponderV2Spec.scala @@ -46,8 +46,8 @@ import org.knora.webapi.util.MutableTestIri import scala.concurrent.duration._ /** - * Tests [[ValuesResponderV2]]. - */ + * Tests [[ValuesResponderV2]]. + */ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { private implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance @@ -179,6 +179,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { constructQuery = parsedGravsearchQuery, targetSchema = ApiV2Complex, schemaOptions = SchemaOptions.ForStandoffWithTextValues, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = requestingUser ) @@ -292,7 +293,12 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { } private def getResourceLastModificationDate(resourceIri: IRI, requestingUser: UserADM): Option[Instant] = { - responderManager ! ResourcesPreviewGetRequestV2(resourceIris = Seq(resourceIri), targetSchema = ApiV2Complex, requestingUser = requestingUser) + responderManager ! ResourcesPreviewGetRequestV2( + resourceIris = Seq(resourceIri), + targetSchema = ApiV2Complex, + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = requestingUser + ) expectMsgPF(timeout) { case previewResponse: ReadResourcesSequenceV2 => @@ -354,7 +360,11 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { } "Load test data" in { - responderManager ! GetMappingRequestV2(mappingIri = "http://rdfh.ch/standoff/mappings/StandardMapping", requestingUser = KnoraSystemInstances.Users.SystemUser) + responderManager ! GetMappingRequestV2( + mappingIri = "http://rdfh.ch/standoff/mappings/StandardMapping", + featureFactoryConfig = defaultFeatureFactoryConfig, + requestingUser = KnoraSystemInstances.Users.SystemUser + ) expectMsgPF(timeout) { case mappingResponse: GetMappingResponseV2 => @@ -381,6 +391,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasInteger = intValue ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -424,6 +435,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasInteger = intValue ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -464,6 +476,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasInteger = intValue ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -515,6 +528,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasInteger = intValue ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -557,6 +571,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { comment = Some(comment) ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -609,6 +624,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { comment = Some(comment) ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -651,6 +667,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { comment = Some(comment) ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -705,6 +722,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { comment = Some(comment) ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -754,6 +772,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { ), permissions = Some(permissions) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -799,6 +818,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { ), permissions = Some(permissions) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -826,6 +846,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { ), permissions = Some(permissions) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -857,6 +878,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueUUID = Some(valueUUID), valueCreationDate = Some(valueCreationDate) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -904,6 +926,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { ), valueCreationDate = Some(valueCreationDate) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -935,6 +958,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { ), valueCreationDate = Some(valueCreationDate) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -986,6 +1010,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { ), newValueVersionIri = Some(newValueVersionIri.toSmartIri) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -1030,6 +1055,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasInteger = intValue ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -1054,6 +1080,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { maybeValueHasString = Some(valueHasString) ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -1093,6 +1120,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { maybeValueHasString = Some(valueHasString) ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -1119,6 +1147,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { comment = Some(valueHasComment) ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -1166,6 +1195,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { mapping = standardMapping ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -1214,6 +1244,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { mapping = standardMapping ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -1241,6 +1272,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasDecimal = valueHasDecimal ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -1281,6 +1313,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasDecimal = valueHasDecimal ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -1308,6 +1341,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasTimeStamp = valueHasTimeStamp ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -1356,6 +1390,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { propertyIri = propertyIri, valueContent = submittedValueContent ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -1407,6 +1442,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { propertyIri = propertyIri, valueContent = submittedValueContent ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -1434,6 +1470,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasBoolean = valueHasBoolean ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -1477,6 +1514,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasGeometry = valueHasGeometry ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -1517,6 +1555,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasGeometry = valueHasGeometry ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -1546,6 +1585,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasIntervalEnd = valueHasIntervalEnd ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -1591,6 +1631,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasIntervalEnd = valueHasIntervalEnd ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -1618,6 +1659,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasListNode = valueHasListNode ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -1660,6 +1702,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasListNode = valueHasListNode ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -1684,6 +1727,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasListNode = valueHasListNode ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -1711,6 +1755,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasColor = valueHasColor ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -1753,6 +1798,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasColor = valueHasColor ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -1780,6 +1826,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasUri = valueHasUri ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -1822,6 +1869,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasUri = valueHasUri ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -1849,6 +1897,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasGeonameCode = valueHasGeonameCode ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -1891,6 +1940,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasGeonameCode = valueHasGeonameCode ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -1916,6 +1966,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { referredResourceIri = zeitglöckleinIri ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -1960,6 +2011,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { referredResourceIri = zeitglöckleinIri ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -1985,6 +2037,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { referredResourceIri = zeitglöckleinIri ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -2007,6 +2060,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { referredResourceIri = generationeIri ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.superUser, apiRequestID = UUID.randomUUID ) @@ -2031,6 +2085,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasInteger = intValue ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -2056,6 +2111,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { maybeValueHasString = Some(valueHasString) ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -2080,6 +2136,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasInteger = intValue ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -2104,6 +2161,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { maybeValueHasString = Some("this is not a date") ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -2128,6 +2186,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { referredResourceIri = "http://rdfh.ch/0803/e41ab5695c" ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -2148,6 +2207,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasInteger = 1 ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -2187,6 +2247,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { mapping = standardMapping ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -2276,6 +2337,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { mapping = standardMapping ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -2352,6 +2414,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasInteger = intValue ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -2377,6 +2440,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasInteger = intValue ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -2405,6 +2469,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { ), permissions = Some(permissions) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -2451,6 +2516,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { ), permissions = Some(permissions) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser2, apiRequestID = UUID.randomUUID ) @@ -2478,6 +2544,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { ), permissions = Some(permissions) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -2505,6 +2572,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { ), permissions = Some(permissions) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -2539,6 +2607,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueType = OntologyConstants.KnoraApiV2Complex.IntValue.toSmartIri, permissions = permissions ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -2576,6 +2645,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueType = OntologyConstants.KnoraApiV2Complex.IntValue.toSmartIri, permissions = permissions ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser2, apiRequestID = UUID.randomUUID ) @@ -2599,6 +2669,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueType = OntologyConstants.KnoraApiV2Complex.IntValue.toSmartIri, permissions = permissions ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -2622,6 +2693,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueType = OntologyConstants.KnoraApiV2Complex.IntValue.toSmartIri, permissions = permissions ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -2647,6 +2719,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasInteger = intValue ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -2672,6 +2745,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { maybeValueHasString = Some(valueHasString) ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -2717,6 +2791,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { mapping = standardMapping ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -2787,6 +2862,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { maybeValueHasString = Some(valueHasString) ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -2815,6 +2891,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { mapping = standardMapping ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -2864,6 +2941,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { mapping = standardMapping ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -2893,6 +2971,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { mapping = standardMapping ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -2943,6 +3022,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { mapping = standardMapping ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -2967,6 +3047,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { maybeValueHasString = Some(valueHasString) ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -2993,6 +3074,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasDecimal = valueHasDecimal ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -3034,6 +3116,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasDecimal = valueHasDecimal ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -3060,6 +3143,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasTimeStamp = valueHasTimeStamp ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -3101,6 +3185,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasTimeStamp = valueHasTimeStamp ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -3132,6 +3217,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueIri = dateValueIri.get, valueContent = submittedValueContent ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -3184,6 +3270,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueIri = dateValueIri.get, valueContent = submittedValueContent ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -3210,6 +3297,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasBoolean = valueHasBoolean ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -3251,6 +3339,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasBoolean = valueHasBoolean ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -3277,6 +3366,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasGeometry = valueHasGeometry ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -3318,6 +3408,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasGeometry = valueHasGeometry ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -3346,6 +3437,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasIntervalEnd = valueHasIntervalEnd ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -3392,6 +3484,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasIntervalEnd = valueHasIntervalEnd ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -3418,6 +3511,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasListNode = valueHasListNode ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -3461,6 +3555,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasListNode = valueHasListNode ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -3486,6 +3581,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasListNode = valueHasListNode ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -3512,6 +3608,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasColor = valueHasColor ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -3555,6 +3652,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasColor = valueHasColor ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -3581,6 +3679,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasUri = valueHasUri ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -3624,6 +3723,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasUri = valueHasUri ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -3650,6 +3750,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasGeonameCode = valueHasGeonameCode ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -3693,6 +3794,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueHasGeonameCode = valueHasGeonameCode ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -3719,6 +3821,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { referredResourceIri = generationeIri ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -3767,6 +3870,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { referredResourceIri = generationeIri ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -3797,6 +3901,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { comment = Some(comment) ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -3847,6 +3952,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { comment = Some(comment) ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -3877,6 +3983,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { comment = Some(comment) ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -3928,6 +4035,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { comment = Some(comment) ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -3969,6 +4077,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { referredResourceIri = generationeIri ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.superUser, apiRequestID = UUID.randomUUID ) @@ -4002,6 +4111,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueIri = stillImageFileValueIri.get, valueContent = valueContent ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -4051,6 +4161,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueIri = stillImageFileValueIri.get, valueContent = valueContent ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -4105,6 +4216,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueIri = stillImageFileValueIri.get, valueContent = valueContent ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, // this user doesn't have the necessary permission apiRequestID = UUID.randomUUID ) @@ -4140,6 +4252,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueIri = stillImageFileValueIri.get, valueContent = valueContent ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -4160,6 +4273,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueIri = intValueIri.get, valueTypeIri = OntologyConstants.KnoraApiV2Complex.IntValue.toSmartIri, deleteComment = Some("this value was incorrect"), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser2, apiRequestID = UUID.randomUUID ) @@ -4181,6 +4295,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueIri = intValueIri.get, valueTypeIri = OntologyConstants.KnoraApiV2Complex.IntValue.toSmartIri, deleteComment = Some("this value was incorrect"), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -4209,6 +4324,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueTypeIri = OntologyConstants.KnoraApiV2Complex.IntValue.toSmartIri, deleteComment = Some("this value was incorrect"), deleteDate = Some(deleteDate), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -4233,6 +4349,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { propertyIri = OntologyConstants.KnoraApiV2Complex.HasStandoffLinkToValue.toSmartIri, valueIri = standoffLinkValueIri.get, valueTypeIri = OntologyConstants.KnoraApiV2Complex.LinkValue.toSmartIri, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.superUser, apiRequestID = UUID.randomUUID ) @@ -4253,6 +4370,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { valueIri = zeitglöckleinCommentWithStandoffIri.get, valueTypeIri = OntologyConstants.KnoraApiV2Complex.TextValue.toSmartIri, deleteComment = Some("this value was incorrect"), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -4291,6 +4409,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { propertyIri = linkValuePropertyIri, valueIri = linkValueIri.get, valueTypeIri = OntologyConstants.KnoraApiV2Complex.LinkValue.toSmartIri, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaUser, apiRequestID = UUID.randomUUID ) @@ -4316,6 +4435,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { propertyIri = propertyIri, valueIri = "http://rdfh.ch/0803/c5058f3a/values/c3295339", valueTypeIri = OntologyConstants.KnoraApiV2Complex.TextValue.toSmartIri, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = incunabulaCreatorUser, apiRequestID = UUID.randomUUID ) @@ -4339,6 +4459,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser01, apiRequestID = UUID.randomUUID ) @@ -4359,6 +4480,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { ), permissions = Some("CR knora-admin:Creator") ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesReviewerUser, apiRequestID = UUID.randomUUID ) @@ -4383,6 +4505,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser01, apiRequestID = UUID.randomUUID ) @@ -4403,6 +4526,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { ), permissions = Some("CR knora-admin:Creator") ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.rootUser, apiRequestID = UUID.randomUUID ) @@ -4425,6 +4549,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { responderManager ! CreateResourceRequestV2( createResource = inputResource, + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser01, apiRequestID = UUID.randomUUID ) @@ -4445,6 +4570,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { ), permissions = Some("CR knora-admin:Creator") ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = SharedTestDataADM.imagesUser01, apiRequestID = UUID.randomUUID ) @@ -4472,6 +4598,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { mapping = standardMapping ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -4512,6 +4639,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { mapping = standardMapping ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) @@ -4559,6 +4687,7 @@ class ValuesResponderV2Spec extends CoreSpec() with ImplicitSender { mapping = standardMapping ) ), + featureFactoryConfig = defaultFeatureFactoryConfig, requestingUser = anythingUser1, apiRequestID = UUID.randomUUID ) diff --git a/webapi/src/test/scala/org/knora/webapi/routing/AuthenticatorSpec.scala b/webapi/src/test/scala/org/knora/webapi/routing/AuthenticatorSpec.scala index 7a2cb91f50..c009243282 100644 --- a/webapi/src/test/scala/org/knora/webapi/routing/AuthenticatorSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/routing/AuthenticatorSpec.scala @@ -21,59 +21,49 @@ package org.knora.webapi.routing import akka.testkit.ImplicitSender import akka.util.Timeout -import com.typesafe.config.ConfigFactory import org.knora.webapi._ import org.knora.webapi.exceptions.{BadCredentialsException, BadRequestException} +import org.knora.webapi.messages.StringFormatter import org.knora.webapi.messages.admin.responder.usersmessages.{UserADM, UserIdentifierADM} import org.knora.webapi.messages.v2.routing.authenticationmessages.{KnoraPasswordCredentialsV2, KnoraTokenCredentialsV2} import org.knora.webapi.routing.Authenticator.AUTHENTICATION_INVALIDATION_CACHE_NAME +import org.knora.webapi.sharedtestdata.SharedTestDataADM import org.knora.webapi.util.cache.CacheUtil import org.scalatest.PrivateMethodTester -import org.knora.webapi.messages.StringFormatter -import org.knora.webapi.sharedtestdata.SharedTestDataADM import scala.concurrent.Future object AuthenticatorSpec { - val config = ConfigFactory.parseString( - """ - app { - - } - """.stripMargin) - - - val rootUser = SharedTestDataADM.rootUser - val rootUserEmail = rootUser.email - val rootUserPassword = "test" + private val rootUser = SharedTestDataADM.rootUser + private val rootUserEmail = rootUser.email + private val rootUserPassword = "test" } - - class AuthenticatorSpec extends CoreSpec("AuthenticationTestSystem") with ImplicitSender with PrivateMethodTester { implicit val timeout: Timeout = settings.defaultTimeout implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance - val getUserByIdentifier = PrivateMethod[Future[UserADM]]('getUserByIdentifier) - val authenticateCredentialsV2 = PrivateMethod[Future[Boolean]]('authenticateCredentialsV2) + private val getUserByIdentifier = PrivateMethod[Future[UserADM]]('getUserByIdentifier) + private val authenticateCredentialsV2 = PrivateMethod[Future[Boolean]]('authenticateCredentialsV2) "During Authentication" when { "called, the 'getUserADMByEmail' method " should { "succeed with the correct 'email' " in { - val resF = Authenticator invokePrivate getUserByIdentifier(UserIdentifierADM(maybeEmail = Some(AuthenticatorSpec.rootUserEmail)), system, responderManager, timeout, executionContext) - resF map { res => assert(res == AuthenticatorSpec.rootUser)} + val resF = Authenticator invokePrivate getUserByIdentifier( + UserIdentifierADM(maybeEmail = Some(AuthenticatorSpec.rootUserEmail)), defaultFeatureFactoryConfig, system, responderManager, timeout, executionContext) + resF map { res => assert(res == AuthenticatorSpec.rootUser) } } "fail with the wrong 'email' " in { - val resF = Authenticator invokePrivate getUserByIdentifier(UserIdentifierADM(maybeEmail = Some("wronguser@example.com")), system, responderManager, timeout, executionContext) - resF map {res => assertThrows(BadCredentialsException)} + val resF = Authenticator invokePrivate getUserByIdentifier(UserIdentifierADM(maybeEmail = Some("wronguser@example.com")), defaultFeatureFactoryConfig, system, responderManager, timeout, executionContext) + resF map { res => assertThrows(BadCredentialsException) } } "fail when not providing anything " in { - an [BadRequestException] should be thrownBy { - Authenticator invokePrivate getUserByIdentifier(UserIdentifierADM(), system, responderManager, timeout, executionContext) + an[BadRequestException] should be thrownBy { + Authenticator invokePrivate getUserByIdentifier(UserIdentifierADM(), defaultFeatureFactoryConfig, system, responderManager, timeout, executionContext) } } } @@ -81,36 +71,36 @@ class AuthenticatorSpec extends CoreSpec("AuthenticationTestSystem") with Implic "called, the 'authenticateCredentialsV2' method" should { "succeed with correct email/password" in { val correctPasswordCreds = KnoraPasswordCredentialsV2(UserIdentifierADM(maybeEmail = Some(AuthenticatorSpec.rootUserEmail)), AuthenticatorSpec.rootUserPassword) - val resF = Authenticator invokePrivate authenticateCredentialsV2(Some(correctPasswordCreds), system, responderManager, executionContext) - resF map {res => assert(res)} + val resF = Authenticator invokePrivate authenticateCredentialsV2(Some(correctPasswordCreds), defaultFeatureFactoryConfig, system, responderManager, executionContext) + resF map { res => assert(res) } } "fail with unknown email" in { - val wrongPasswordCreds = KnoraPasswordCredentialsV2(UserIdentifierADM(maybeEmail = Some("wrongemail@example.com")), "wrongpassword") - val resF = Authenticator invokePrivate authenticateCredentialsV2(Some(wrongPasswordCreds), system, responderManager, executionContext) - resF map {res => assertThrows(BadCredentialsException)} + val wrongPasswordCreds = KnoraPasswordCredentialsV2(UserIdentifierADM(maybeEmail = Some("wrongemail@example.com")), "wrongpassword") + val resF = Authenticator invokePrivate authenticateCredentialsV2(Some(wrongPasswordCreds), defaultFeatureFactoryConfig, system, responderManager, executionContext) + resF map { res => assertThrows(BadCredentialsException) } } "fail with wrong password" in { - val wrongPasswordCreds = KnoraPasswordCredentialsV2(UserIdentifierADM(maybeEmail = Some(AuthenticatorSpec.rootUserEmail)), "wrongpassword") - val resF = Authenticator invokePrivate authenticateCredentialsV2(Some(wrongPasswordCreds), system, responderManager, executionContext) - resF map {res => assertThrows(BadCredentialsException)} + val wrongPasswordCreds = KnoraPasswordCredentialsV2(UserIdentifierADM(maybeEmail = Some(AuthenticatorSpec.rootUserEmail)), "wrongpassword") + val resF = Authenticator invokePrivate authenticateCredentialsV2(Some(wrongPasswordCreds), defaultFeatureFactoryConfig, system, responderManager, executionContext) + resF map { res => assertThrows(BadCredentialsException) } } "succeed with correct token" in { val token = JWTHelper.createToken("myuseriri", settings.jwtSecretKey, settings.jwtLongevity) val tokenCreds = KnoraTokenCredentialsV2(token) - val resF = Authenticator invokePrivate authenticateCredentialsV2(Some(tokenCreds), system, responderManager, executionContext) - resF map {res => assert(res)} + val resF = Authenticator invokePrivate authenticateCredentialsV2(Some(tokenCreds), defaultFeatureFactoryConfig, system, responderManager, executionContext) + resF map { res => assert(res) } } "fail with invalidated token" in { - val token = JWTHelper.createToken("myuseriri", settings.jwtSecretKey, settings.jwtLongevity) - val tokenCreds = KnoraTokenCredentialsV2(token) - CacheUtil.put(AUTHENTICATION_INVALIDATION_CACHE_NAME, tokenCreds.token, tokenCreds.token) - val resF = Authenticator invokePrivate authenticateCredentialsV2(Some(tokenCreds), system, responderManager, executionContext) - resF map {res => assertThrows(BadCredentialsException)} + val token = JWTHelper.createToken("myuseriri", settings.jwtSecretKey, settings.jwtLongevity) + val tokenCreds = KnoraTokenCredentialsV2(token) + CacheUtil.put(AUTHENTICATION_INVALIDATION_CACHE_NAME, tokenCreds.token, tokenCreds.token) + val resF = Authenticator invokePrivate authenticateCredentialsV2(Some(tokenCreds), defaultFeatureFactoryConfig, system, responderManager, executionContext) + resF map { res => assertThrows(BadCredentialsException) } } "fail with wrong token" in { - val tokenCreds = KnoraTokenCredentialsV2("123456") - val resF = Authenticator invokePrivate authenticateCredentialsV2(Some(tokenCreds), system, responderManager, executionContext) - resF map {res => assertThrows(BadCredentialsException)} + val tokenCreds = KnoraTokenCredentialsV2("123456") + val resF = Authenticator invokePrivate authenticateCredentialsV2(Some(tokenCreds), defaultFeatureFactoryConfig, system, responderManager, executionContext) + resF map { res => assertThrows(BadCredentialsException) } } }