From 4b666829ff81a447cd1c1fae304bb5ca518fbab9 Mon Sep 17 00:00:00 2001 From: Marcin Procyk Date: Fri, 18 Nov 2022 07:31:34 +0100 Subject: [PATCH] feat(projectsADM): add possibility to get project and members by UUID (DEV-1408) (#2272) --- docs/03-apis/api-admin/projects.md | 4 +- .../src/main/scala/dsp/valueobjects/Iri.scala | 20 ++ .../src/main/scala/dsp/valueobjects/V2.scala | 15 +- .../test/scala/dsp/valueobjects/IriSpec.scala | 32 ++- .../gravsearchtest1-admin.ttl | 4 +- .../gravsearchtest1-data.ttl | 14 +- .../gravsearchtest1-onto.ttl | 2 +- .../lumieres-lausanne-data-lists.ttl | 30 +-- .../lumieres-lausanne-onto.ttl | 2 +- .../lumieres-lausanne_admin.ttl | 34 ++-- .../lumieres-lausanne_permissions.ttl | 102 +++++----- .../ProjectsWithOptionalPersonOrBiblio.jsonld | 15 +- .../ProjectsMessagesADM.scala | 189 ++++++++---------- .../util/ConstructResponseUtilV2.scala | 7 +- .../messages/util/search/QueryTraverser.scala | 13 +- .../resourcemessages/ResourceMessagesV2.scala | 6 +- .../responders/admin/GroupsResponderADM.scala | 19 +- .../responders/admin/ListsResponderADM.scala | 38 ++-- .../admin/PermissionsResponderADM.scala | 10 +- .../admin/ProjectsResponderADM.scala | 126 ++++++------ .../responders/admin/SipiResponderADM.scala | 7 +- .../responders/admin/UsersResponderADM.scala | 45 +++-- .../responders/v1/ResourcesResponderV1.scala | 40 ++-- .../responders/v1/ValuesResponderV1.scala | 6 +- .../responders/v2/OntologyResponderV2.scala | 6 +- .../responders/v2/ResourcesResponderV2.scala | 23 ++- .../responders/v2/StandoffResponderV2.scala | 6 +- .../routing/admin/ProjectsRouteADM.scala | 188 +++++++++++------ .../webapi/routing/v1/ResourcesRouteV1.scala | 58 +++--- .../cache/impl/CacheServiceInMemImpl.scala | 48 +++-- .../cache/impl/CacheServiceRedisImpl.scala | 83 ++++++-- .../upgrade/plugins/UpgradePluginPR2255.scala | 20 +- .../webapi/e2e/admin/ProjectsADME2ESpec.scala | 4 +- .../ProjectsMessagesADMSpec.scala | 29 ++- .../other/v2/LumieresLausanneV2E2ESpec.scala | 2 +- .../admin/ProjectsResponderADMSpec.scala | 113 ++++++++--- .../admin/UsersResponderADMSpec.scala | 28 ++- .../sharedtestdata/SharedTestDataADM.scala | 3 +- .../sharedtestdata/SharedTestDataV1.scala | 4 +- .../store/cache/CacheServiceManagerSpec.scala | 23 ++- .../cache/impl/CacheInMemImplZSpec.scala | 115 ++++++----- .../cache/impl/CacheRedisImplZSpec.scala | 87 +++++--- 42 files changed, 993 insertions(+), 627 deletions(-) diff --git a/docs/03-apis/api-admin/projects.md b/docs/03-apis/api-admin/projects.md index 2fedac6f97..938774cbfa 100644 --- a/docs/03-apis/api-admin/projects.md +++ b/docs/03-apis/api-admin/projects.md @@ -13,7 +13,7 @@ - `POST: /admin/projects` : create a new project -- `GET: /admin/projects/[iri | shortname | shortcode]/` : returns a single project identified either through iri, shortname, or shortcode +- `GET: /admin/projects/[iri | shortname | shortcode | uuid]/` : returns a single project identified either through iri, shortname, shortcode or UUID - `PUT: /admin/projects/iri/` : update a project identified by iri @@ -23,7 +23,7 @@ **Project Member Operations:** -- `GET: /admin/projects/[iri | shortname | shortcode]//members` : returns all members part of a project identified through iri, shortname or shortcode +- `GET: /admin/projects/[iri | shortname | shortcode | uuid]//members` : returns all members part of a project identified through iri, shortname, shortcode or UUID **Project Admin Member Operations:** diff --git a/dsp-shared/src/main/scala/dsp/valueobjects/Iri.scala b/dsp-shared/src/main/scala/dsp/valueobjects/Iri.scala index feff9c2307..348170f227 100644 --- a/dsp-shared/src/main/scala/dsp/valueobjects/Iri.scala +++ b/dsp-shared/src/main/scala/dsp/valueobjects/Iri.scala @@ -132,6 +132,24 @@ object Iri { } } + /** + * Base64Uuid value object. + * This is base64 encoded UUID version without paddings. + * + * @param value to validate. + */ + sealed abstract case class Base64Uuid private (value: String) + object Base64Uuid { + def make(value: String): Validation[ValidationException, Base64Uuid] = + if (value.isEmpty) { + Validation.fail(ValidationException(IriErrorMessages.UuidMissing)) + } else if (!V2UuidValidation.hasUuidLength(value)) { + Validation.fail(ValidationException(IriErrorMessages.UuidInvalid(value))) + } else if (!V2UuidValidation.isUuidVersion4Or5(value)) { + Validation.fail(ValidationException(IriErrorMessages.UuidVersionInvalid)) + } else Validation.succeed(new Base64Uuid(value) {}) + } + /** * RoleIri value object. */ @@ -221,6 +239,8 @@ object IriErrorMessages { val RoleIriInvalid = (iri: String) => s"Role IRI: $iri is invalid." val UserIriMissing = "User IRI cannot be empty." val UserIriInvalid = (iri: String) => s"User IRI: $iri is invalid." + val UuidMissing = "UUID cannot be empty" + val UuidInvalid = (uuid: String) => s"'$uuid' is not a UUID" val UuidVersionInvalid = "Invalid UUID used to create IRI. Only versions 4 and 5 are supported." val PropertyIriMissing = "Property IRI cannot be empty." } diff --git a/dsp-shared/src/main/scala/dsp/valueobjects/V2.scala b/dsp-shared/src/main/scala/dsp/valueobjects/V2.scala index 328c77d8a2..59574a87d5 100644 --- a/dsp-shared/src/main/scala/dsp/valueobjects/V2.scala +++ b/dsp-shared/src/main/scala/dsp/valueobjects/V2.scala @@ -225,15 +225,22 @@ object V2UuidValidation { getUUIDVersion(s) == 4 || getUUIDVersion(s) == 5 /** - * Gets the last segment of IRI, decodes UUID and gets the version. - * @param s the string (IRI) to be checked. + * Decodes Base64 encoded UUID and gets its version. + * @param uuid the Base64 encoded UUID as [[String]] to be checked. * @return UUID version. */ - def getUUIDVersion(s: String): Int = { - val encodedUUID = s.split("/").last + def getUUIDVersion(uuid: String): Int = { + val encodedUUID = getUuidFromIri(uuid) decodeUuid(encodedUUID).version() } + /** + * Gets the last IRI segment - Base64 encoded UUID. + * @param iri the IRI [[String]] to get the UUID from. + * @return Base64 encoded UUID as [[String]] + */ + def getUuidFromIri(iri: String): String = iri.split("/").last + /** * Calls `decodeUuidWithErr`, throwing [[InconsistentRepositoryDataException]] if the string cannot be parsed. */ diff --git a/dsp-shared/src/test/scala/dsp/valueobjects/IriSpec.scala b/dsp-shared/src/test/scala/dsp/valueobjects/IriSpec.scala index 8619555931..4fc99826bf 100644 --- a/dsp-shared/src/test/scala/dsp/valueobjects/IriSpec.scala +++ b/dsp-shared/src/test/scala/dsp/valueobjects/IriSpec.scala @@ -12,6 +12,7 @@ import zio.test._ import dsp.errors.BadRequestException import dsp.errors.ValidationException import dsp.valueobjects.Iri._ +import dsp.valueobjects.V2UuidValidation._ /** * This spec is used to test the [[Iri]] value objects creation. @@ -35,7 +36,11 @@ object IriSpec extends ZIOSpecDefault { val validUserIri = "http://rdfh.ch/users/jDEEitJESRi3pDaDjjQ1WQ" val userIriWithUUIDVersion3 = "http://rdfh.ch/users/cCmdcpn2MO211YYOplR1hQ" - def spec = (groupIriTest + listIriTest + projectIriTest + RoleIriTest + UserIriTest) + val invalidUuid = "MAgdcpn2MO211YYOplR32v" + val uuidVersion3 = getUuidFromIri(userIriWithUUIDVersion3) + val supportedUuid = getUuidFromIri(validUserIri) + + def spec = (groupIriTest + listIriTest + projectIriTest + uuidTest + roleIriTest + userIriTest) private val groupIriTest = suite("IriSpec - GroupIri")( test("pass an empty value and return an error") { @@ -190,7 +195,28 @@ object IriSpec extends ZIOSpecDefault { } ) - private val RoleIriTest = suite("IriSpec - roleIri")( + private val uuidTest = suite("IriSpec - Base64Uuid")( + test("pass an empty value and return an error") { + assertTrue(Base64Uuid.make("") == Validation.fail(ValidationException(IriErrorMessages.UuidMissing))) + }, + test("pass an invalid UUID and return an error") { + assertTrue( + Base64Uuid.make(invalidIri) == Validation.fail(ValidationException(IriErrorMessages.UuidInvalid(invalidIri))) + ) + }, + test("pass an valid UUID, which has not supported version 3") { + assertTrue( + Base64Uuid.make(uuidVersion3) == Validation.fail(ValidationException(IriErrorMessages.UuidVersionInvalid)) + ) + }, + test("pass valid UUID and successfully create value object") { + (for { + uuid <- Base64Uuid.make(supportedUuid) + } yield assertTrue(uuid.value == supportedUuid)).toZIO + } + ) + + private val roleIriTest = suite("IriSpec - roleIri")( test("pass an empty value and return an error") { assertTrue(RoleIri.make("") == Validation.fail(BadRequestException(IriErrorMessages.RoleIriMissing))) }, @@ -213,7 +239,7 @@ object IriSpec extends ZIOSpecDefault { } ) - private val UserIriTest = suite("IriSpec - UserIri")( + private val userIriTest = suite("IriSpec - UserIri")( test("pass an empty value and return an error") { assertTrue(UserIri.make("") == Validation.fail(BadRequestException(IriErrorMessages.UserIriMissing))) }, diff --git a/test_data/e2e.v2.SearchRouteV2R2RSpec/gravsearchtest1-admin.ttl b/test_data/e2e.v2.SearchRouteV2R2RSpec/gravsearchtest1-admin.ttl index e776c099ad..4a5aec409e 100644 --- a/test_data/e2e.v2.SearchRouteV2R2RSpec/gravsearchtest1-admin.ttl +++ b/test_data/e2e.v2.SearchRouteV2R2RSpec/gravsearchtest1-admin.ttl @@ -6,7 +6,7 @@ @prefix knora-admin: . @prefix salsah-gui: . - a knora-admin:knoraProject ; + a knora-admin:knoraProject ; knora-admin:projectShortname "test"^^xsd:string ; knora-admin:projectLongname "Test"^^xsd:string ; knora-admin:projectShortcode "0666"^^xsd:string ; @@ -25,5 +25,5 @@ knora-admin:familyName "test"^^xsd:string ; knora-admin:status "true"^^xsd:boolean ; knora-admin:preferredLanguage "en"^^xsd:string ; - knora-admin:isInProject ; + knora-admin:isInProject ; knora-admin:isInSystemAdminGroup "true"^^xsd:boolean . diff --git a/test_data/e2e.v2.SearchRouteV2R2RSpec/gravsearchtest1-data.ttl b/test_data/e2e.v2.SearchRouteV2R2RSpec/gravsearchtest1-data.ttl index b794518c84..d63502ac18 100644 --- a/test_data/e2e.v2.SearchRouteV2R2RSpec/gravsearchtest1-data.ttl +++ b/test_data/e2e.v2.SearchRouteV2R2RSpec/gravsearchtest1-data.ttl @@ -109,19 +109,19 @@ rdf:object . - :attachedToProject . + :attachedToProject . - :attachedToProject . + :attachedToProject . - :attachedToProject . + :attachedToProject . - :attachedToProject . + :attachedToProject . - :attachedToProject . + :attachedToProject . - :attachedToProject . + :attachedToProject . - :attachedToProject . + :attachedToProject . :creationDate "2018-06-06T12:08:56.619Z"^^xsd:dateTime . diff --git a/test_data/e2e.v2.SearchRouteV2R2RSpec/gravsearchtest1-onto.ttl b/test_data/e2e.v2.SearchRouteV2R2RSpec/gravsearchtest1-onto.ttl index 98ca711a97..d00c3d2017 100644 --- a/test_data/e2e.v2.SearchRouteV2R2RSpec/gravsearchtest1-onto.ttl +++ b/test_data/e2e.v2.SearchRouteV2R2RSpec/gravsearchtest1-onto.ttl @@ -9,7 +9,7 @@ a owl:Ontology ; rdfs:label "Test ontology" ; - knora-base:attachedToProject ; + knora-base:attachedToProject ; knora-base:lastModificationDate "2012-12-12T12:12:12.12Z"^^xsd:dateTime . gravsearchtest1:isInProjectValue rdf:type owl:ObjectProperty ; diff --git a/test_data/other.v2.LumieresLausanneV2E2ESpec/lumieres-lausanne-data-lists.ttl b/test_data/other.v2.LumieresLausanneV2E2ESpec/lumieres-lausanne-data-lists.ttl index 19e726d3fc..733d3ffff9 100644 --- a/test_data/other.v2.LumieresLausanneV2E2ESpec/lumieres-lausanne-data-lists.ttl +++ b/test_data/other.v2.LumieresLausanneV2E2ESpec/lumieres-lausanne-data-lists.ttl @@ -22,7 +22,7 @@ knora-base:isRootNode "true"^^xsd:boolean ; rdfs:comment """Type d'études"""@fr ; rdfs:label """Type d'études"""@fr ; - knora-base:attachedToProject ; + knora-base:attachedToProject ; knora-base:hasSubListNode , . # , @@ -87,7 +87,7 @@ # knora-base:isRootNode "true"^^xsd:boolean ; # rdfs:comment """Sélection oui/non"""@fr ; # rdfs:label """Oui/Non"""@fr ; -# knora-base:attachedToProject ; +# knora-base:attachedToProject ; # knora-base:hasSubListNode , # . # @@ -119,7 +119,7 @@ knora-base:isRootNode "true"^^xsd:boolean ; rdfs:comment """Liste de choix des différentes contribution à une fiche Bibliographie."""@de ; rdfs:label """Liste de contributions"""@fr ; - knora-base:attachedToProject ; + knora-base:attachedToProject ; knora-base:hasSubListNode , , , @@ -195,7 +195,7 @@ knora-base:isRootNode "true"^^xsd:boolean ; rdfs:comment """Choix du type de littérature."""@fr ; rdfs:label """Type de littérature"""@fr ; - knora-base:attachedToProject ; + knora-base:attachedToProject ; knora-base:hasSubListNode , . @@ -227,7 +227,7 @@ knora-base:isRootNode "true"^^xsd:boolean ; rdfs:comment """Liste des types de documents"""@fr ; rdfs:label """Type de document"""@fr ; - knora-base:attachedToProject ; + knora-base:attachedToProject ; knora-base:hasSubListNode , , , @@ -292,7 +292,7 @@ knora-base:isRootNode "true"^^xsd:boolean ; rdfs:comment """Liste de langues"""@fr ; rdfs:label """Langues"""@fr ; - knora-base:attachedToProject ; + knora-base:attachedToProject ; knora-base:hasSubListNode , , , @@ -368,7 +368,7 @@ knora-base:isRootNode "true"^^xsd:boolean ; rdfs:comment """Liste des institutions conservant le manuscrit. """@fr ; rdfs:label """Lieu de dépôt (manuscrit)"""@fr ; - knora-base:attachedToProject ; + knora-base:attachedToProject ; knora-base:hasSubListNode , , , @@ -609,7 +609,7 @@ knora-base:isRootNode "true"^^xsd:boolean ; rdfs:comment """Liste de choix parmi différents types d'écrits."""@fr ; rdfs:label """Type d'écrit"""@fr ; - knora-base:attachedToProject ; + knora-base:attachedToProject ; knora-base:hasSubListNode , , , @@ -740,7 +740,7 @@ knora-base:isRootNode "true"^^xsd:boolean ; rdfs:comment """Liste des sociétés et académies."""@fr ; rdfs:label """Sociétés/académies"""@fr ; - knora-base:attachedToProject ; + knora-base:attachedToProject ; knora-base:hasSubListNode , , , @@ -1399,7 +1399,7 @@ knora-base:isRootNode "true"^^xsd:boolean ; rdfs:comment """Liste des types de relation"""@fr ; rdfs:label """Liste des types de relation"""@fr ; - knora-base:attachedToProject ; + knora-base:attachedToProject ; knora-base:hasSubListNode , , , @@ -1585,7 +1585,7 @@ knora-base:isRootNode "true"^^xsd:boolean ; rdfs:comment """Liste des religions"""@fr ; rdfs:label """Religion"""@fr ; - knora-base:attachedToProject ; + knora-base:attachedToProject ; knora-base:hasSubListNode , , , @@ -1639,7 +1639,7 @@ knora-base:isRootNode "true"^^xsd:boolean ; rdfs:comment """Liste de nationalités (nationalités & régions d'origine)"""@fr ; rdfs:label """Nationalités"""@fr ; - knora-base:attachedToProject ; + knora-base:attachedToProject ; knora-base:hasSubListNode , , , @@ -1825,7 +1825,7 @@ knora-base:isRootNode "true"^^xsd:boolean ; rdfs:comment """Etat de la transcription"""@fr ; rdfs:label """Etat"""@fr ; - knora-base:attachedToProject ; + knora-base:attachedToProject ; knora-base:hasSubListNode , . @@ -1857,7 +1857,7 @@ knora-base:isRootNode "true"^^xsd:boolean ; rdfs:comment """Etendue de la transcription"""@fr ; rdfs:label """Emprise de la transcription"""@fr ; - knora-base:attachedToProject ; + knora-base:attachedToProject ; knora-base:hasSubListNode , . @@ -1896,7 +1896,7 @@ rdf:type knora-base:ListNode ; knora-base:isRootNode "true"^^xsd:boolean ; rdfs:label """mots de clé"""@fr ; - knora-base:attachedToProject ; + knora-base:attachedToProject ; knora-base:hasSubListNode , , , diff --git a/test_data/other.v2.LumieresLausanneV2E2ESpec/lumieres-lausanne-onto.ttl b/test_data/other.v2.LumieresLausanneV2E2ESpec/lumieres-lausanne-onto.ttl index 1c7d3009eb..6f3e5a96b3 100644 --- a/test_data/other.v2.LumieresLausanneV2E2ESpec/lumieres-lausanne-onto.ttl +++ b/test_data/other.v2.LumieresLausanneV2E2ESpec/lumieres-lausanne-onto.ttl @@ -10,7 +10,7 @@ a owl:Ontology ; rdfs:label "The Lumières.Lausanne ontology" ; - knora-base:attachedToProject ; + knora-base:attachedToProject ; knora-base:lastModificationDate "2012-12-12T12:12:12.12Z"^^xsd:dateTime . ########################################################## diff --git a/test_data/other.v2.LumieresLausanneV2E2ESpec/lumieres-lausanne_admin.ttl b/test_data/other.v2.LumieresLausanneV2E2ESpec/lumieres-lausanne_admin.ttl index 42086c3d4d..bf94cb3504 100644 --- a/test_data/other.v2.LumieresLausanneV2E2ESpec/lumieres-lausanne_admin.ttl +++ b/test_data/other.v2.LumieresLausanneV2E2ESpec/lumieres-lausanne_admin.ttl @@ -10,7 +10,7 @@ # --- Project --- - a knora-admin:knoraProject ; + a knora-admin:knoraProject ; knora-admin:projectLongname "Lumières.Lausanne"^^xsd:string ; knora-admin:projectShortname "lumieres-lausanne"^^xsd:string ; knora-admin:projectShortcode "0113"^^xsd:string ; @@ -26,42 +26,42 @@ rdf:type knora-admin:UserGroup ; knora-admin:groupName "Utilisateur"^^xsd:string ; knora-admin:groupDescriptions """Statut permanent. Attribué à toute personne désireuse de s'enregistrer. N'est membre d'aucun autre groupe (étudiant, chercheur). Par rapport au visiteur anonyme sans login, accès supplémentaire à la gestion des collections, aux transcriptions/documents joints/projets slmt si autorisation."""@fr ; - knora-admin:belongsToProject ; + knora-admin:belongsToProject ; knora-admin:status "true"^^xsd:boolean ; knora-admin:hasSelfJoinEnabled "false"^^xsd:boolean . rdf:type knora-admin:UserGroup ; knora-admin:groupName "Etudiant"^^xsd:string ; knora-admin:groupDescriptions """Statut temporaire. Uniquement les étudiants UNIL liés à un séminaire donné dans le cadre du projet Lumières.Lausanne. Ont reçu les consignes ainsi qu'une initiation (obligatoire). A la fin du séminaire, leur statut est changé en statut "Utilisateur", sauf demande particulière."""@fr ; - knora-admin:belongsToProject ; + knora-admin:belongsToProject ; knora-admin:status "true"^^xsd:boolean ; knora-admin:hasSelfJoinEnabled "false"^^xsd:boolean . rdf:type knora-admin:UserGroup ; knora-admin:groupName "Chercheur"^^xsd:string ; knora-admin:groupDescriptions "Statut permanent. Doctorants, professeurs, autres chercheurs qui ont reçu préalablement l'autorisation d'un directeur. Ont reçu les consignes (obligatoire), et si possible une initiation."@fr ; - knora-admin:belongsToProject ; + knora-admin:belongsToProject ; knora-admin:status "true"^^xsd:boolean ; knora-admin:hasSelfJoinEnabled "false"^^xsd:boolean . rdf:type knora-admin:UserGroup ; knora-admin:groupName "Doctorant"^^xsd:string ; knora-admin:groupDescriptions "Statut temporaire. Doctorants et étudiants-assistants directement liés au Projet Lumières.Lausanne. Ont reçu les consignes ainsi qu'une initiation (obligatoire). Une fois leur mandat terminé, passent en statut Chercheur."@fr ; - knora-admin:belongsToProject ; + knora-admin:belongsToProject ; knora-admin:status "true"^^xsd:boolean ; knora-admin:hasSelfJoinEnabled "false"^^xsd:boolean . rdf:type knora-admin:UserGroup ; knora-admin:groupName "Directeur"^^xsd:string ; knora-admin:groupDescriptions "Béla Kapossy, Béatrice Lovis."@fr ; - knora-admin:belongsToProject ; + knora-admin:belongsToProject ; knora-admin:status "true"^^xsd:boolean ; knora-admin:hasSelfJoinEnabled "false"^^xsd:boolean . rdf:type knora-admin:UserGroup ; knora-admin:groupName "Administrateur"^^xsd:string ; knora-admin:groupDescriptions "Béatrice Lovis."@fr ; - knora-admin:belongsToProject ; + knora-admin:belongsToProject ; knora-admin:status "true"^^xsd:boolean ; knora-admin:hasSelfJoinEnabled "false"^^xsd:boolean . @@ -78,7 +78,7 @@ # knora-admin:email "lumieres@unil.ch"^^xsd:string ; # knora-admin:preferredLanguage "fr"^^xsd:string ; # knora-admin:status "true"^^xsd:boolean ; -# knora-admin:isInProject ; +# knora-admin:isInProject ; # knora-admin:isInSystemAdminGroup "false"^^xsd:boolean . a knora-admin:User ; @@ -89,7 +89,7 @@ knora-admin:email "user_test@unil.ch"^^xsd:string ; knora-admin:preferredLanguage "fr"^^xsd:string ; knora-admin:status "true"^^xsd:boolean ; - knora-admin:isInProject ; + knora-admin:isInProject ; knora-admin:isInGroup ; knora-admin:isInSystemAdminGroup "false"^^xsd:boolean . @@ -101,7 +101,7 @@ knora-admin:email "etu_test@unil.ch"^^xsd:string ; knora-admin:preferredLanguage "fr"^^xsd:string ; knora-admin:status "true"^^xsd:boolean ; - knora-admin:isInProject ; + knora-admin:isInProject ; knora-admin:isInGroup ; knora-admin:isInSystemAdminGroup "false"^^xsd:boolean . @@ -113,7 +113,7 @@ knora-admin:email "etu_test2@unil.ch"^^xsd:string ; knora-admin:preferredLanguage "fr"^^xsd:string ; knora-admin:status "true"^^xsd:boolean ; - knora-admin:isInProject ; + knora-admin:isInProject ; knora-admin:isInGroup ; knora-admin:isInSystemAdminGroup "false"^^xsd:boolean . @@ -125,7 +125,7 @@ knora-admin:email "cherch_test@unil.ch"^^xsd:string ; knora-admin:preferredLanguage "fr"^^xsd:string ; knora-admin:status "true"^^xsd:boolean ; - knora-admin:isInProject ; + knora-admin:isInProject ; knora-admin:isInGroup ; knora-admin:isInSystemAdminGroup "false"^^xsd:boolean . @@ -137,7 +137,7 @@ knora-admin:email "doct_test@unil.ch"^^xsd:string ; knora-admin:preferredLanguage "fr"^^xsd:string ; knora-admin:status "true"^^xsd:boolean ; - knora-admin:isInProject ; + knora-admin:isInProject ; knora-admin:isInGroup ; knora-admin:isInSystemAdminGroup "false"^^xsd:boolean . @@ -149,7 +149,7 @@ knora-admin:email "dir_test@unil.ch"^^xsd:string ; knora-admin:preferredLanguage "fr"^^xsd:string ; knora-admin:status "true"^^xsd:boolean ; - knora-admin:isInProject ; + knora-admin:isInProject ; knora-admin:isInGroup ; knora-admin:isInSystemAdminGroup "false"^^xsd:boolean . @@ -161,7 +161,7 @@ knora-admin:email "admin_test@unil.ch"^^xsd:string ; knora-admin:preferredLanguage "fr"^^xsd:string ; knora-admin:status "true"^^xsd:boolean ; - knora-admin:isInProject ; + knora-admin:isInProject ; knora-admin:isInGroup ; knora-admin:isInSystemAdminGroup "true"^^xsd:boolean . @@ -174,7 +174,7 @@ knora-admin:email "Beatrice.Lovis@unil.ch"^^xsd:string ; knora-admin:preferredLanguage "fr"^^xsd:string ; knora-admin:status "true"^^xsd:boolean ; - knora-admin:isInProject ; + knora-admin:isInProject ; knora-admin:isInGroup ; knora-admin:isInSystemAdminGroup "false"^^xsd:boolean . @@ -186,6 +186,6 @@ knora-admin:email "gilles.faucherand@unil.ch"^^xsd:string ; knora-admin:preferredLanguage "fr"^^xsd:string ; knora-admin:status "true"^^xsd:boolean ; - knora-admin:isInProject ; + knora-admin:isInProject ; knora-admin:isInGroup ; knora-admin:isInSystemAdminGroup "false"^^xsd:boolean . diff --git a/test_data/other.v2.LumieresLausanneV2E2ESpec/lumieres-lausanne_permissions.ttl b/test_data/other.v2.LumieresLausanneV2E2ESpec/lumieres-lausanne_permissions.ttl index 37937d52d9..a4f6bd7fa8 100644 --- a/test_data/other.v2.LumieresLausanneV2E2ESpec/lumieres-lausanne_permissions.ttl +++ b/test_data/other.v2.LumieresLausanneV2E2ESpec/lumieres-lausanne_permissions.ttl @@ -19,38 +19,38 @@ # Administrative Permissions on User group rdf:type knora-admin:AdministrativePermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forGroup ; knora-base:hasPermissions "ProjectResourceCreateRestrictedPermission http://www.knora.org/ontology/0113/lumieres-lausanne#Collection,http://www.knora.org/ontology/0113/lumieres-lausanne#CollectionRestricted"^^xsd:string . # Administrative Permissions on Student group rdf:type knora-admin:AdministrativePermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forGroup ; knora-base:hasPermissions "ProjectResourceCreateRestrictedPermission http://www.knora.org/ontology/0113/lumieres-lausanne#BibliographicNotice,http://www.knora.org/ontology/0113/lumieres-lausanne#Collection,http://www.knora.org/ontology/0113/lumieres-lausanne#CollectionRestricted,http://www.knora.org/ontology/0113/lumieres-lausanne#Contribution,http://www.knora.org/ontology/0113/lumieres-lausanne#DraftBibliographicNotice,http://www.knora.org/ontology/0113/lumieres-lausanne#Note,http://www.knora.org/ontology/0113/lumieres-lausanne#NoteRestricted,http://www.knora.org/ontology/0113/lumieres-lausanne#Position,http://www.knora.org/ontology/0113/lumieres-lausanne#Relationship,http://www.knora.org/ontology/0113/lumieres-lausanne#SocietyMembership,http://www.knora.org/ontology/0113/lumieres-lausanne#Transcription"^^xsd:string . # Administrative Permissions on Researcher group rdf:type knora-admin:AdministrativePermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forGroup ; knora-base:hasPermissions "ProjectResourceCreateRestrictedPermission http://www.knora.org/ontology/0113/lumieres-lausanne#BibliographicNotice,http://www.knora.org/ontology/0113/lumieres-lausanne#Collection,http://www.knora.org/ontology/0113/lumieres-lausanne#CollectionRestricted,http://www.knora.org/ontology/0113/lumieres-lausanne#Contribution,http://www.knora.org/ontology/0113/lumieres-lausanne#DraftBibliographicNotice,http://www.knora.org/ontology/0113/lumieres-lausanne#Note,http://www.knora.org/ontology/0113/lumieres-lausanne#NoteRestricted,http://www.knora.org/ontology/0113/lumieres-lausanne#Position,http://www.knora.org/ontology/0113/lumieres-lausanne#Relationship,http://www.knora.org/ontology/0113/lumieres-lausanne#SocietyMembership,http://www.knora.org/ontology/0113/lumieres-lausanne#Transcription,http://www.knora.org/ontology/0113/lumieres-lausanne#TranscriptionRestricted"^^xsd:string . # Administrative Permissions on PhdStudent group rdf:type knora-admin:AdministrativePermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forGroup ; knora-base:hasPermissions "ProjectResourceCreateRestrictedPermission http://www.knora.org/ontology/0113/lumieres-lausanne#AdditionalResource,http://www.knora.org/ontology/0113/lumieres-lausanne#AdditionalResourceRestricted,http://www.knora.org/ontology/0113/lumieres-lausanne#BibliographicNotice,http://www.knora.org/ontology/0113/lumieres-lausanne#Collection,http://www.knora.org/ontology/0113/lumieres-lausanne#CollectionRestricted,http://www.knora.org/ontology/0113/lumieres-lausanne#Contribution,http://www.knora.org/ontology/0113/lumieres-lausanne#DraftBibliographicNotice,http://www.knora.org/ontology/0113/lumieres-lausanne#Document,http://www.knora.org/ontology/0113/lumieres-lausanne#Image,http://www.knora.org/ontology/0113/lumieres-lausanne#Note,http://www.knora.org/ontology/0113/lumieres-lausanne#NoteRestricted,http://www.knora.org/ontology/0113/lumieres-lausanne#Position,http://www.knora.org/ontology/0113/lumieres-lausanne#Relationship,http://www.knora.org/ontology/0113/lumieres-lausanne#SocietyMembership,http://www.knora.org/ontology/0113/lumieres-lausanne#Transcription,http://www.knora.org/ontology/0113/lumieres-lausanne#TranscriptionRestricted"^^xsd:string . # Administrative Permissions on Director group rdf:type knora-admin:AdministrativePermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forGroup ; knora-base:hasPermissions "ProjectResourceCreateRestrictedPermission http://www.knora.org/ontology/0113/lumieres-lausanne#AdditionalResource,http://www.knora.org/ontology/0113/lumieres-lausanne#AdditionalResourceRestricted,http://www.knora.org/ontology/0113/lumieres-lausanne#BibliographicNotice,http://www.knora.org/ontology/0113/lumieres-lausanne#Collection,http://www.knora.org/ontology/0113/lumieres-lausanne#CollectionRestricted,http://www.knora.org/ontology/0113/lumieres-lausanne#Contribution,http://www.knora.org/ontology/0113/lumieres-lausanne#DraftBibliographicNotice,http://www.knora.org/ontology/0113/lumieres-lausanne#DraftPerson,http://www.knora.org/ontology/0113/lumieres-lausanne#Document,http://www.knora.org/ontology/0113/lumieres-lausanne#Image,http://www.knora.org/ontology/0113/lumieres-lausanne#Note,http://www.knora.org/ontology/0113/lumieres-lausanne#NoteRestricted,http://www.knora.org/ontology/0113/lumieres-lausanne#Person,http://www.knora.org/ontology/0113/lumieres-lausanne#Position,http://www.knora.org/ontology/0113/lumieres-lausanne#Project,http://www.knora.org/ontology/0113/lumieres-lausanne#Relationship,http://www.knora.org/ontology/0113/lumieres-lausanne#SocietyMembership,http://www.knora.org/ontology/0113/lumieres-lausanne#Transcription,http://www.knora.org/ontology/0113/lumieres-lausanne#TranscriptionRestricted"^^xsd:string . # Administrative Permissions on Administrator group rdf:type knora-admin:AdministrativePermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forGroup ; knora-base:hasPermissions "ProjectResourceCreateRestrictedPermission http://www.knora.org/ontology/0113/lumieres-lausanne#AdditionalResource,http://www.knora.org/ontology/0113/lumieres-lausanne#AdditionalResourceRestricted,http://www.knora.org/ontology/0113/lumieres-lausanne#BibliographicNotice,http://www.knora.org/ontology/0113/lumieres-lausanne#Collection,http://www.knora.org/ontology/0113/lumieres-lausanne#CollectionRestricted,http://www.knora.org/ontology/0113/lumieres-lausanne#Contribution,http://www.knora.org/ontology/0113/lumieres-lausanne#Dissemination,http://www.knora.org/ontology/0113/lumieres-lausanne#DraftBibliographicNotice,http://www.knora.org/ontology/0113/lumieres-lausanne#DraftPerson,http://www.knora.org/ontology/0113/lumieres-lausanne#Document,http://www.knora.org/ontology/0113/lumieres-lausanne#Finding,http://www.knora.org/ontology/0113/lumieres-lausanne#FreeContent,http://www.knora.org/ontology/0113/lumieres-lausanne#Image,http://www.knora.org/ontology/0113/lumieres-lausanne#News,http://www.knora.org/ontology/0113/lumieres-lausanne#Note,http://www.knora.org/ontology/0113/lumieres-lausanne#NoteRestricted,http://www.knora.org/ontology/0113/lumieres-lausanne#Person,http://www.knora.org/ontology/0113/lumieres-lausanne#Position,http://www.knora.org/ontology/0113/lumieres-lausanne#Project,http://www.knora.org/ontology/0113/lumieres-lausanne#Relationship,http://www.knora.org/ontology/0113/lumieres-lausanne#SocietyMembership,http://www.knora.org/ontology/0113/lumieres-lausanne#Transcription,http://www.knora.org/ontology/0113/lumieres-lausanne#TranscriptionRestricted,http://www.knora.org/ontology/0113/lumieres-lausanne#User"^^xsd:string . @@ -64,37 +64,37 @@ # Default Object Access Permissions on User group rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forGroup ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student|V http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . # Default Object Access Permissions on Student group rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forGroup ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student|V http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . # Default Object Access Permissions on Researcher group rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forGroup ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student|V http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . # Default Object Access Permissions on PhdStudent group rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forGroup ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student|V http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . # Default Object Access Permissions on Director group rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forGroup ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student|V http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . # Default Object Access Permissions on Administrator group rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forGroup ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student|V http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . @@ -108,13 +108,13 @@ ### Default Object Access Permissions on resource class BibliographicNotice rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:BibliographicNotice ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher|V http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . ### Default Object Access Permissions on resource class Contribution rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:Contribution ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher|V http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . @@ -122,122 +122,122 @@ ### Default Object Access Permissions on resource class Person # Inutile compte-tenu des DOAP sur les groupes. # rdf:type knora-admin:DefaultObjectAccessPermission ; -# knora-admin:forProject ; +# knora-admin:forProject ; # knora-admin:forResourceClass lumieres-lausanne:Person ; # knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student|V http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . #### Default Object Access Permissions on resource class Note # Inutile compte-tenu des DOAP sur les groupes. # rdf:type knora-admin:DefaultObjectAccessPermission ; -# knora-admin:forProject ; +# knora-admin:forProject ; # knora-admin:forResourceClass lumieres-lausanne:Note ; # knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher|V http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . ### Default Object Access Permissions on resource class Transcription rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:Transcription ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent|V http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . ### Default Object Access Permissions on resource class TranscriptionRestricted rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:TranscriptionRestricted ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent"^^xsd:string . ### Default Object Access Permissions on resource class NoteRestricted rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:NoteRestricted ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent"^^xsd:string . ### Default Object Access Permissions on resource class CollectionRestricted rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:CollectionRestricted ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator|D knora-base:Creator"^^xsd:string . ### Default Object Access Permissions on resource class AdditionalResourceRestricted rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:AdditionalResourceRestricted ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent"^^xsd:string . ### Default Object Access Permissions on resource class ImageRestricted rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:ImageRestricted ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent"^^xsd:string . ### Default Object Access Permissions on resource class DocumentRestricted rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:DocumentRestricted ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent"^^xsd:string . ### Default Object Access Permissions on resource class DraftBibliographicNotice rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:DraftBibliographicNotice ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher|V http://rdfh.ch/groups/0113/lumieres-lausanne-student"^^xsd:string . ### Default Object Access Permissions on resource class DraftPerson rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:DraftPerson ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student"^^xsd:string . ### Default Object Access Permissions on resource class Collection rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:Collection ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|V http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user"^^xsd:string . ### Default Object Access Permissions on resource class AdditionalResource rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:AdditionalResource ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|V http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . ### Default Object Access Permissions on resource class Image rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:Image ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|V http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . ### Default Object Access Permissions on resource class Document rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:Document ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|V http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . ### Default Object Access Permissions on resource class Finding rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:Finding ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|V http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . ### Default Object Access Permissions on resource class FreeContent rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:FreeContent ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|V http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . ### Default Object Access Permissions on resource class Dissemination rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:Dissemination ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|V http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . ### Default Object Access Permissions on resource class News rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:News ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|V http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . ### Default Object Access Permissions on resource class Project rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:Project ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|V http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . @@ -253,119 +253,119 @@ ### Default Object Access Permissions on Person for mayHaveBiography rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:Person ; knora-admin:forProperty lumieres-lausanne:mayHaveBiography ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|V http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . ### Default Object Access Permissions on Project for hasDiffusionType rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:Project ; knora-admin:forProperty lumieres-lausanne:hasDiffusionType ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator"^^xsd:string . ### Default Object Access Permissions on Transcription for hasDiffusionType rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:Transcription ; knora-admin:forProperty lumieres-lausanne:hasDiffusionType ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator"^^xsd:string . ### Default Object Access Permissions on Note for hasDiffusionType rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:Note ; knora-admin:forProperty lumieres-lausanne:hasDiffusionType ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator"^^xsd:string . ### Default Object Access Permissions on BibliographicNotice for isInProject rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:BibliographicNotice ; knora-admin:forProperty lumieres-lausanne:isInProject ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent|V http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . ### Default Object Access Permissions on BibliographicNotice for isInProjectValue rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:BibliographicNotice ; knora-admin:forProperty lumieres-lausanne:isInProjectValue ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent|V http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . ### Default Object Access Permissions on Person for isInProject rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:Person ; knora-admin:forProperty lumieres-lausanne:isInProject ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent|V http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . ### Default Object Access Permissions on Person for isInProjectValue rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:Person ; knora-admin:forProperty lumieres-lausanne:isInProjectValue ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent|V http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . ### Default Object Access Permissions on Person for noticeIsValid rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:Person ; knora-admin:forProperty lumieres-lausanne:noticeIsValid ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|V http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . ### Default Object Access Permissions on Person for hasName rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:Person ; knora-admin:forProperty lumieres-lausanne:hasName ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent|V http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . ### Default Object Access Permissions on DraftPerson for noticeIsValid rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:DraftPerson ; knora-admin:forProperty lumieres-lausanne:noticeIsValid ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|V http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . ### Default Object Access Permissions on DraftPerson for hasName rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:DraftPerson ; knora-admin:forProperty lumieres-lausanne:hasName ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|V http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . ### Default Object Access Permissions on DraftBibliographicNotice for isInProject rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:DraftBibliographicNotice ; knora-admin:forProperty lumieres-lausanne:isInProject ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent|V http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . ### Default Object Access Permissions on DraftBibliographicNotice for isInProjectValue rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:DraftBibliographicNotice ; knora-admin:forProperty lumieres-lausanne:isInProjectValue ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent|V http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . ### Default Object Access Permissions on DraftPerson for isInProject rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:DraftPerson ; knora-admin:forProperty lumieres-lausanne:isInProject ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent|V http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . ### Default Object Access Permissions on DraftPerson for isInProjectValue rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:DraftPerson ; knora-admin:forProperty lumieres-lausanne:isInProjectValue ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|M http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent|V http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . ### Default Object Access Permissions on DraftPerson for mayHaveBiography rdf:type knora-admin:DefaultObjectAccessPermission ; - knora-admin:forProject ; + knora-admin:forProject ; knora-admin:forResourceClass lumieres-lausanne:DraftPerson ; knora-admin:forProperty lumieres-lausanne:mayHaveBiography ; knora-base:hasPermissions "CR http://rdfh.ch/groups/0113/lumieres-lausanne-administrator,http://rdfh.ch/groups/0113/lumieres-lausanne-director|D knora-base:Creator|V http://rdfh.ch/groups/0113/lumieres-lausanne-phdstudent,http://rdfh.ch/groups/0113/lumieres-lausanne-researcher,http://rdfh.ch/groups/0113/lumieres-lausanne-student,http://rdfh.ch/groups/0113/lumieres-lausanne-user,knora-base:KnownUser,knora-base:UnknownUser"^^xsd:string . diff --git a/test_data/searchR2RV2/ProjectsWithOptionalPersonOrBiblio.jsonld b/test_data/searchR2RV2/ProjectsWithOptionalPersonOrBiblio.jsonld index 4486c516e6..5191f87e46 100644 --- a/test_data/searchR2RV2/ProjectsWithOptionalPersonOrBiblio.jsonld +++ b/test_data/searchR2RV2/ProjectsWithOptionalPersonOrBiblio.jsonld @@ -1,4 +1,3 @@ - { "@graph": [ { @@ -12,7 +11,7 @@ "@type": "xsd:anyURI" }, "knora-api:attachedToProject": { - "@id": "http://rdfh.ch/projects/0666" + "@id": "http://rdfh.ch/projects/cXxbOh4xRce3uLUyXHujfg" }, "knora-api:userHasPermission": "V", "knora-api:creationDate": { @@ -44,7 +43,7 @@ "@type": "xsd:anyURI" }, "knora-api:attachedToProject": { - "@id": "http://rdfh.ch/projects/0666" + "@id": "http://rdfh.ch/projects/cXxbOh4xRce3uLUyXHujfg" }, "knora-api:userHasPermission": "V", "knora-api:creationDate": { @@ -109,7 +108,7 @@ "@type": "xsd:anyURI" }, "knora-api:attachedToProject": { - "@id": "http://rdfh.ch/projects/0666" + "@id": "http://rdfh.ch/projects/cXxbOh4xRce3uLUyXHujfg" }, "knora-api:userHasPermission": "V", "knora-api:creationDate": { @@ -142,7 +141,7 @@ "@type": "xsd:anyURI" }, "knora-api:attachedToProject": { - "@id": "http://rdfh.ch/projects/0666" + "@id": "http://rdfh.ch/projects/cXxbOh4xRce3uLUyXHujfg" }, "knora-api:userHasPermission": "V", "knora-api:creationDate": { @@ -214,7 +213,7 @@ "@type": "xsd:anyURI" }, "knora-api:attachedToProject": { - "@id": "http://rdfh.ch/projects/0666" + "@id": "http://rdfh.ch/projects/cXxbOh4xRce3uLUyXHujfg" }, "knora-api:userHasPermission": "V", "knora-api:creationDate": { @@ -280,7 +279,7 @@ "@type": "xsd:anyURI" }, "knora-api:attachedToProject": { - "@id": "http://rdfh.ch/projects/0666" + "@id": "http://rdfh.ch/projects/cXxbOh4xRce3uLUyXHujfg" }, "knora-api:userHasPermission": "V", "knora-api:creationDate": { @@ -302,4 +301,4 @@ "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "xsd": "http://www.w3.org/2001/XMLSchema#" } -} \ No newline at end of file +} 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 45c7da6f22..3bf847cb6e 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 @@ -11,13 +11,17 @@ import spray.json.DefaultJsonProtocol import spray.json.JsValue import spray.json.JsonFormat import spray.json.RootJsonFormat +import zio.prelude.Validation import java.nio.file.Path import java.util.UUID import dsp.errors.BadRequestException -import dsp.errors.DataConversionException import dsp.errors.OntologyConstraintException +import dsp.errors.ValidationException +import dsp.valueobjects.Iri.ProjectIri +import dsp.valueobjects.Iri._ +import dsp.valueobjects.Project._ import dsp.valueobjects.V2 import org.knora.webapi.IRI import org.knora.webapi.messages.ResponderRequest.KnoraRequestADM @@ -28,6 +32,8 @@ import org.knora.webapi.messages.store.triplestoremessages.StringLiteralV2 import org.knora.webapi.messages.store.triplestoremessages.TriplestoreJsonProtocol import org.knora.webapi.messages.v1.responder.projectmessages.ProjectInfoV1 +import ProjectIdentifierADM._ + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // API requests @@ -505,130 +511,103 @@ case class ProjectADM( } /** - * The ProjectIdentifierADM factory object, making sure that all necessary checks are performed and all inputs - * validated and escaped. + * Represents the project's identifier, which can be an IRI, shortcode, shortname or UUID. */ -object ProjectIdentifierADM { - def apply(maybeIri: Option[IRI] = None, maybeShortname: Option[String] = None, maybeShortcode: Option[String] = None)( - implicit sf: StringFormatter - ): ProjectIdentifierADM = { - - val parametersCount: Int = List( - maybeIri, - maybeShortname, - maybeShortcode - ).flatten.size - - // something needs to be set - if (parametersCount == 0) throw BadRequestException("Empty project identifier is not allowed.") - - if (parametersCount > 1) throw BadRequestException("Only one option allowed for project identifier.") - - new ProjectIdentifierADM( - maybeIri = - sf.validateAndEscapeOptionalProjectIri(maybeIri, throw BadRequestException(s"Invalid user project $maybeIri")), - maybeShortname = sf.validateAndEscapeOptionalProjectShortname( - maybeShortname, - throw BadRequestException(s"Invalid user project shortname $maybeShortname") - ), - maybeShortcode = sf.validateAndEscapeOptionalProjectShortcode( - maybeShortcode, - throw BadRequestException(s"Invalid user project shortcode $maybeShortcode") - ) - ) - } -} +sealed trait ProjectIdentifierADM { self => + def asIriIdentifierOption: Option[String] = + self match { + case IriIdentifier(value) => Some(value.value) + case _ => None + } -/** - * Represents the project's identifier. It can be an IRI, shortcode or shortname. - * - * @param maybeIri the project's IRI. - * @param maybeShortname the project's shortname. - * @param maybeShortcode the project's shortcode - */ -class ProjectIdentifierADM private ( - maybeIri: Option[IRI] = None, - maybeShortname: Option[String] = None, - maybeShortcode: Option[String] = None -) { - - // squash and return value. - val value: String = List( - maybeIri, - maybeShortname, - maybeShortcode - ).flatten.head - - def hasType: ProjectIdentifierType = - if (maybeIri.isDefined) { - ProjectIdentifierType.IRI - } else if (maybeShortcode.isDefined) { - ProjectIdentifierType.SHORTCODE - } else { - ProjectIdentifierType.SHORTNAME + def asShortcodeIdentifierOption: Option[String] = + self match { + case ShortcodeIdentifier(value) => Some(value.value) + case _ => None } - /** - * Tries to return the value as an IRI. - */ - def toIri: IRI = - maybeIri.getOrElse( - throw DataConversionException(s"Identifier $value is not of the required 'ProjectIdentifierType.IRI' type.") - ) + def asShortnameIdentifierOption: Option[String] = + self match { + case ShortnameIdentifier(value) => Some(value.value) + case _ => None + } - /** - * Returns an optional value of the identifier. - */ - def toIriOption: Option[IRI] = - maybeIri + def asUuidIdentifierOption: Option[String] = + self match { + case UuidIdentifier(value) => Some(UuidIdentifier.makeProjectIri(value.value)) + case _ => None + } +} + +object ProjectIdentifierADM { /** - * Tries to return the value as an SHORTNAME. + * Represents [[IriIdentifier]] identifier. + * + * @param value that constructs the identifier in the type of [[ProjectIri]] value object. */ - def toShortname: String = - maybeShortname.getOrElse( - throw DataConversionException(s"Identifier $value is not of the required 'ProjectIdentifierType.SHORTNAME' type.") - ) + final case class IriIdentifier(value: ProjectIri) extends ProjectIdentifierADM + object IriIdentifier { + def fromString(value: String): Validation[ValidationException, IriIdentifier] = + ProjectIri.make(value).map { + IriIdentifier(_) + } + } /** - * Returns an optional value of the identifier. + * Represents [[ShortcodeIdentifier]] identifier. + * + * @param value that constructs the identifier in the type of [[ShortCode]] value object. */ - def toShortnameOption: Option[String] = - maybeShortname + final case class ShortcodeIdentifier(value: ShortCode) extends ProjectIdentifierADM + object ShortcodeIdentifier { + def fromString(value: String): Validation[ValidationException, ShortcodeIdentifier] = + ShortCode.make(value).map { + ShortcodeIdentifier(_) + } + } /** - * Tries to return the value as an SHORTCODE. + * Represents [[ShortnameIdentifier]] identifier. + * + * @param value that constructs the identifier in the type of [[ShortName]] value object. */ - def toShortcode: String = - maybeShortcode.getOrElse( - throw DataConversionException(s"Identifier $value is not of the required 'ProjectIdentifierType.SHORTCODE' type.") - ) + final case class ShortnameIdentifier(value: ShortName) extends ProjectIdentifierADM + object ShortnameIdentifier { + def fromString(value: String): Validation[ValidationException, ShortnameIdentifier] = + ShortName.make(value).map { + ShortnameIdentifier(_) + } + } /** - * Returns an optional value of the identifier. + * Represents [[UuidIdentifier]] identifier. + * + * @param value that constructs the identifier in the type of [[Base64Uuid]] value object. */ - def toShortcodeOption: Option[String] = - maybeShortcode + final case class UuidIdentifier(value: Base64Uuid) extends ProjectIdentifierADM + object UuidIdentifier { + def fromString(value: String): Validation[ValidationException, UuidIdentifier] = + Base64Uuid.make(value).map { + UuidIdentifier(_) + } + + def makeProjectIri(uuid: String) = s"http://rdfh.ch/projects/${uuid}" + } /** - * Returns the string representation + * Gets desired Project identifier value. + * + * @param identifier either IRI, Shortname, Shortcode or UUID of the project. + * @return identifier's value as [[String]] */ - override def toString: IRI = - s"ProjectIdentifierADM(${this.value})" - -} - -/** - * Project identifier types: - * - IRI - * - Shortcode - * - Shortname - */ -sealed trait ProjectIdentifierType -object ProjectIdentifierType { - case object IRI extends ProjectIdentifierType - case object SHORTCODE extends ProjectIdentifierType - case object SHORTNAME extends ProjectIdentifierType + def getId(identifier: ProjectIdentifierADM): String = + identifier match { + case IriIdentifier(value) => value.value + case ShortnameIdentifier(value) => value.value + case ShortcodeIdentifier(value) => value.value + case UuidIdentifier(value) => UuidIdentifier.makeProjectIri(value.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 3838ae8b19..424ed7edf6 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 @@ -16,6 +16,7 @@ import scala.concurrent.ExecutionContext import scala.concurrent.Future import dsp.errors.AssertionException +import dsp.errors.BadRequestException import dsp.errors.InconsistentRepositoryDataException import dsp.errors.NotImplementedException import org.knora.webapi._ @@ -26,7 +27,7 @@ import org.knora.webapi.messages.SmartIri import org.knora.webapi.messages.StringFormatter import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectGetRequestADM import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectGetResponseADM -import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM +import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.store.triplestoremessages.SparqlExtendedConstructResponse.ConstructPredicateObjects import org.knora.webapi.messages.store.triplestoremessages._ @@ -1570,7 +1571,9 @@ object ConstructResponseUtilV2 { appActor .ask( ProjectGetRequestADM( - identifier = ProjectIdentifierADM(maybeIri = Some(resourceAttachedToProject)), + identifier = IriIdentifier + .fromString(resourceAttachedToProject) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = requestingUser ) ) diff --git a/webapi/src/main/scala/org/knora/webapi/messages/util/search/QueryTraverser.scala b/webapi/src/main/scala/org/knora/webapi/messages/util/search/QueryTraverser.scala index 85ce575294..0d32199a61 100644 --- a/webapi/src/main/scala/org/knora/webapi/messages/util/search/QueryTraverser.scala +++ b/webapi/src/main/scala/org/knora/webapi/messages/util/search/QueryTraverser.scala @@ -13,6 +13,7 @@ import scala.concurrent.ExecutionContext import scala.concurrent._ import scala.concurrent.duration._ +import dsp.errors.BadRequestException import org.knora.webapi.InternalSchema import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.OntologyConstants @@ -20,7 +21,7 @@ import org.knora.webapi.messages.SmartIri import org.knora.webapi.messages.StringFormatter import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectADM import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectGetADM -import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM +import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ import org.knora.webapi.responders.v2.ontology.Cache /** @@ -231,13 +232,19 @@ object QueryTraverser { val shortcode = internal.getProjectCode shortcode match { case None => FastFuture.successful(Seq.empty) - case Some(_) => { + case Some(value) => { // find the project with the shortcode for { projectMaybe <- appActor - .ask(ProjectGetADM(ProjectIdentifierADM(maybeShortcode = shortcode)))(Duration(100, SECONDS)) + .ask( + ProjectGetADM( + ShortcodeIdentifier + .fromString(value) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) + ) + )(Duration(100, SECONDS)) .mapTo[Option[ProjectADM]] projectOntologies = projectMaybe match { case None => Seq.empty 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 c87e9dbbc2..a6e4a657f8 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 @@ -26,7 +26,7 @@ import org.knora.webapi.messages.StringFormatter import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectADM import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectGetRequestADM import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectGetResponseADM -import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM +import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.util.PermissionUtilADM.EntityPermission import org.knora.webapi.messages.util._ @@ -702,7 +702,9 @@ object CreateResourceRequestV2 extends KnoraJsonLDRequestReaderV2[CreateResource appActor .ask( ProjectGetRequestADM( - identifier = ProjectIdentifierADM(maybeIri = Some(projectIri.toString)), + identifier = IriIdentifier + .fromString(projectIri.toString) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = requestingUser ) ) 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 1bf122ac6f..9cf5886a0d 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 @@ -20,7 +20,7 @@ import org.knora.webapi.messages.SmartIri import org.knora.webapi.messages.admin.responder.groupsmessages._ import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectADM import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectGetADM -import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM +import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ import org.knora.webapi.messages.admin.responder.usersmessages._ import org.knora.webapi.messages.store.triplestoremessages._ import org.knora.webapi.messages.util.KnoraSystemInstances @@ -114,9 +114,9 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond appActor .ask( ProjectGetADM( - identifier = ProjectIdentifierADM( - maybeIri = Some(projectIri) - ) + identifier = IriIdentifier + .fromString(projectIri) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) ) ) .mapTo[Option[ProjectADM]] @@ -420,9 +420,10 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond } ) + iri = createRequest.project.value nameExists <- groupByNameAndProjectExists( name = createRequest.name.value, - projectIri = createRequest.project.value + projectIri = iri ) _ = if (nameExists) { throw DuplicateValueException(s"Group with the name '${createRequest.name.value}' already exists") @@ -432,7 +433,9 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond appActor .ask( ProjectGetADM( - identifier = ProjectIdentifierADM(maybeIri = Some(createRequest.project.value)) + identifier = IriIdentifier + .fromString(iri) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) ) ) .mapTo[Option[ProjectADM]] @@ -783,7 +786,9 @@ class GroupsResponderADM(responderData: ResponderData) extends Responder(respond appActor .ask( ProjectGetADM( - identifier = ProjectIdentifierADM(maybeIri = Some(projectIri)) + identifier = IriIdentifier + .fromString(projectIri) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) ) ) .mapTo[Option[ProjectADM]] 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 15e87f8c34..6ce640db10 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,7 +25,7 @@ import org.knora.webapi.messages.admin.responder.listsmessages.ListNodeCreatePay import org.knora.webapi.messages.admin.responder.listsmessages._ import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectADM import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectGetADM -import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM +import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ import org.knora.webapi.messages.admin.responder.usersmessages._ import org.knora.webapi.messages.store.triplestoremessages._ import org.knora.webapi.messages.util.KnoraSystemInstances @@ -938,13 +938,16 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde for { /* 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 <- appActor - .ask( - ProjectGetADM( - identifier = ProjectIdentifierADM(maybeIri = Some(projectIri.value)) - ) - ) - .mapTo[Option[ProjectADM]] + maybeProject <- + appActor + .ask( + ProjectGetADM( + identifier = IriIdentifier + .fromString(projectIri.value) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) + ) + ) + .mapTo[Option[ProjectADM]] project: ProjectADM = maybeProject match { case Some(project: ProjectADM) => project @@ -2264,15 +2267,16 @@ class ListsResponderADM(responderData: ResponderData) extends Responder(responde protected def getDataNamedGraph(projectIri: IRI): Future[IRI] = for { /* Get the project information */ - maybeProject <- appActor - .ask( - ProjectGetADM( - ProjectIdentifierADM( - maybeIri = Some(projectIri) - ) - ) - ) - .mapTo[Option[ProjectADM]] + maybeProject <- + appActor + .ask( + ProjectGetADM( + IriIdentifier + .fromString(projectIri) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) + ) + ) + .mapTo[Option[ProjectADM]] project: ProjectADM = maybeProject match { case Some(project: ProjectADM) => project 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 b3fa57fa25..966a7b9033 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 @@ -24,7 +24,7 @@ import org.knora.webapi.messages.admin.responder.permissionsmessages import org.knora.webapi.messages.admin.responder.permissionsmessages._ import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectADM import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectGetADM -import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM +import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.store.triplestoremessages._ import org.knora.webapi.messages.util.KnoraSystemInstances @@ -697,7 +697,9 @@ class PermissionsResponderADM(responderData: ResponderData) extends Responder(re appActor .ask( ProjectGetADM( - identifier = ProjectIdentifierADM(maybeIri = Some(createRequest.forProject)) + identifier = IriIdentifier + .fromString(createRequest.forProject) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) ) ) .mapTo[Option[ProjectADM]] @@ -1634,7 +1636,9 @@ class PermissionsResponderADM(responderData: ResponderData) extends Responder(re appActor .ask( ProjectGetADM( - identifier = ProjectIdentifierADM(maybeIri = Some(createRequest.forProject)) + identifier = IriIdentifier + .fromString(createRequest.forProject) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) ) ) .mapTo[Option[ProjectADM]] 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 85d7ef12a0..f16e027ee3 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 @@ -25,6 +25,7 @@ import org.knora.webapi.messages.IriConversions._ import org.knora.webapi.messages.OntologyConstants import org.knora.webapi.messages.SmartIri import org.knora.webapi.messages.admin.responder.permissionsmessages._ +import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ 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.UserGetADM @@ -204,9 +205,9 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo } yield result /** - * Gets the project with the given project IRI, shortname, or shortcode and returns the information as a [[ProjectADM]]. + * Gets the project with the given project IRI, shortname, shortcode or UUID and returns the information as a [[ProjectADM]]. * - * @param identifier the IRI, shortname, or shortcode of the project. + * @param identifier the IRI, shortname, shortcode or UUID of the project. * @param skipCache if `true`, doesn't check the cache and tries to retrieve the project directly from the triplestore * @return information about the project as an optional [[ProjectADM]]. */ @@ -218,7 +219,7 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo log.debug( s"getSingleProjectADM - id: {}, skipCache: {}", - identifier.value, + getId(identifier), skipCache ) @@ -234,19 +235,19 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo _ = if (maybeProjectADM.nonEmpty) { - log.debug("getSingleProjectADM - successfully retrieved project: {}", identifier.value) + log.debug("getSingleProjectADM - successfully retrieved project: {}", getId(identifier)) } else { - log.debug("getSingleProjectADM - could not retrieve project: {}", identifier.value) + log.debug("getSingleProjectADM - could not retrieve project: {}", getId(identifier)) } } yield maybeProjectADM } /** - * Gets the project with the given project IRI, shortname, or shortcode and returns the information + * Gets the project with the given project IRI, shortname, shortcode or UUID and returns the information * as a [[ProjectGetResponseADM]]. * - * @param identifier the IRI, shortname, or shortcode of the project. + * @param identifier the IRI, shortname, shortcode or UUID of the project. * @param requestingUser the user making the request. * @return information about the project as a [[ProjectGetResponseADM]]. * @throws NotFoundException when no project for the given IRI can be found @@ -262,17 +263,17 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo project = maybeProject match { case Some(p) => p - case None => throw NotFoundException(s"Project '${identifier.value}' not found") + case None => throw NotFoundException(s"Project '${getId(identifier)}' not found") } } yield ProjectGetResponseADM( project = project ) /** - * Gets the members of a project with the given IRI, shortname, oder shortcode. Returns an empty list + * Gets the members of a project with the given IRI, shortname, shortcode or UUID. Returns an empty list * if none are found. * - * @param identifier the IRI, shortname, or shortcode of the project. + * @param identifier the IRI, shortname, shortcode or UUID of the project. * @param requestingUser the user making the request. * @return the members of a project as a [[ProjectMembersGetResponseADM]] */ @@ -290,7 +291,7 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo _ = if (project.isEmpty) { - throw NotFoundException(s"Project '${identifier.value}' not found.") + throw NotFoundException(s"Project '${getId(identifier)}' not found.") } else { if ( !requestingUser.permissions.isSystemAdmin && !requestingUser.permissions.isProjectAdmin( @@ -304,9 +305,9 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo sparqlQueryString <- Future( org.knora.webapi.messages.twirl.queries.sparql.admin.txt .getProjectMembers( - maybeIri = identifier.toIriOption, - maybeShortname = identifier.toShortnameOption, - maybeShortcode = identifier.toShortcodeOption + maybeIri = identifier.asIriIdentifierOption, + maybeShortname = identifier.asShortnameIdentifierOption, + maybeShortcode = identifier.asShortcodeIdentifierOption ) .toString() ) @@ -352,10 +353,10 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo } yield ProjectMembersGetResponseADM(members = users) /** - * Gets the admin members of a project with the given IRI, shortname, or shortcode. Returns an empty list + * Gets the admin members of a project with the given IRI, shortname, shortcode or UUIDe. Returns an empty list * if none are found * - * @param identifier the IRI, shortname, or shortcode of the project. + * @param identifier the IRI, shortname, shortcode or UUID of the project. * @param requestingUser the user making the request. * @return the members of a project as a [[ProjectMembersGetResponseADM]] */ @@ -372,7 +373,7 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo _ = if (project.isEmpty) { - throw NotFoundException(s"Project '${identifier.value}' not found.") + throw NotFoundException(s"Project '${getId(identifier)}' not found.") } else { if (!requestingUser.permissions.isSystemAdmin && !requestingUser.permissions.isProjectAdmin(project.get.id)) { throw ForbiddenException("SystemAdmin or ProjectAdmin permissions are required.") @@ -382,9 +383,9 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo sparqlQueryString <- Future( org.knora.webapi.messages.twirl.queries.sparql.admin.txt .getProjectAdminMembers( - maybeIri = identifier.toIriOption, - maybeShortname = identifier.toShortnameOption, - maybeShortcode = identifier.toShortcodeOption + maybeIri = identifier.asIriIdentifierOption, + maybeShortname = identifier.asShortnameIdentifierOption, + maybeShortcode = identifier.asShortcodeIdentifierOption ) .toString() ) @@ -459,7 +460,9 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo ): Future[ProjectKeywordsGetResponseADM] = for { maybeProject <- getSingleProjectADM( - identifier = ProjectIdentifierADM(maybeIri = Some(projectIri)) + identifier = IriIdentifier + .fromString(projectIri) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) ) keywords: Seq[String] = maybeProject match { @@ -572,7 +575,7 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo ) project: ProjectADM = maybeProject.getOrElse( - throw NotFoundException(s"Project '${projectIdentifier.value}' not found.") + throw NotFoundException(s"Project '${getId(projectIdentifier)}' not found.") ) // Check that the user has permission to download the data. @@ -665,7 +668,7 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo /** * Get project's restricted view settings. * - * @param identifier the project's identifier (IRI / shortcode / shortname) + * @param identifier the project's identifier (IRI / shortcode / shortname / UUID) * * @param requestingUser the user making the request. * @return [[ProjectRestrictedViewSettingsADM]] @@ -679,9 +682,9 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo sparqlQuery <- Future( org.knora.webapi.messages.twirl.queries.sparql.admin.txt .getProjects( - maybeIri = identifier.toIriOption, - maybeShortname = identifier.toShortnameOption, - maybeShortcode = identifier.toShortcodeOption + maybeIri = identifier.asIriIdentifierOption, + maybeShortname = identifier.asShortnameIdentifierOption, + maybeShortcode = identifier.asShortcodeIdentifierOption ) .toString() ) @@ -716,7 +719,7 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo /** * Get project's restricted view settings. * - * @param identifier the project's identifier (IRI / shortcode / shortname) + * @param identifier the project's identifier (IRI / shortcode / shortname / UUID) * * @param requestingUser the user making the request. * @return [[ProjectRestrictedViewSettingsGetResponseADM]] @@ -724,30 +727,24 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo private def projectRestrictedViewSettingsGetRequestADM( identifier: ProjectIdentifierADM, requestingUser: UserADM - ): Future[ProjectRestrictedViewSettingsGetResponseADM] = { - - val maybeIri = identifier.toIriOption - val maybeShortname = identifier.toShortnameOption - val maybeShortcode = identifier.toShortcodeOption - + ): Future[ProjectRestrictedViewSettingsGetResponseADM] = for { - maybeSettings: Option[ProjectRestrictedViewSettingsADM] <- projectRestrictedViewSettingsGetADM( - identifier = identifier, - requestingUser = requestingUser - ) + maybeSettings: Option[ProjectRestrictedViewSettingsADM] <- + projectRestrictedViewSettingsGetADM( + identifier = identifier, + requestingUser = requestingUser + ) settings = maybeSettings match { case Some(s) => s case None => throw NotFoundException( - s"Project '${Seq(maybeIri, maybeShortname, maybeShortcode).flatten.head}' not found." + s"Project '${getId(identifier)}' not found." ) } } yield ProjectRestrictedViewSettingsGetResponseADM(settings) - } - /** * Changes project's basic information. * @@ -850,10 +847,13 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo if (parametersCount == 0) throw BadRequestException("No data would be changed. Aborting update request.") for { - maybeCurrentProject: Option[ProjectADM] <- getSingleProjectADM( - identifier = ProjectIdentifierADM(maybeIri = Some(projectIri)), - skipCache = true - ) + maybeCurrentProject: Option[ProjectADM] <- + getSingleProjectADM( + identifier = IriIdentifier + .fromString(projectIri) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), + skipCache = true + ) _ = if (maybeCurrentProject.isEmpty) { throw NotFoundException(s"Project '$projectIri' not found. Aborting update request.") @@ -885,10 +885,13 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo .mapTo[SparqlUpdateResponse] /* Verify that the project was updated. */ - maybeUpdatedProject <- getSingleProjectADM( - identifier = ProjectIdentifierADM(maybeIri = Some(projectIri)), - skipCache = true - ) + maybeUpdatedProject <- + getSingleProjectADM( + identifier = IriIdentifier + .fromString(projectIri) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), + skipCache = true + ) updatedProject: ProjectADM = maybeUpdatedProject.getOrElse( @@ -1128,10 +1131,13 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo .mapTo[SparqlUpdateResponse] // try to retrieve newly created project (will also add to cache) - maybeNewProjectADM <- getSingleProjectADM( - identifier = ProjectIdentifierADM(maybeIri = Some(newProjectIRI)), - skipCache = true - ) + maybeNewProjectADM <- + getSingleProjectADM( + identifier = IriIdentifier + .fromString(newProjectIRI) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), + skipCache = true + ) // check to see if we could retrieve the new project newProjectADM = maybeNewProjectADM.getOrElse( @@ -1200,13 +1206,12 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo identifier: ProjectIdentifierADM ): Future[Option[ProjectADM]] = for { - sparqlQuery <- Future( org.knora.webapi.messages.twirl.queries.sparql.admin.txt .getProjects( - maybeIri = identifier.toIriOption, - maybeShortname = identifier.toShortnameOption, - maybeShortcode = identifier.toShortcodeOption + maybeIri = identifier.asIriIdentifierOption, + maybeShortname = identifier.asShortnameIdentifierOption, + maybeShortcode = identifier.asShortcodeIdentifierOption ) .toString() ) @@ -1230,14 +1235,13 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo maybeProjectADM: Option[ProjectADM] = if (projectResponse.statements.nonEmpty) { - log.debug("getProjectFromTriplestore - triplestore hit for: {}", identifier) + log.debug("getProjectFromTriplestore - triplestore hit for: {}", getId(identifier)) val projectOntologies = ontologies.getOrElse(projectIris.head, Seq.empty[IRI]) Some(statements2ProjectADM(statements = projectResponse.statements.head, ontologies = projectOntologies)) } else { - log.debug("getProjectFromTriplestore - no triplestore hit for: {}", identifier) + log.debug("getProjectFromTriplestore - no triplestore hit for: {}", getId(identifier)) None } - } yield maybeProjectADM /** @@ -1358,10 +1362,10 @@ class ProjectsResponderADM(responderData: ResponderData) extends Responder(respo val result = appActor.ask(CacheServiceGetProjectADM(identifier)).mapTo[Option[ProjectADM]] result.map { case Some(project) => - log.debug("getProjectFromCache - cache hit for: {}", identifier) + log.debug("getProjectFromCache - cache hit for: {}", getId(identifier)) Some(project.unescape) case None => - log.debug("getUserProjectCache - no cache hit for: {}", identifier) + log.debug("getUserProjectCache - no cache hit for: {}", getId(identifier)) None } } 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 c4169db62e..753667aaa7 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 @@ -10,10 +10,11 @@ import akka.pattern._ import scala.concurrent.Future +import dsp.errors.BadRequestException import dsp.errors.InconsistentRepositoryDataException import dsp.errors.NotFoundException import org.knora.webapi.messages.SmartIri -import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM +import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectRestrictedViewSettingsADM import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectRestrictedViewSettingsGetADM import org.knora.webapi.messages.admin.responder.sipimessages.SipiFileInfoGetRequestADM @@ -122,7 +123,9 @@ class SipiResponderADM(responderData: ResponderData) extends Responder(responder appActor .ask( ProjectRestrictedViewSettingsGetADM( - identifier = ProjectIdentifierADM(maybeShortcode = Some(request.projectID)), + identifier = ShortcodeIdentifier + .fromString(request.projectID) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = KnoraSystemInstances.Users.SystemUser ) ) 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 a7de7f653b..f36acedff1 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 @@ -27,7 +27,7 @@ import org.knora.webapi.messages.admin.responder.permissionsmessages.PermissionD import org.knora.webapi.messages.admin.responder.permissionsmessages.PermissionsDataADM import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectADM import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectGetADM -import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM +import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ import org.knora.webapi.messages.admin.responder.usersmessages.UserChangeRequestADM import org.knora.webapi.messages.admin.responder.usersmessages._ import org.knora.webapi.messages.store.cacheservicemessages.CacheServiceGetUserADM @@ -908,16 +908,18 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde case None => Seq.empty[IRI] } - maybeProjectFutures: Seq[Future[Option[ProjectADM]]] = projectIris.map { projectIri => - appActor - .ask( - ProjectGetADM( - identifier = - ProjectIdentifierADM(maybeIri = Some(projectIri)) - ) - ) - .mapTo[Option[ProjectADM]] - } + maybeProjectFutures: Seq[Future[Option[ProjectADM]]] = + projectIris.map { projectIri => + appActor + .ask( + ProjectGetADM( + identifier = IriIdentifier + .fromString(projectIri) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) + ) + ) + .mapTo[Option[ProjectADM]] + } maybeProjects: Seq[Option[ProjectADM]] <- Future.sequence(maybeProjectFutures) projects: Seq[ProjectADM] = maybeProjects.flatten @@ -1945,15 +1947,18 @@ class UsersResponderADM(responderData: ResponderData) extends Responder(responde // _ = log.debug("statements2UserADM - groups: {}", MessageUtil.toSource(groups)) - maybeProjectFutures: Seq[Future[Option[ProjectADM]]] = projectIris.map { projectIri => - appActor - .ask( - ProjectGetADM( - ProjectIdentifierADM(maybeIri = Some(projectIri)) - ) - ) - .mapTo[Option[ProjectADM]] - } + maybeProjectFutures: Seq[Future[Option[ProjectADM]]] = + projectIris.map { projectIri => + appActor + .ask( + ProjectGetADM( + identifier = IriIdentifier + .fromString(projectIri) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) + ) + ) + .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/ResourcesResponderV1.scala b/webapi/src/main/scala/org/knora/webapi/responders/v1/ResourcesResponderV1.scala index 5583b3bb39..e8ee008c17 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 @@ -30,7 +30,7 @@ import org.knora.webapi.messages.admin.responder.permissionsmessages.ResourceCre import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectADM import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectGetRequestADM import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectGetResponseADM -import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM +import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.store.triplestoremessages._ import org.knora.webapi.messages.twirl.SparqlTemplateResourceToCreate @@ -1582,14 +1582,17 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo } // Get information about the project in which the resources will be created. - projectInfoResponse <- appActor - .ask( - ProjectGetRequestADM( - identifier = ProjectIdentifierADM(maybeIri = Some(projectIri)), - requestingUser = requestingUser - ) - ) - .mapTo[ProjectGetResponseADM] + projectInfoResponse <- + appActor + .ask( + ProjectGetRequestADM( + identifier = IriIdentifier + .fromString(projectIri) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), + requestingUser = requestingUser + ) + ) + .mapTo[ProjectGetResponseADM] projectADM = projectInfoResponse.project @@ -2457,14 +2460,17 @@ class ResourcesResponderV1(responderData: ResponderData) extends Responder(respo } // Get project info - projectResponse <- appActor - .ask( - ProjectGetRequestADM( - identifier = ProjectIdentifierADM(maybeIri = Some(projectIri)), - requestingUser = userProfile - ) - ) - .mapTo[ProjectGetResponseADM] + projectResponse <- + appActor + .ask( + ProjectGetRequestADM( + identifier = IriIdentifier + .fromString(projectIri) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), + requestingUser = userProfile + ) + ) + .mapTo[ProjectGetResponseADM] // Ensure that the project isn't the system project or the shared ontologies project. 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 0686e914c8..a9c1115fbe 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,7 +24,7 @@ import org.knora.webapi.messages.admin.responder.permissionsmessages.PermissionT import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectADM import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectGetRequestADM import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectGetResponseADM -import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM +import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.store.triplestoremessages._ import org.knora.webapi.messages.twirl.SparqlTemplateLinkUpdate @@ -839,7 +839,9 @@ class ValuesResponderV1(responderData: ResponderData) extends Responder(responde appActor .ask( ProjectGetRequestADM( - identifier = ProjectIdentifierADM(maybeIri = Some(resourceInfoResponse.resource_info.get.project_id)), + identifier = IriIdentifier + .fromString(resourceInfoResponse.resource_info.get.project_id) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = changeFileValueRequest.userProfile ) ) 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 00f12cd073..6e9c03719f 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 @@ -20,7 +20,7 @@ import org.knora.webapi.messages.OntologyConstants import org.knora.webapi.messages.SmartIri import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectGetRequestADM import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectGetResponseADM -import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM +import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.store.triplestoremessages.SmartIriLiteralV2 import org.knora.webapi.messages.store.triplestoremessages.SparqlUpdateRequest @@ -608,7 +608,9 @@ class OntologyResponderV2(responderData: ResponderData) extends Responder(respon appActor .ask( ProjectGetRequestADM( - identifier = ProjectIdentifierADM(maybeIri = Some(projectIri.toString)), + identifier = IriIdentifier + .fromString(projectIri.toString) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = requestingUser ) ) 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 fa86ead457..c8e2fff289 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 @@ -23,6 +23,7 @@ import org.knora.webapi.messages.SmartIri import org.knora.webapi.messages.admin.responder.permissionsmessages.DefaultObjectAccessPermissionsStringForResourceClassGetADM import org.knora.webapi.messages.admin.responder.permissionsmessages.DefaultObjectAccessPermissionsStringResponseADM import org.knora.webapi.messages.admin.responder.permissionsmessages.ResourceCreateOperation +import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ import org.knora.webapi.messages.admin.responder.projectsmessages._ import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.store.sipimessages.SipiGetTextFileRequest @@ -2672,17 +2673,17 @@ class ResourcesResponderV2(responderData: ResponderData) extends ResponderWithSt ): Future[ResourceAndValueVersionHistoryResponseV2] = for { // Get the project; checks if a project with given IRI exists. - projectInfoResponse: ProjectGetResponseADM <- appActor - .ask( - ProjectGetRequestADM( - identifier = ProjectIdentifierADM(maybeIri = - Some(projectResourceHistoryEventsGetRequest.projectIri) - ), - requestingUser = - projectResourceHistoryEventsGetRequest.requestingUser - ) - ) - .mapTo[ProjectGetResponseADM] + projectInfoResponse: ProjectGetResponseADM <- + appActor + .ask( + ProjectGetRequestADM( + identifier = IriIdentifier + .fromString(projectResourceHistoryEventsGetRequest.projectIri) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), + requestingUser = projectResourceHistoryEventsGetRequest.requestingUser + ) + ) + .mapTo[ProjectGetResponseADM] // Do a SELECT prequery to get the IRIs of the resources that belong to the project. prequery = org.knora.webapi.messages.twirl.queries.sparql.v2.txt 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 1e0e27c661..c328ecb3f3 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 @@ -32,7 +32,7 @@ import org.knora.webapi.messages.SmartIri import org.knora.webapi.messages.StringFormatter import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectADM import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectGetADM -import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM +import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.store.sipimessages.SipiGetTextFileRequest import org.knora.webapi.messages.store.sipimessages.SipiGetTextFileResponse @@ -668,7 +668,9 @@ class StandoffResponderV2(responderData: ResponderData) extends Responder(respon appActor .ask( ProjectGetADM( - identifier = ProjectIdentifierADM(maybeIri = Some(projectIri.toString)) + identifier = IriIdentifier + .fromString(projectIri.toString) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) ) ) .mapTo[Option[ProjectADM]] 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 a00a3e6aa4..cd0196e75d 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 @@ -29,11 +29,13 @@ import dsp.errors.BadRequestException import dsp.valueobjects.Iri.ProjectIri import dsp.valueobjects.Project._ import org.knora.webapi.IRI +import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ import org.knora.webapi.messages.admin.responder.projectsmessages._ import org.knora.webapi.routing.Authenticator import org.knora.webapi.routing.KnoraRoute import org.knora.webapi.routing.KnoraRouteData import org.knora.webapi.routing.RouteUtilADM + class ProjectsRouteADM(routeData: KnoraRouteData) extends KnoraRoute(routeData) with Authenticator @@ -50,11 +52,13 @@ class ProjectsRouteADM(routeData: KnoraRouteData) getKeywords() ~ getProjectKeywords() ~ getProjectByIri() ~ + getProjectByUuid() ~ getProjectByShortname() ~ getProjectByShortcode() ~ changeProject() ~ deleteProject() ~ getProjectMembersByIri() ~ + getProjectMembersByUuid() ~ getProjectMembersByShortname() ~ getProjectMembersByShortcode() ~ getProjectAdminMembersByIri() ~ @@ -65,7 +69,9 @@ class ProjectsRouteADM(routeData: KnoraRouteData) getProjectRestrictedViewSettingsByShortcode() ~ getProjectData() - /* return all projects */ + /** + * Returns all projects. + */ private def getProjects(): Route = path(projectsBasePath) { get { requestContext => log.info("All projects requested.") @@ -87,7 +93,9 @@ class ProjectsRouteADM(routeData: KnoraRouteData) } } - /* create a new project */ + /** + * Creates a new project. + */ private def addProject(): Route = path(projectsBasePath) { post { entity(as[CreateProjectApiRequestADM]) { apiRequest => requestContext => @@ -125,7 +133,9 @@ class ProjectsRouteADM(routeData: KnoraRouteData) } } - /* returns all unique keywords for all projects as a list */ + /** + * Returns all unique keywords for all projects as a list. + */ private def getKeywords(): Route = path(projectsBasePath / "Keywords") { get { requestContext => val requestMessage: Future[ProjectsKeywordsGetRequestADM] = for { @@ -146,7 +156,9 @@ class ProjectsRouteADM(routeData: KnoraRouteData) } } - /* returns all keywords for a single project */ + /** + * Returns all keywords for a single project. + */ private def getProjectKeywords(): Route = path(projectsBasePath / "iri" / Segment / "Keywords") { value => get { requestContext => @@ -173,7 +185,7 @@ class ProjectsRouteADM(routeData: KnoraRouteData) } /** - * returns a single project identified through iri + * Returns a single project identified through the IRI. */ private def getProjectByIri(): Route = path(projectsBasePath / "iri" / Segment) { value => @@ -183,11 +195,39 @@ class ProjectsRouteADM(routeData: KnoraRouteData) requestContext = requestContext, routeData.appConfig ) - checkedProjectIri = - stringFormatter.validateAndEscapeProjectIri(value, throw BadRequestException(s"Invalid project IRI $value")) } yield ProjectGetRequestADM( - identifier = ProjectIdentifierADM(maybeIri = Some(checkedProjectIri)), + identifier = IriIdentifier + .fromString(value) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), + requestingUser = requestingUser + ) + + RouteUtilADM.runJsonRoute( + requestMessageF = requestMessage, + requestContext = requestContext, + appActor = appActor, + log = log + ) + } + } + + /** + * Returns a single project identified through the Base64 encoded UUID. + */ + private def getProjectByUuid(): Route = + path(projectsBasePath / "uuid" / Segment) { value => + get { requestContext => + val requestMessage: Future[ProjectGetRequestADM] = for { + requestingUser <- getUserADM( + requestContext = requestContext, + routeData.appConfig + ) + + } yield ProjectGetRequestADM( + identifier = UuidIdentifier + .fromString(value) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = requestingUser ) @@ -201,7 +241,7 @@ class ProjectsRouteADM(routeData: KnoraRouteData) } /** - * returns a single project identified through shortname. + * Returns a single project identified through the shortname. */ private def getProjectByShortname(): Route = path(projectsBasePath / "shortname" / Segment) { value => @@ -211,13 +251,11 @@ class ProjectsRouteADM(routeData: KnoraRouteData) requestContext = requestContext, routeData.appConfig ) - shortNameDec = stringFormatter.validateAndEscapeProjectShortname( - value, - throw BadRequestException(s"Invalid project shortname $value") - ) } yield ProjectGetRequestADM( - identifier = ProjectIdentifierADM(maybeShortname = Some(shortNameDec)), + identifier = ShortnameIdentifier + .fromString(value) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = requestingUser ) @@ -231,7 +269,7 @@ class ProjectsRouteADM(routeData: KnoraRouteData) } /** - * returns a single project identified through shortcode. + * Returns a single project identified through the shortcode. */ private def getProjectByShortcode(): Route = path(projectsBasePath / "shortcode" / Segment) { value => @@ -241,13 +279,11 @@ class ProjectsRouteADM(routeData: KnoraRouteData) requestContext = requestContext, routeData.appConfig ) - checkedShortcode = stringFormatter.validateAndEscapeProjectShortcode( - value, - throw BadRequestException(s"Invalid project shortcode $value") - ) } yield ProjectGetRequestADM( - identifier = ProjectIdentifierADM(maybeShortcode = Some(checkedShortcode)), + identifier = ShortcodeIdentifier + .fromString(value) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = requestingUser ) @@ -261,7 +297,7 @@ class ProjectsRouteADM(routeData: KnoraRouteData) } /** - * update a project identified by iri + * Updates a project identified by the IRI. */ private def changeProject(): Route = path(projectsBasePath / "iri" / Segment) { value => @@ -295,7 +331,7 @@ class ProjectsRouteADM(routeData: KnoraRouteData) } /** - * update project status to false + * Updates project status to false. */ private def deleteProject(): Route = path(projectsBasePath / "iri" / Segment) { value => @@ -325,7 +361,7 @@ class ProjectsRouteADM(routeData: KnoraRouteData) } /** - * returns all members part of a project identified through iri + * Returns all members of a project identified through the IRI. */ private def getProjectMembersByIri(): Route = path(projectsBasePath / "iri" / Segment / "members") { value => @@ -335,11 +371,11 @@ class ProjectsRouteADM(routeData: KnoraRouteData) requestContext = requestContext, routeData.appConfig ) - checkedProjectIri = - stringFormatter.validateAndEscapeProjectIri(value, throw BadRequestException(s"Invalid project IRI $value")) } yield ProjectMembersGetRequestADM( - identifier = ProjectIdentifierADM(maybeIri = Some(checkedProjectIri)), + identifier = IriIdentifier + .fromString(value) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = requestingUser ) @@ -353,7 +389,35 @@ class ProjectsRouteADM(routeData: KnoraRouteData) } /** - * returns all members part of a project identified through shortname + * Returns all members of a project identified through the Base64 encoded UUID. + */ + private def getProjectMembersByUuid(): Route = + path(projectsBasePath / "uuid" / Segment / "members") { value => + get { requestContext => + val requestMessage: Future[ProjectMembersGetRequestADM] = for { + requestingUser <- getUserADM( + requestContext = requestContext, + routeData.appConfig + ) + + } yield ProjectMembersGetRequestADM( + identifier = UuidIdentifier + .fromString(value) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), + requestingUser = requestingUser + ) + + RouteUtilADM.runJsonRoute( + requestMessageF = requestMessage, + requestContext = requestContext, + appActor = appActor, + log = log + ) + } + } + + /** + * Returns all members of a project identified through the shortname. */ private def getProjectMembersByShortname(): Route = path(projectsBasePath / "shortname" / Segment / "members") { value => @@ -363,13 +427,11 @@ class ProjectsRouteADM(routeData: KnoraRouteData) requestContext = requestContext, routeData.appConfig ) - shortNameDec = stringFormatter.validateAndEscapeProjectShortname( - value, - throw BadRequestException(s"Invalid project shortname $value") - ) } yield ProjectMembersGetRequestADM( - identifier = ProjectIdentifierADM(maybeShortname = Some(shortNameDec)), + identifier = ShortnameIdentifier + .fromString(value) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = requestingUser ) @@ -383,7 +445,7 @@ class ProjectsRouteADM(routeData: KnoraRouteData) } /** - * returns all members part of a project identified through shortcode + * Returns all members of a project identified through the shortcode. */ private def getProjectMembersByShortcode(): Route = path(projectsBasePath / "shortcode" / Segment / "members") { value => @@ -393,13 +455,11 @@ class ProjectsRouteADM(routeData: KnoraRouteData) requestContext = requestContext, routeData.appConfig ) - checkedShortcode = stringFormatter.validateAndEscapeProjectShortcode( - value, - throw BadRequestException(s"Invalid project shortcode $value") - ) } yield ProjectMembersGetRequestADM( - identifier = ProjectIdentifierADM(maybeShortcode = Some(checkedShortcode)), + identifier = ShortcodeIdentifier + .fromString(value) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = requestingUser ) @@ -413,7 +473,7 @@ class ProjectsRouteADM(routeData: KnoraRouteData) } /** - * returns all admin members part of a project identified through iri + * Returns all admin members of a project identified through the IRI. */ private def getProjectAdminMembersByIri(): Route = path(projectsBasePath / "iri" / Segment / "admin-members") { value => @@ -423,11 +483,11 @@ class ProjectsRouteADM(routeData: KnoraRouteData) requestContext = requestContext, routeData.appConfig ) - checkedProjectIri = - stringFormatter.validateAndEscapeProjectIri(value, throw BadRequestException(s"Invalid project IRI $value")) } yield ProjectAdminMembersGetRequestADM( - identifier = ProjectIdentifierADM(maybeIri = Some(checkedProjectIri)), + identifier = IriIdentifier + .fromString(value) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = requestingUser ) @@ -441,7 +501,7 @@ class ProjectsRouteADM(routeData: KnoraRouteData) } /** - * returns all admin members part of a project identified through shortname + * Returns all admin members of a project identified through the shortname. */ private def getProjectAdminMembersByShortname(): Route = path(projectsBasePath / "shortname" / Segment / "admin-members") { value => @@ -451,13 +511,11 @@ class ProjectsRouteADM(routeData: KnoraRouteData) requestContext = requestContext, routeData.appConfig ) - checkedShortname = stringFormatter.validateAndEscapeProjectShortname( - value, - throw BadRequestException(s"Invalid project shortname $value") - ) } yield ProjectAdminMembersGetRequestADM( - identifier = ProjectIdentifierADM(maybeShortname = Some(checkedShortname)), + identifier = ShortnameIdentifier + .fromString(value) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = requestingUser ) @@ -471,7 +529,7 @@ class ProjectsRouteADM(routeData: KnoraRouteData) } /** - * returns all admin members part of a project identified through shortcode + * Returns all admin members of a project identified through shortcode. */ private def getProjectAdminMembersByShortcode(): Route = path(projectsBasePath / "shortcode" / Segment / "admin-members") { value => @@ -481,13 +539,11 @@ class ProjectsRouteADM(routeData: KnoraRouteData) requestContext = requestContext, routeData.appConfig ) - checkedShortcode = stringFormatter.validateProjectShortcode( - value, - throw BadRequestException(s"Invalid project shortcode $value") - ) } yield ProjectAdminMembersGetRequestADM( - identifier = ProjectIdentifierADM(maybeShortcode = Some(checkedShortcode)), + identifier = ShortcodeIdentifier + .fromString(value) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = requestingUser ) @@ -501,7 +557,7 @@ class ProjectsRouteADM(routeData: KnoraRouteData) } /** - * Returns the project's restricted view settings identified through IRI. + * Returns the project's restricted view settings identified through the IRI. */ private def getProjectRestrictedViewSettingsByIri(): Route = path(projectsBasePath / "iri" / Segment / "RestrictedViewSettings") { value: String => @@ -513,7 +569,9 @@ class ProjectsRouteADM(routeData: KnoraRouteData) ) } yield ProjectRestrictedViewSettingsGetRequestADM( - identifier = ProjectIdentifierADM(maybeIri = Some(value)), + identifier = IriIdentifier + .fromString(value) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = requestingUser ) @@ -527,7 +585,7 @@ class ProjectsRouteADM(routeData: KnoraRouteData) } /** - * Returns the project's restricted view settings identified through shortname. + * Returns the project's restricted view settings identified through the shortname. */ private def getProjectRestrictedViewSettingsByShortname(): Route = path(projectsBasePath / "shortname" / Segment / "RestrictedViewSettings") { value: String => @@ -537,10 +595,11 @@ class ProjectsRouteADM(routeData: KnoraRouteData) requestContext = requestContext, routeData.appConfig ) - shortNameDec = java.net.URLDecoder.decode(value, "utf-8") } yield ProjectRestrictedViewSettingsGetRequestADM( - identifier = ProjectIdentifierADM(maybeShortname = Some(shortNameDec)), + identifier = ShortnameIdentifier + .fromString(value) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = requestingUser ) @@ -564,8 +623,11 @@ class ProjectsRouteADM(routeData: KnoraRouteData) requestContext = requestContext, routeData.appConfig ) + } yield ProjectRestrictedViewSettingsGetRequestADM( - identifier = ProjectIdentifierADM(maybeShortcode = Some(value)), + identifier = ShortcodeIdentifier + .fromString(value) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = requestingUser ) @@ -596,8 +658,6 @@ class ProjectsRouteADM(routeData: KnoraRouteData) } private def getProjectDataEntity(projectIri: IRI): Route = { requestContext => - val projectIdentifier = ProjectIdentifierADM(maybeIri = Some(projectIri)) - val httpEntityFuture: Future[HttpEntity.Chunked] = for { requestingUser <- getUserADM( requestContext = requestContext, @@ -605,7 +665,9 @@ class ProjectsRouteADM(routeData: KnoraRouteData) ) requestMessage = ProjectDataGetRequestADM( - projectIdentifier = projectIdentifier, + projectIdentifier = IriIdentifier + .fromString(projectIri) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = requestingUser ) 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 eab5739cfb..325a138d01 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 @@ -42,7 +42,7 @@ import org.knora.webapi.messages.SmartIri import org.knora.webapi.messages.StringFormatter.XmlImportNamespaceInfoV1 import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectGetRequestADM import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectGetResponseADM -import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM +import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.store.sipimessages.GetFileMetadataRequest import org.knora.webapi.messages.store.sipimessages.GetFileMetadataResponse @@ -297,10 +297,8 @@ class ResourcesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) apiRequest: CreateResourceApiRequestV1, userADM: UserADM ): Future[ResourceCreateRequestV1] = { - val projectIri = stringFormatter.validateAndEscapeIri( - apiRequest.project_id, - throw BadRequestException(s"Invalid project IRI: ${apiRequest.project_id}") - ) + val projectIri = apiRequest.project_id + val resourceTypeIri = stringFormatter.validateAndEscapeIri( apiRequest.restype_id, throw BadRequestException(s"Invalid resource IRI: ${apiRequest.restype_id}") @@ -311,17 +309,20 @@ class ResourcesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) ) for { - projectShortcode: String <- for { - projectResponse: ProjectGetResponseADM <- - appActor - .ask( - ProjectGetRequestADM( - ProjectIdentifierADM(maybeIri = Some(projectIri)), - requestingUser = userADM - ) - ) - .mapTo[ProjectGetResponseADM] - } yield projectResponse.project.shortcode + projectShortcode: String <- + for { + projectResponse: ProjectGetResponseADM <- + appActor + .ask( + ProjectGetRequestADM( + identifier = IriIdentifier + .fromString(projectIri) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), + requestingUser = userADM + ) + ) + .mapTo[ProjectGetResponseADM] + } yield projectResponse.project.shortcode file: Option[FileValueV1] <- apiRequest.file match { case Some(filename) => @@ -443,17 +444,20 @@ class ResourcesRouteV1(routeData: KnoraRouteData) extends KnoraRoute(routeData) } for { - projectShortcode: String <- for { - projectResponse: ProjectGetResponseADM <- - appActor - .ask( - ProjectGetRequestADM( - identifier = ProjectIdentifierADM(maybeIri = Some(projectId)), - requestingUser = userProfile - ) - ) - .mapTo[ProjectGetResponseADM] - } yield projectResponse.project.shortcode + projectShortcode: String <- + for { + projectResponse: ProjectGetResponseADM <- + appActor + .ask( + ProjectGetRequestADM( + identifier = IriIdentifier + .fromString(projectId) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), + requestingUser = userProfile + ) + ) + .mapTo[ProjectGetResponseADM] + } yield projectResponse.project.shortcode resourcesToCreate: Seq[Future[OneOfMultipleResourceCreateRequestV1]] = resourceRequest.map { createResourceRequest => diff --git a/webapi/src/main/scala/org/knora/webapi/store/cache/impl/CacheServiceInMemImpl.scala b/webapi/src/main/scala/org/knora/webapi/store/cache/impl/CacheServiceInMemImpl.scala index 0b370df66c..3d774c60a8 100644 --- a/webapi/src/main/scala/org/knora/webapi/store/cache/impl/CacheServiceInMemImpl.scala +++ b/webapi/src/main/scala/org/knora/webapi/store/cache/impl/CacheServiceInMemImpl.scala @@ -8,9 +8,11 @@ package org.knora.webapi.store.cache.impl import zio._ import zio.stm._ +import dsp.valueobjects.Iri +import dsp.valueobjects.Project import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectADM import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM -import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierType +import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.admin.responder.usersmessages.UserIdentifierADM import org.knora.webapi.messages.admin.responder.usersmessages.UserIdentifierType @@ -119,32 +121,54 @@ case class CacheServiceInMemImpl( * @return an optional [[ProjectADM]] */ def getProjectADM(identifier: ProjectIdentifierADM): Task[Option[ProjectADM]] = - (identifier.hasType match { - case ProjectIdentifierType.IRI => getProjectByIri(identifier.toIri) - case ProjectIdentifierType.SHORTCODE => getProjectByShortcodeOrShortname(identifier.toShortcode) - case ProjectIdentifierType.SHORTNAME => getProjectByShortcodeOrShortname(identifier.toShortname) + (identifier match { + case IriIdentifier(value) => getProjectByIri(value) + case ShortcodeIdentifier(value) => getProjectByShortcode(value) + case ShortnameIdentifier(value) => getProjectByShortname(value) + case UuidIdentifier(value) => getProjectByUuid(value) }).tap(_ => ZIO.logDebug(s"Retrieved ProjectADM from Cache: $identifier")) /** - * Retrieves the project stored under the IRI. + * Retrieves the project by the IRI. * - * @param id the project's IRI + * @param iri the project's IRI * @return an optional [[ProjectADM]]. */ - def getProjectByIri(id: String) = projects.get(id).commit + def getProjectByIri(iri: Iri.ProjectIri) = projects.get(iri.value).commit + + /** + * Retrieves the project by the SHORTNAME. + * + * @param shortname of the project. + * @return an optional [[ProjectADM]] + */ + def getProjectByShortname(shortname: Project.ShortName): UIO[Option[ProjectADM]] = + (for { + iri <- lut.get(shortname.value).some + project <- projects.get(iri).some + } yield project).commit.unsome /** - * Retrieves the project stored under a SHORTCODE or SHORTNAME. + * Retrieves the project by the SHORTCODE. * - * @param shortcodeOrShortname of the project. + * @param shortcode of the project. * @return an optional [[ProjectADM]] */ - def getProjectByShortcodeOrShortname(shortcodeOrShortname: String): UIO[Option[ProjectADM]] = + def getProjectByShortcode(shortcode: Project.ShortCode): UIO[Option[ProjectADM]] = (for { - iri <- lut.get(shortcodeOrShortname).some + iri <- lut.get(shortcode.value).some project <- projects.get(iri).some } yield project).commit.unsome + /** + * Retrieves the project by the UUID. + * + * @param uuid the project's UUID + * @return an optional [[ProjectADM]]. + */ + def getProjectByUuid(uuid: Iri.Base64Uuid) = + projects.get(UuidIdentifier.makeProjectIri(uuid.value)).commit + /** * Store string or byte array value under key. * diff --git a/webapi/src/main/scala/org/knora/webapi/store/cache/impl/CacheServiceRedisImpl.scala b/webapi/src/main/scala/org/knora/webapi/store/cache/impl/CacheServiceRedisImpl.scala index 1c08fd4309..ba8d6cbf37 100644 --- a/webapi/src/main/scala/org/knora/webapi/store/cache/impl/CacheServiceRedisImpl.scala +++ b/webapi/src/main/scala/org/knora/webapi/store/cache/impl/CacheServiceRedisImpl.scala @@ -11,9 +11,11 @@ import redis.clients.jedis.JedisPoolConfig import zio._ import dsp.errors.ForbiddenException +import dsp.valueobjects.Iri +import dsp.valueobjects.Project import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectADM import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM -import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierType +import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.admin.responder.usersmessages.UserIdentifierADM import org.knora.webapi.messages.admin.responder.usersmessages.UserIdentifierType @@ -105,42 +107,85 @@ case class CacheServiceRedisImpl(pool: JedisPool) extends CacheService { } yield () /** - * Retrieves the project stored under the identifier (either iri, shortname, or shortcode). + * Retrieves the project stored under the identifier, either Iri, Shortcode, Shortname or Uuid. * * @param identifier the project identifier. */ def getProjectADM(identifier: ProjectIdentifierADM): Task[Option[ProjectADM]] = - // The data is stored under the IRI key. - // Additionally, the SHORTNAME and SHORTCODE keys point to the IRI key - identifier.hasType match { - case ProjectIdentifierType.IRI => getProjectByIri(identifier.toIri) - case ProjectIdentifierType.SHORTCODE => getProjectByShortcodeOrShortname(identifier.toShortcode) - case ProjectIdentifierType.SHORTNAME => getProjectByShortcodeOrShortname(identifier.toShortname) + // The data is stored under the Iri + // Additionally, the Shortcode, Shortname and Uuid point to the Iri + identifier match { + case IriIdentifier(value) => getProjectByIri(value) + case ShortcodeIdentifier(value) => getProjectByShortcode(value) + case ShortnameIdentifier(value) => getProjectByShortname(value) + case UuidIdentifier(value) => getProjectByUuid(value) } /** - * Retrieves the project stored under the IRI. + * Retrieves the project by its IRI. * * @param id the project's IRI * @return an optional [[ProjectADM]]. */ - def getProjectByIri(id: String): Task[Option[ProjectADM]] = + def getProjectByIri(iri: Iri.ProjectIri): Task[Option[ProjectADM]] = + (for { + bytes <- getBytesValue(iri.value) + project <- + bytes match { + case Some(value) => CacheSerialization.deserialize[ProjectADM](value) + case None => ZIO.succeed(None) + } + } yield project) + + /** + * Retrieves the project by its SHORTNAME. + * + * @param shortname of the project. + * @return an optional [[ProjectADM]] + */ + def getProjectByShortname(shortname: Project.ShortName): Task[Option[ProjectADM]] = (for { - bytes <- getBytesValue(id).some - project <- CacheSerialization.deserialize[ProjectADM](bytes).some - } yield project).unsome + iri <- getStringValue(shortname.value) + validIri <- Iri.ProjectIri.make(iri).toZIO + project <- + validIri match { + case Some(value) => getProjectByIri(value) + case None => ZIO.succeed(None) + } + } yield project) /** - * Retrieves the project stored under a SHORTCODE or SHORTNAME. + * Retrieves the project by its SHORTCODE. * - * @param shortcodeOrShortname of the project. + * @param shortcode of the project. * @return an optional [[ProjectADM]] */ - def getProjectByShortcodeOrShortname(shortcodeOrShortname: String): Task[Option[ProjectADM]] = + def getProjectByShortcode(shortcode: Project.ShortCode): Task[Option[ProjectADM]] = + (for { + iri <- getStringValue(shortcode.value) + validIri <- Iri.ProjectIri.make(iri).toZIO + project <- + validIri match { + case Some(value) => getProjectByIri(value) + case None => ZIO.succeed(None) + } + } yield project) + + /** + * Retrieves the project by its UUID. + * + * @param id the project's UUID + * @return an optional [[ProjectADM]]. + */ + def getProjectByUuid(uuid: Iri.Base64Uuid): Task[Option[ProjectADM]] = (for { - iri <- getStringValue(shortcodeOrShortname).some - project <- getProjectByIri(iri).some - } yield project).unsome + bytes <- getBytesValue(UuidIdentifier.makeProjectIri(uuid.value)) + project <- + bytes match { + case Some(value) => CacheSerialization.deserialize[ProjectADM](value) + case None => ZIO.succeed(None) + } + } yield project) /** * Store string value under key. diff --git a/webapi/src/main/scala/org/knora/webapi/store/triplestore/upgrade/plugins/UpgradePluginPR2255.scala b/webapi/src/main/scala/org/knora/webapi/store/triplestore/upgrade/plugins/UpgradePluginPR2255.scala index 1a863b7d6b..c84a5403e4 100644 --- a/webapi/src/main/scala/org/knora/webapi/store/triplestore/upgrade/plugins/UpgradePluginPR2255.scala +++ b/webapi/src/main/scala/org/knora/webapi/store/triplestore/upgrade/plugins/UpgradePluginPR2255.scala @@ -13,7 +13,7 @@ import org.knora.webapi.store.triplestore.upgrade.UpgradePlugin /** * Transforms a repository for DSP-API PR2255. * Transforms incorrect value of project IRIs from the one containing either shortcode or - * not suppored UUID version to UUID v4 base64 encoded. + * not supported UUID version to UUID v4 base64 encoded. */ class UpgradePluginPR2255(log: Logger) extends UpgradePlugin { private val nodeFactory: RdfNodeFactory = RdfFeatureFactory.getRdfNodeFactory() @@ -34,7 +34,8 @@ class UpgradePluginPR2255(log: Logger) extends UpgradePlugin { statementsToAdd += nodeFactory.makeStatement( subj = updatedNode, pred = statement.pred, - obj = statement.obj + obj = statement.obj, + context = statement.context ) } @@ -44,7 +45,8 @@ class UpgradePluginPR2255(log: Logger) extends UpgradePlugin { statementsToAdd += nodeFactory.makeStatement( subj = statement.subj, pred = statement.pred, - obj = updatedNode + obj = updatedNode, + context = statement.context ) } } yield () @@ -61,6 +63,18 @@ class UpgradePluginPR2255(log: Logger) extends UpgradePlugin { object ProjectsIrisToChange { val prefix = "http://rdfh.ch/projects/" + + // KEEP it for reference, not a part of plugin and used only for replacement of + // IRIs existing in DSP-API repo + val onlyFoundInRepo: Map[String, String] = Map( + "0113" -> "bFURQB6zR1ugDFQL7EZy9Q", + "0666" -> "cXxbOh4xRce3uLUyXHujfg", + // beol in v1 test data + "0801" -> "bL0y8GRuTUiFmvF1oXbeFQ", + // dokubib in v1 test data + "00FE" -> "oIjhUsZmQLuJ0VMGvJ2pfg" + ) + val newToOldIrisMap: Map[String, String] = Map( s"${prefix}0001" -> s"${prefix}Lw3FC39BSzCwvmdOaTyLqQ", s"${prefix}00FF" -> s"${prefix}MTvoB0EJRrqovzRkWXqfkA", 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 3722cd4677..cd2c12c389 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 @@ -57,6 +57,8 @@ class ProjectsADME2ESpec // Collects client test data private val clientTestDataCollector = new ClientTestDataCollector(appConfig) + private val notExistingProjectButValidProjectIri = "http://rdfh.ch/projects/cXxbOh4xRce3uLUyXHujfg" + override lazy val rdfDataObjects: List[RdfDataObject] = List( RdfDataObject(path = "test_data/all_data/anything-data.ttl", name = "http://www.knora.org/data/0001/anything") ) @@ -743,7 +745,7 @@ class ProjectsADME2ESpec } "return 'NotFound' when the project IRI is unknown" in { - val notexistingIriEnc = URLEncoder.encode("http://rdfh.ch/projects/notexisting", "utf-8") + val notexistingIriEnc = URLEncoder.encode(notExistingProjectButValidProjectIri, "utf-8") val request = Get(baseApiUrl + s"/admin/projects/iri/$notexistingIriEnc/Keywords") ~> addCredentials( BasicHttpCredentials(rootEmail, testPass) ) diff --git a/webapi/src/test/scala/org/knora/webapi/messages/admin/responder/projectsmessages/ProjectsMessagesADMSpec.scala b/webapi/src/test/scala/org/knora/webapi/messages/admin/responder/projectsmessages/ProjectsMessagesADMSpec.scala index 151550fb81..c2deb4aa34 100644 --- a/webapi/src/test/scala/org/knora/webapi/messages/admin/responder/projectsmessages/ProjectsMessagesADMSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/messages/admin/responder/projectsmessages/ProjectsMessagesADMSpec.scala @@ -9,6 +9,7 @@ import dsp.errors.BadRequestException import dsp.errors.OntologyConstraintException import org.knora.webapi._ import org.knora.webapi.messages.StringFormatter +import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ import org.knora.webapi.messages.store.triplestoremessages.StringLiteralV2 import org.knora.webapi.sharedtestdata.SharedTestDataADM @@ -55,20 +56,28 @@ class ProjectsMessagesADMSpec extends CoreSpec { "The ProjectIdentifierADM class" should { "return without throwing when the project IRI is valid" in { - ProjectIdentifierADM(maybeIri = - Some(SharedTestDataADM.incunabulaProject.id) - ).value shouldBe SharedTestDataADM.incunabulaProject.id - ProjectIdentifierADM(maybeIri = - Some(SharedTestDataADM.defaultSharedOntologiesProject.id) - ).value shouldBe SharedTestDataADM.defaultSharedOntologiesProject.id - ProjectIdentifierADM(maybeIri = - Some(SharedTestDataADM.systemProject.id) - ).value shouldBe SharedTestDataADM.systemProject.id + IriIdentifier + .fromString(SharedTestDataADM.incunabulaProject.id) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) + .value + .value shouldBe SharedTestDataADM.incunabulaProject.id + IriIdentifier + .fromString(SharedTestDataADM.defaultSharedOntologiesProject.id) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) + .value + .value shouldBe SharedTestDataADM.defaultSharedOntologiesProject.id + IriIdentifier + .fromString(SharedTestDataADM.systemProject.id) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) + .value + .value shouldBe SharedTestDataADM.systemProject.id } "return a 'BadRequestException' when the project IRI is invalid" in { assertThrows[BadRequestException] { - ProjectIdentifierADM(maybeIri = Some("http://not-valid.org")) + IriIdentifier + .fromString("http://not-valid.org") + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) } } } diff --git a/webapi/src/test/scala/org/knora/webapi/other/v2/LumieresLausanneV2E2ESpec.scala b/webapi/src/test/scala/org/knora/webapi/other/v2/LumieresLausanneV2E2ESpec.scala index 19935bb4aa..c58f45ec4e 100644 --- a/webapi/src/test/scala/org/knora/webapi/other/v2/LumieresLausanneV2E2ESpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/other/v2/LumieresLausanneV2E2ESpec.scala @@ -52,7 +52,7 @@ class LumieresLausanneV2E2ESpec extends E2ESpec with TriplestoreJsonProtocol { | "@type": "onto:User", | "rdfs:label": "Test", | "knora-api:attachedToProject": { - | "@id": "http://rdfh.ch/projects/0113" + | "@id": "http://rdfh.ch/projects/bFURQB6zR1ugDFQL7EZy9Q" | }, | "onto:isKnoraUser": { | "@type": "knora-api:UriValue", 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 a50f92153b..1579ce7cd6 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 @@ -24,6 +24,7 @@ import org.knora.webapi._ import org.knora.webapi.messages.OntologyConstants import org.knora.webapi.messages.StringFormatter import org.knora.webapi.messages.admin.responder.permissionsmessages._ +import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ import org.knora.webapi.messages.admin.responder.projectsmessages._ import org.knora.webapi.messages.admin.responder.usersmessages.UserInformationTypeADM import org.knora.webapi.messages.store.triplestoremessages._ @@ -40,6 +41,8 @@ class ProjectsResponderADMSpec extends CoreSpec with ImplicitSender { private val rootUser = SharedTestDataADM.rootUser + private val notExistingProjectButValidProjectIri = "http://rdfh.ch/projects/cXxbOh4xRce3uLUyXHujfg" + "The ProjectsResponderADM" when { "used to query for project information" should { "return information for every project" in { @@ -53,9 +56,10 @@ class ProjectsResponderADMSpec extends CoreSpec with ImplicitSender { } "return information about a project identified by IRI" in { - /* Incunabula project */ appActor ! ProjectGetRequestADM( - identifier = ProjectIdentifierADM(maybeIri = Some(SharedTestDataADM.incunabulaProject.id)), + identifier = IriIdentifier + .fromString(SharedTestDataADM.incunabulaProject.id) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = SharedTestDataADM.rootUser ) expectMsg(ProjectGetResponseADM(SharedTestDataADM.incunabulaProject)) @@ -64,7 +68,9 @@ class ProjectsResponderADMSpec extends CoreSpec with ImplicitSender { "return information about a project identified by shortname" in { appActor ! ProjectGetRequestADM( - identifier = ProjectIdentifierADM(maybeShortname = Some(SharedTestDataADM.incunabulaProject.shortname)), + identifier = ShortnameIdentifier + .fromString(SharedTestDataADM.incunabulaProject.shortname) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = SharedTestDataADM.rootUser ) expectMsg(ProjectGetResponseADM(SharedTestDataADM.incunabulaProject)) @@ -72,16 +78,20 @@ class ProjectsResponderADMSpec extends CoreSpec with ImplicitSender { "return 'NotFoundException' when the project IRI is unknown" in { appActor ! ProjectGetRequestADM( - identifier = ProjectIdentifierADM(maybeIri = Some("http://rdfh.ch/projects/notexisting")), + identifier = IriIdentifier + .fromString(notExistingProjectButValidProjectIri) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = SharedTestDataADM.rootUser ) - expectMsg(Failure(NotFoundException(s"Project 'http://rdfh.ch/projects/notexisting' not found"))) + expectMsg(Failure(NotFoundException(s"Project '$notExistingProjectButValidProjectIri' not found"))) } "return 'NotFoundException' when the project shortname is unknown " in { appActor ! ProjectGetRequestADM( - identifier = ProjectIdentifierADM(maybeShortname = Some("wrongshortname")), + identifier = ShortnameIdentifier + .fromString("wrongshortname") + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = SharedTestDataADM.rootUser ) expectMsg(Failure(NotFoundException(s"Project 'wrongshortname' not found"))) @@ -89,7 +99,9 @@ class ProjectsResponderADMSpec extends CoreSpec with ImplicitSender { "return 'NotFoundException' when the project shortcode is unknown " in { appActor ! ProjectGetRequestADM( - identifier = ProjectIdentifierADM(maybeShortcode = Some("9999")), + identifier = ShortcodeIdentifier + .fromString("9999") + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = SharedTestDataADM.rootUser ) expectMsg(Failure(NotFoundException(s"Project '9999' not found"))) @@ -101,7 +113,9 @@ class ProjectsResponderADMSpec extends CoreSpec with ImplicitSender { "return restricted view settings using project IRI" in { appActor ! ProjectRestrictedViewSettingsGetADM( - identifier = ProjectIdentifierADM(maybeIri = Some(SharedTestDataADM.imagesProject.id)), + identifier = IriIdentifier + .fromString(SharedTestDataADM.imagesProject.id) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = SharedTestDataADM.rootUser ) expectMsg(Some(expectedResult)) @@ -109,7 +123,9 @@ class ProjectsResponderADMSpec extends CoreSpec with ImplicitSender { "return restricted view settings using project SHORTNAME" in { appActor ! ProjectRestrictedViewSettingsGetADM( - identifier = ProjectIdentifierADM(maybeShortname = Some(SharedTestDataADM.imagesProject.shortname)), + identifier = ShortnameIdentifier + .fromString(SharedTestDataADM.imagesProject.shortname) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = SharedTestDataADM.rootUser ) expectMsg(Some(expectedResult)) @@ -117,7 +133,9 @@ class ProjectsResponderADMSpec extends CoreSpec with ImplicitSender { "return restricted view settings using project SHORTCODE" in { appActor ! ProjectRestrictedViewSettingsGetADM( - identifier = ProjectIdentifierADM(maybeShortcode = Some(SharedTestDataADM.imagesProject.shortcode)), + identifier = ShortcodeIdentifier + .fromString(SharedTestDataADM.imagesProject.shortcode) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = SharedTestDataADM.rootUser ) expectMsg(Some(expectedResult)) @@ -125,15 +143,19 @@ class ProjectsResponderADMSpec extends CoreSpec with ImplicitSender { "return 'NotFoundException' when the project IRI is unknown" in { appActor ! ProjectRestrictedViewSettingsGetRequestADM( - identifier = ProjectIdentifierADM(maybeIri = Some("http://rdfh.ch/projects/notexisting")), + identifier = IriIdentifier + .fromString(notExistingProjectButValidProjectIri) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = SharedTestDataADM.rootUser ) - expectMsg(Failure(NotFoundException(s"Project 'http://rdfh.ch/projects/notexisting' not found."))) + expectMsg(Failure(NotFoundException(s"Project '$notExistingProjectButValidProjectIri' not found."))) } "return 'NotFoundException' when the project SHORTCODE is unknown" in { appActor ! ProjectRestrictedViewSettingsGetRequestADM( - identifier = ProjectIdentifierADM(maybeShortcode = Some("9999")), + identifier = ShortcodeIdentifier + .fromString("9999") + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = SharedTestDataADM.rootUser ) expectMsg(Failure(NotFoundException(s"Project '9999' not found."))) @@ -141,7 +163,9 @@ class ProjectsResponderADMSpec extends CoreSpec with ImplicitSender { "return 'NotFoundException' when the project SHORTNAME is unknown" in { appActor ! ProjectRestrictedViewSettingsGetRequestADM( - identifier = ProjectIdentifierADM(maybeShortname = Some("wrongshortname")), + identifier = ShortnameIdentifier + .fromString("wrongshortname") + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = SharedTestDataADM.rootUser ) expectMsg(Failure(NotFoundException(s"Project 'wrongshortname' not found."))) @@ -392,14 +416,14 @@ class ProjectsResponderADMSpec extends CoreSpec with ImplicitSender { "return 'NotFound' if a not existing project IRI is submitted during update" in { appActor ! ProjectChangeRequestADM( - projectIri = "http://rdfh.ch/projects/notexisting", + projectIri = notExistingProjectButValidProjectIri, changeProjectRequest = ChangeProjectApiRequestADM(longname = Some("new long name")).validateAndEscape, SharedTestDataADM.rootUser, UUID.randomUUID() ) expectMsg( Failure( - NotFoundException(s"Project 'http://rdfh.ch/projects/notexisting' not found. Aborting update request.") + NotFoundException(s"Project '$notExistingProjectButValidProjectIri' not found. Aborting update request.") ) ) } @@ -449,10 +473,11 @@ class ProjectsResponderADMSpec extends CoreSpec with ImplicitSender { */ "used to query members" should { - "return all members of a project identified by IRI" in { appActor ! ProjectMembersGetRequestADM( - ProjectIdentifierADM(maybeIri = Some(SharedTestDataADM.imagesProject.id)), + IriIdentifier + .fromString(SharedTestDataADM.imagesProject.id) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), SharedTestDataADM.rootUser ) val received: ProjectMembersGetResponseADM = expectMsgType[ProjectMembersGetResponseADM](timeout) @@ -470,7 +495,9 @@ class ProjectsResponderADMSpec extends CoreSpec with ImplicitSender { "return all members of a project identified by shortname" in { appActor ! ProjectMembersGetRequestADM( - ProjectIdentifierADM(maybeShortname = Some(SharedTestDataADM.imagesProject.shortname)), + ShortnameIdentifier + .fromString(SharedTestDataADM.imagesProject.shortname) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = SharedTestDataADM.rootUser ) val received: ProjectMembersGetResponseADM = expectMsgType[ProjectMembersGetResponseADM](timeout) @@ -488,7 +515,9 @@ class ProjectsResponderADMSpec extends CoreSpec with ImplicitSender { "return all members of a project identified by shortcode" in { appActor ! ProjectMembersGetRequestADM( - ProjectIdentifierADM(maybeShortcode = Some(SharedTestDataADM.imagesProject.shortcode)), + ShortcodeIdentifier + .fromString(SharedTestDataADM.imagesProject.shortcode) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = SharedTestDataADM.rootUser ) val received: ProjectMembersGetResponseADM = expectMsgType[ProjectMembersGetResponseADM](timeout) @@ -506,15 +535,19 @@ class ProjectsResponderADMSpec extends CoreSpec with ImplicitSender { "return 'NotFound' when the project IRI is unknown (project membership)" in { appActor ! ProjectMembersGetRequestADM( - ProjectIdentifierADM(maybeIri = Some("http://rdfh.ch/projects/notexisting")), + IriIdentifier + .fromString(notExistingProjectButValidProjectIri) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), SharedTestDataADM.rootUser ) - expectMsg(Failure(NotFoundException(s"Project 'http://rdfh.ch/projects/notexisting' not found."))) + expectMsg(Failure(NotFoundException(s"Project '$notExistingProjectButValidProjectIri' not found."))) } "return 'NotFound' when the project shortname is unknown (project membership)" in { appActor ! ProjectMembersGetRequestADM( - ProjectIdentifierADM(maybeShortname = Some("wrongshortname")), + ShortnameIdentifier + .fromString("wrongshortname") + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = SharedTestDataADM.rootUser ) expectMsg(Failure(NotFoundException(s"Project 'wrongshortname' not found."))) @@ -522,7 +555,9 @@ class ProjectsResponderADMSpec extends CoreSpec with ImplicitSender { "return 'NotFound' when the project shortcode is unknown (project membership)" in { appActor ! ProjectMembersGetRequestADM( - ProjectIdentifierADM(maybeShortcode = Some("9999")), + ShortcodeIdentifier + .fromString("9999") + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = SharedTestDataADM.rootUser ) expectMsg(Failure(NotFoundException(s"Project '9999' not found."))) @@ -530,7 +565,9 @@ class ProjectsResponderADMSpec extends CoreSpec with ImplicitSender { "return all project admin members of a project identified by IRI" in { appActor ! ProjectAdminMembersGetRequestADM( - ProjectIdentifierADM(maybeIri = Some(SharedTestDataADM.imagesProject.id)), + IriIdentifier + .fromString(SharedTestDataADM.imagesProject.id) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), SharedTestDataADM.rootUser ) val received: ProjectAdminMembersGetResponseADM = expectMsgType[ProjectAdminMembersGetResponseADM](timeout) @@ -546,7 +583,9 @@ class ProjectsResponderADMSpec extends CoreSpec with ImplicitSender { "return all project admin members of a project identified by shortname" in { appActor ! ProjectAdminMembersGetRequestADM( - ProjectIdentifierADM(maybeShortname = Some(SharedTestDataADM.imagesProject.shortname)), + ShortnameIdentifier + .fromString(SharedTestDataADM.imagesProject.shortname) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = SharedTestDataADM.rootUser ) val received: ProjectAdminMembersGetResponseADM = expectMsgType[ProjectAdminMembersGetResponseADM](timeout) @@ -562,7 +601,9 @@ class ProjectsResponderADMSpec extends CoreSpec with ImplicitSender { "return all project admin members of a project identified by shortcode" in { appActor ! ProjectAdminMembersGetRequestADM( - ProjectIdentifierADM(maybeShortcode = Some(SharedTestDataADM.imagesProject.shortcode)), + ShortcodeIdentifier + .fromString(SharedTestDataADM.imagesProject.shortcode) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = SharedTestDataADM.rootUser ) val received: ProjectAdminMembersGetResponseADM = expectMsgType[ProjectAdminMembersGetResponseADM](timeout) @@ -578,15 +619,19 @@ class ProjectsResponderADMSpec extends CoreSpec with ImplicitSender { "return 'NotFound' when the project IRI is unknown (project admin membership)" in { appActor ! ProjectAdminMembersGetRequestADM( - ProjectIdentifierADM(maybeIri = Some("http://rdfh.ch/projects/notexisting")), + IriIdentifier + .fromString(notExistingProjectButValidProjectIri) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), SharedTestDataADM.rootUser ) - expectMsg(Failure(NotFoundException(s"Project 'http://rdfh.ch/projects/notexisting' not found."))) + expectMsg(Failure(NotFoundException(s"Project '$notExistingProjectButValidProjectIri' not found."))) } "return 'NotFound' when the project shortname is unknown (project admin membership)" in { appActor ! ProjectAdminMembersGetRequestADM( - ProjectIdentifierADM(maybeShortname = Some("wrongshortname")), + ShortnameIdentifier + .fromString("wrongshortname") + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = SharedTestDataADM.rootUser ) expectMsg(Failure(NotFoundException(s"Project 'wrongshortname' not found."))) @@ -594,7 +639,9 @@ class ProjectsResponderADMSpec extends CoreSpec with ImplicitSender { "return 'NotFound' when the project shortcode is unknown (project admin membership)" in { appActor ! ProjectAdminMembersGetRequestADM( - ProjectIdentifierADM(maybeShortcode = Some("9999")), + ShortcodeIdentifier + .fromString("9999") + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = SharedTestDataADM.rootUser ) expectMsg(Failure(NotFoundException(s"Project '9999' not found."))) @@ -631,11 +678,11 @@ class ProjectsResponderADMSpec extends CoreSpec with ImplicitSender { "return 'NotFound' when the project IRI is unknown" in { appActor ! ProjectKeywordsGetRequestADM( - projectIri = "http://rdfh.ch/projects/notexisting", + projectIri = notExistingProjectButValidProjectIri, SharedTestDataADM.rootUser ) - expectMsg(Failure(NotFoundException(s"Project 'http://rdfh.ch/projects/notexisting' not found."))) + expectMsg(Failure(NotFoundException(s"Project '$notExistingProjectButValidProjectIri' not found."))) } } } 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 6bd773d82f..07b79af710 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 @@ -23,7 +23,7 @@ import org.knora.webapi.messages.admin.responder.groupsmessages.GroupMembersGetR import org.knora.webapi.messages.admin.responder.groupsmessages.GroupMembersGetResponseADM import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectAdminMembersGetRequestADM import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectAdminMembersGetResponseADM -import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM +import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectMembersGetRequestADM import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectMembersGetResponseADM import org.knora.webapi.messages.admin.responder.usersmessages._ @@ -557,9 +557,12 @@ class UsersResponderADMSpec extends CoreSpec with ImplicitSender with Authentica membershipsAfterUpdate.projects should equal(Seq(imagesProject)) appActor ! ProjectMembersGetRequestADM( - ProjectIdentifierADM(maybeIri = Some(imagesProject.id)), + IriIdentifier + .fromString(imagesProject.id) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = KnoraSystemInstances.Users.SystemUser ) + val received: ProjectMembersGetResponseADM = expectMsgType[ProjectMembersGetResponseADM](timeout) received.members.map(_.id) should contain(normalUser.id) @@ -594,7 +597,9 @@ class UsersResponderADMSpec extends CoreSpec with ImplicitSender with Authentica // check that the user was not added to the project appActor ! ProjectMembersGetRequestADM( - ProjectIdentifierADM(maybeIri = Some(incunabulaProject.id)), + IriIdentifier + .fromString(incunabulaProject.id) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = KnoraSystemInstances.Users.SystemUser ) val received = expectMsgType[ProjectMembersGetResponseADM](timeout) @@ -625,7 +630,9 @@ class UsersResponderADMSpec extends CoreSpec with ImplicitSender with Authentica ) appActor ! ProjectMembersGetRequestADM( - ProjectIdentifierADM(maybeIri = Some(incunabulaProject.id)), + IriIdentifier + .fromString(incunabulaProject.id) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = KnoraSystemInstances.Users.SystemUser ) val received = expectMsgType[ProjectMembersGetResponseADM](timeout) @@ -687,7 +694,9 @@ class UsersResponderADMSpec extends CoreSpec with ImplicitSender with Authentica // also check that the user has been removed from the project's list of users appActor ! ProjectMembersGetRequestADM( - ProjectIdentifierADM(maybeIri = Some(imagesProject.id)), + IriIdentifier + .fromString(imagesProject.id) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = rootUser ) val received: ProjectMembersGetResponseADM = expectMsgType[ProjectMembersGetResponseADM](timeout) @@ -729,7 +738,6 @@ class UsersResponderADMSpec extends CoreSpec with ImplicitSender with Authentica } "asked to update the user's project admin group membership" should { - "Not ADD user to project admin group if he is not a member of that project" in { // get the current project admin memberships (should be empty) appActor ! UserProjectAdminMembershipsGetRequestADM( @@ -797,7 +805,9 @@ class UsersResponderADMSpec extends CoreSpec with ImplicitSender with Authentica // get project admins for images project (should contain normal user) appActor ! ProjectAdminMembersGetRequestADM( - ProjectIdentifierADM(maybeIri = Some(imagesProject.id)), + IriIdentifier + .fromString(imagesProject.id) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = rootUser ) val received: ProjectAdminMembersGetResponseADM = expectMsgType[ProjectAdminMembersGetResponseADM](timeout) @@ -831,7 +841,9 @@ class UsersResponderADMSpec extends CoreSpec with ImplicitSender with Authentica membershipsAfterUpdate.projects should equal(Seq()) appActor ! ProjectAdminMembersGetRequestADM( - ProjectIdentifierADM(maybeIri = Some(imagesProject.id)), + IriIdentifier + .fromString(imagesProject.id) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)), requestingUser = rootUser ) val received: ProjectAdminMembersGetResponseADM = expectMsgType[ProjectAdminMembersGetResponseADM](timeout) diff --git a/webapi/src/test/scala/org/knora/webapi/sharedtestdata/SharedTestDataADM.scala b/webapi/src/test/scala/org/knora/webapi/sharedtestdata/SharedTestDataADM.scala index 33961551cf..fb4f65d77b 100644 --- a/webapi/src/test/scala/org/knora/webapi/sharedtestdata/SharedTestDataADM.scala +++ b/webapi/src/test/scala/org/knora/webapi/sharedtestdata/SharedTestDataADM.scala @@ -202,7 +202,8 @@ object SharedTestDataADM { /** * ********************************** */ - val IMAGES_PROJECT_IRI = "http://rdfh.ch/projects/MTvoB0EJRrqovzRkWXqfkA" + val imagesProjectUuid = "MTvoB0EJRrqovzRkWXqfkA" + val IMAGES_PROJECT_IRI = s"http://rdfh.ch/projects/$imagesProjectUuid" /* represents 'user01' as found in admin-data.ttl */ def imagesUser01: UserADM = diff --git a/webapi/src/test/scala/org/knora/webapi/sharedtestdata/SharedTestDataV1.scala b/webapi/src/test/scala/org/knora/webapi/sharedtestdata/SharedTestDataV1.scala index e8b1918ee9..e4c324ec52 100644 --- a/webapi/src/test/scala/org/knora/webapi/sharedtestdata/SharedTestDataV1.scala +++ b/webapi/src/test/scala/org/knora/webapi/sharedtestdata/SharedTestDataV1.scala @@ -422,7 +422,7 @@ object SharedTestDataV1 { /** * ********************************* */ - val BEOL_PROJECT_IRI = "http://rdfh.ch/projects/0801" + val BEOL_PROJECT_IRI = "http://rdfh.ch/projects/bL0y8GRuTUiFmvF1oXbeFQ" def beolProjectInfo = ProjectInfoV1( id = BEOL_PROJECT_IRI, @@ -462,7 +462,7 @@ object SharedTestDataV1 { /** * ********************************* */ - val DOKUBIB_PROJECT_IRI = "http://rdfh.ch/projects/00FE" + val DOKUBIB_PROJECT_IRI = "http://rdfh.ch/projects/oIjhUsZmQLuJ0VMGvJ2pfg" def dokubibProjectInfo = ProjectInfoV1( id = DOKUBIB_PROJECT_IRI, diff --git a/webapi/src/test/scala/org/knora/webapi/store/cache/CacheServiceManagerSpec.scala b/webapi/src/test/scala/org/knora/webapi/store/cache/CacheServiceManagerSpec.scala index 84b7d65cb5..7e82a01aba 100644 --- a/webapi/src/test/scala/org/knora/webapi/store/cache/CacheServiceManagerSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/store/cache/CacheServiceManagerSpec.scala @@ -5,9 +5,10 @@ package org.knora.webapi.store.cache +import dsp.errors.BadRequestException import org.knora.webapi._ import org.knora.webapi.messages.StringFormatter -import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM +import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ import org.knora.webapi.messages.admin.responder.usersmessages.UserIdentifierADM import org.knora.webapi.messages.store.cacheservicemessages.CacheServiceGetProjectADM import org.knora.webapi.messages.store.cacheservicemessages.CacheServiceGetUserADM @@ -53,17 +54,31 @@ class CacheServiceManagerSpec extends CoreSpec { } "successfully retrieve a project by IRI" in { - appActor ! CacheServiceGetProjectADM(ProjectIdentifierADM(maybeIri = Some(project.id))) + appActor ! CacheServiceGetProjectADM( + IriIdentifier + .fromString(project.id) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) + ) expectMsg(Some(project)) + } "successfully retrieve a project by SHORTNAME" in { - appActor ! CacheServiceGetProjectADM(ProjectIdentifierADM(maybeShortname = Some(project.shortname))) + appActor ! CacheServiceGetProjectADM( + ShortnameIdentifier + .fromString(project.shortname) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) + ) expectMsg(Some(project)) + } "successfully retrieve a project by SHORTCODE" in { - appActor ! CacheServiceGetProjectADM(ProjectIdentifierADM(maybeShortcode = Some(project.shortcode))) + appActor ! CacheServiceGetProjectADM( + ShortcodeIdentifier + .fromString(project.shortcode) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) + ) expectMsg(Some(project)) } } diff --git a/webapi/src/test/scala/org/knora/webapi/store/cache/impl/CacheInMemImplZSpec.scala b/webapi/src/test/scala/org/knora/webapi/store/cache/impl/CacheInMemImplZSpec.scala index e666756ab8..d96ee3b878 100644 --- a/webapi/src/test/scala/org/knora/webapi/store/cache/impl/CacheInMemImplZSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/store/cache/impl/CacheInMemImplZSpec.scala @@ -9,9 +9,11 @@ import zio.ZLayer import zio.test.Assertion._ import zio.test._ +import dsp.errors.BadRequestException +import dsp.valueobjects.V2UuidValidation import org.knora.webapi.messages.StringFormatter import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectADM -import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM +import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.admin.responder.usersmessages.UserIdentifierADM import org.knora.webapi.sharedtestdata.SharedTestDataADM @@ -53,48 +55,71 @@ object CacheInMemImplZSpec extends ZIOSpecDefault { _ <- CacheService.putUserADM(user) retrievedUser <- CacheService.getUserADM(UserIdentifierADM(maybeIri = Some(user.id))) } yield assertTrue(retrievedUser == Some(user)) - } + - test("successfully store a user and retrieve by USERNAME")( - for { - _ <- CacheService.putUserADM(user) - retrievedUser <- CacheService.getUserADM(UserIdentifierADM(maybeUsername = Some(user.username))) - } yield assert(retrievedUser)(equalTo(Some(user))) - ) + - test("successfully store a user and retrieve by EMAIL")( - for { - _ <- CacheService.putUserADM(user) - retrievedUser <- CacheService.getUserADM(UserIdentifierADM(maybeEmail = Some(user.email))) - } yield assert(retrievedUser)(equalTo(Some(user))) - ) + - test("successfully store and retrieve a user with special characters in his name")( - for { - _ <- CacheService.putUserADM(userWithApostrophe) - retrievedUser <- CacheService.getUserADM(UserIdentifierADM(maybeIri = Some(userWithApostrophe.id))) - } yield assert(retrievedUser)(equalTo(Some(userWithApostrophe))) - ) + }, + test("successfully store a user and retrieve by USERNAME")( + for { + _ <- CacheService.putUserADM(user) + retrievedUser <- CacheService.getUserADM(UserIdentifierADM(maybeUsername = Some(user.username))) + } yield assert(retrievedUser)(equalTo(Some(user))) + ), + test("successfully store a user and retrieve by EMAIL")( + for { + _ <- CacheService.putUserADM(user) + retrievedUser <- CacheService.getUserADM(UserIdentifierADM(maybeEmail = Some(user.email))) + } yield assert(retrievedUser)(equalTo(Some(user))) + ), + test("successfully store and retrieve a user with special characters in his name")( + for { + _ <- CacheService.putUserADM(userWithApostrophe) + retrievedUser <- CacheService.getUserADM(UserIdentifierADM(maybeIri = Some(userWithApostrophe.id))) + } yield assert(retrievedUser)(equalTo(Some(userWithApostrophe))) + ) ) val projectTests = suite("CacheInMemImplZSpec - project")( test("successfully store a project and retrieve by IRI")( for { - _ <- CacheService.putProjectADM(project) - retrievedProject <- CacheService.getProjectADM(ProjectIdentifierADM(maybeIri = Some(project.id))) + _ <- CacheService.putProjectADM(project) + retrievedProject <- CacheService.getProjectADM( + IriIdentifier + .fromString(project.id) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) + ) + } yield assert(retrievedProject)(equalTo(Some(project))) + ), + test("successfully store a project and retrieve by SHORTCODE")( + for { + _ <- CacheService.putProjectADM(project) + retrievedProject <- + CacheService.getProjectADM( + ShortcodeIdentifier + .fromString(project.shortcode) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) + ) } yield assert(retrievedProject)(equalTo(Some(project))) - ) + - test("successfully store a project and retrieve by SHORTCODE")( - for { - _ <- CacheService.putProjectADM(project) - retrievedProject <- - CacheService.getProjectADM(ProjectIdentifierADM(maybeShortcode = Some(project.shortcode))) - } yield assert(retrievedProject)(equalTo(Some(project))) - ) + - test("successfully store a project and retrieve by SHORTNAME")( - for { - _ <- CacheService.putProjectADM(project) - retrievedProject <- - CacheService.getProjectADM(ProjectIdentifierADM(maybeShortname = Some(project.shortname))) - } yield assert(retrievedProject)(equalTo(Some(project))) - ) + ), + test("successfully store a project and retrieve by SHORTNAME")( + for { + _ <- CacheService.putProjectADM(project) + retrievedProject <- + CacheService.getProjectADM( + ShortnameIdentifier + .fromString(project.shortname) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) + ) + } yield assert(retrievedProject)(equalTo(Some(project))) + ), + test("successfully store a project and retrieve by UUID")( + for { + _ <- CacheService.putProjectADM(project) + retrievedProject <- + CacheService.getProjectADM( + UuidIdentifier + .fromString(V2UuidValidation.getUuidFromIri(project.id)) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) + ) + } yield assert(retrievedProject)(equalTo(Some(project))) + ) ) val otherTests = suite("CacheInMemImplZSpec - other")( @@ -103,13 +128,13 @@ object CacheInMemImplZSpec extends ZIOSpecDefault { _ <- CacheService.putStringValue("my-new-key", "my-new-value") retrievedValue <- CacheService.getStringValue("my-new-key") } yield assert(retrievedValue)(equalTo(Some("my-new-value"))) - ) + - test("successfully delete stored value")( - for { - _ <- CacheService.putStringValue("my-new-key", "my-new-value") - _ <- CacheService.removeValues(Set("my-new-key")) - retrievedValue <- CacheService.getStringValue("my-new-key") - } yield assert(retrievedValue)(equalTo(None)) - ) + ), + test("successfully delete stored value")( + for { + _ <- CacheService.putStringValue("my-new-key", "my-new-value") + _ <- CacheService.removeValues(Set("my-new-key")) + retrievedValue <- CacheService.getStringValue("my-new-key") + } yield assert(retrievedValue)(equalTo(None)) + ) ) } diff --git a/webapi/src/test/scala/org/knora/webapi/store/cache/impl/CacheRedisImplZSpec.scala b/webapi/src/test/scala/org/knora/webapi/store/cache/impl/CacheRedisImplZSpec.scala index 1d0062e654..2a051c84a1 100644 --- a/webapi/src/test/scala/org/knora/webapi/store/cache/impl/CacheRedisImplZSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/store/cache/impl/CacheRedisImplZSpec.scala @@ -9,9 +9,11 @@ import zio._ import zio.test.Assertion._ import zio.test._ +import dsp.errors.BadRequestException +import dsp.valueobjects.V2UuidValidation import org.knora.webapi.messages.StringFormatter import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectADM -import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM +import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ import org.knora.webapi.messages.admin.responder.usersmessages.UserADM import org.knora.webapi.messages.admin.responder.usersmessages.UserIdentifierADM import org.knora.webapi.sharedtestdata.SharedTestDataADM @@ -49,41 +51,64 @@ object CacheRedisImplZSpec extends ZIOSpecDefault { _ <- CacheService.putUserADM(user) retrievedUser <- CacheService.getUserADM(UserIdentifierADM(maybeIri = Some(user.id))) } yield assert(retrievedUser)(equalTo(Some(user))) - } @@ TestAspect.ignore + - test("successfully store a user and retrieve by USERNAME")( - for { - _ <- CacheService.putUserADM(user) - retrievedUser <- CacheService.getUserADM(UserIdentifierADM(maybeUsername = Some(user.username))) - } yield assert(retrievedUser)(equalTo(Some(user))) - ) @@ TestAspect.ignore + - test("successfully store a user and retrieve by EMAIL")( - for { - _ <- CacheService.putUserADM(user) - retrievedUser <- CacheService.getUserADM(UserIdentifierADM(maybeEmail = Some(user.email))) - } yield assert(retrievedUser)(equalTo(Some(user))) - ) @@ TestAspect.ignore + } @@ TestAspect.ignore, + test("successfully store a user and retrieve by USERNAME")( + for { + _ <- CacheService.putUserADM(user) + retrievedUser <- CacheService.getUserADM(UserIdentifierADM(maybeUsername = Some(user.username))) + } yield assert(retrievedUser)(equalTo(Some(user))) + ) @@ TestAspect.ignore, + test("successfully store a user and retrieve by EMAIL")( + for { + _ <- CacheService.putUserADM(user) + retrievedUser <- CacheService.getUserADM(UserIdentifierADM(maybeEmail = Some(user.email))) + } yield assert(retrievedUser)(equalTo(Some(user))) + ) @@ TestAspect.ignore ) val projectTests = suite("CacheRedisImplSpec - project")( test("successfully store a project and retrieve by IRI")( for { - _ <- CacheService.putProjectADM(project) - retrievedProject <- CacheService.getProjectADM(ProjectIdentifierADM(maybeIri = Some(project.id))) + _ <- CacheService.putProjectADM(project) + retrievedProject <- CacheService.getProjectADM( + IriIdentifier + .fromString(project.id) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) + ) + } yield assert(retrievedProject)(equalTo(Some(project))) + ), + test("successfully store a project and retrieve by SHORTCODE")( + for { + _ <- CacheService.putProjectADM(project) + retrievedProject <- + CacheService.getProjectADM( + ShortcodeIdentifier + .fromString(project.shortcode) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) + ) + } yield assert(retrievedProject)(equalTo(Some(project))) + ), + test("successfully store a project and retrieve by SHORTNAME")( + for { + _ <- CacheService.putProjectADM(project) + retrievedProject <- + CacheService.getProjectADM( + ShortnameIdentifier + .fromString(project.shortname) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) + ) + } yield assert(retrievedProject)(equalTo(Some(project))) + ), + test("successfully store a project and retrieve by UUID")( + for { + _ <- CacheService.putProjectADM(project) + retrievedProject <- + CacheService.getProjectADM( + UuidIdentifier + .fromString(V2UuidValidation.getUuidFromIri(project.id)) + .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) + ) } yield assert(retrievedProject)(equalTo(Some(project))) - ) + - test("successfully store a project and retrieve by SHORTCODE")( - for { - _ <- CacheService.putProjectADM(project) - retrievedProject <- - CacheService.getProjectADM(ProjectIdentifierADM(maybeShortcode = Some(project.shortcode))) - } yield assert(retrievedProject)(equalTo(Some(project))) - ) + - test("successfully store a project and retrieve by SHORTNAME")( - for { - _ <- CacheService.putProjectADM(project) - retrievedProject <- - CacheService.getProjectADM(ProjectIdentifierADM(maybeShortname = Some(project.shortname))) - } yield assert(retrievedProject)(equalTo(Some(project))) - ) + ) ) }