diff --git a/docs/03-apis/api-admin/groups.md b/docs/03-apis/api-admin/groups.md index 7a0848f252..23e1c755d6 100644 --- a/docs/03-apis/api-admin/groups.md +++ b/docs/03-apis/api-admin/groups.md @@ -42,7 +42,7 @@ License along with DSP. If not, see . - Required permission: SystemAdmin / hasProjectAllAdminPermission / hasProjectAllGroupAdminPermission - Required information: name (unique inside project), project IRI -- Optional information: group description +- Optional information: group descriptions - Returns information about the newly created group - TypeScript Docs: groupFormats - CreateGroupApiRequestV1 - POST: `/admin/groups` @@ -51,7 +51,10 @@ License along with DSP. If not, see . ```json { "name": "NewGroup", - "description": "NewGroupDescription", + "descriptions": [ + {"value": "NewGroupDescription", "language": "en"}, + {"value": "NeueGruppenBeschreibung", "language": "de"} + ], "project": "http://rdfh.ch/projects/00FF", "status": true, "selfjoin": false @@ -65,7 +68,7 @@ specified by the `id` in the request body as below: { "id": "http://rdfh.ch/groups/00FF/a95UWs71KUklnFOe1rcw1w", "name": "GroupWithCustomIRI", - "description": "A new group with a custom IRI", + "descriptions": [{"value": "A new group with a custom IRI", "language": "en"}], "project": "http://rdfh.ch/projects/00FF", "status": true, "selfjoin": false @@ -77,7 +80,7 @@ specified by the `id` in the request body as below: - Required permission: SystemAdmin / hasProjectAllAdminPermission / hasProjectAllGroupAdminPermission / hasProjectRestrictedGroupAdminPermission (for this group) -- Changeable information: `name`, `description`, `selfjoin` +- Changeable information: `name`, `descriptions`, `selfjoin` - TypeScript Docs: groupFormats - ChangeGroupApiRequestADM - PUT: `/admin/groups/` - BODY: @@ -85,7 +88,7 @@ hasProjectRestrictedGroupAdminPermission (for this group) ```json { "name": "UpdatedGroupName", - "description": "UpdatedGroupDescription", + "descriptions": [{"value": "UpdatedGroupDescription", "language": "en"}], "selfjoin": false } ``` @@ -117,7 +120,7 @@ Example Group Information stored in admin named graph: : rdf:type knora-admin:UserGroup ; knora-admin:groupName "Name of the group" ; - knora-admin:groupDescriptions "A description of the group" ; + knora-admin:groupDescriptions "A description of the group"@en ; knora-admin:belongsToProject ; knora-admin:status "true"^^xsd:boolean ; knora-admin:hasSelfJoinEnabled "false"^^xsd:boolean . diff --git a/knora-ontologies/knora-admin.ttl b/knora-ontologies/knora-admin.ttl index d030c16837..99cf35707f 100644 --- a/knora-ontologies/knora-admin.ttl +++ b/knora-ontologies/knora-admin.ttl @@ -569,7 +569,7 @@ ] , [ rdf:type owl:Restriction ; owl:onProperty :groupDescriptions ; - owl:maxCardinality "1"^^xsd:nonNegativeInteger + owl:minCardinality "1"^^xsd:nonNegativeInteger ] , [ rdf:type owl:Restriction ; owl:onProperty :status ; diff --git a/knora-ontologies/knora-base.ttl b/knora-ontologies/knora-base.ttl index 10f06620f6..89720f556b 100644 --- a/knora-ontologies/knora-base.ttl +++ b/knora-ontologies/knora-base.ttl @@ -33,7 +33,7 @@ :attachedToProject knora-admin:SystemProject ; - :ontologyVersion "knora-base v12" . + :ontologyVersion "knora-base v13" . diff --git a/test_data/all_data/admin-data.ttl b/test_data/all_data/admin-data.ttl index c07a58f042..dccd501131 100644 --- a/test_data/all_data/admin-data.ttl +++ b/test_data/all_data/admin-data.ttl @@ -204,7 +204,7 @@ knora-admin:groupName "Image reviewer"^^xsd:string ; - knora-admin:groupDescriptions "A group for image reviewers."^^xsd:string ; + knora-admin:groupDescriptions "A group for image reviewers."@en ; knora-admin:belongsToProject ; @@ -433,7 +433,7 @@ Die Internetpublikation macht das digitalisierte Korpus dieser Frühdrucke durc rdf:type knora-admin:UserGroup ; knora-admin:groupName "Thing searcher"^^xsd:string ; - knora-admin:groupDescriptions "A group for thing searchers."^^xsd:string ; + knora-admin:groupDescriptions "A group for thing searchers."@en ; knora-admin:belongsToProject ; knora-admin:status "true"^^xsd:boolean ; knora-admin:hasSelfJoinEnabled "true"^^xsd:boolean . diff --git a/test_data/other.v1.DrawingsGodsV1Spec/drawings-gods_admin-data.ttl b/test_data/other.v1.DrawingsGodsV1Spec/drawings-gods_admin-data.ttl index 991a0a1abd..dbff2ee0ba 100644 --- a/test_data/other.v1.DrawingsGodsV1Spec/drawings-gods_admin-data.ttl +++ b/test_data/other.v1.DrawingsGodsV1Spec/drawings-gods_admin-data.ttl @@ -20,28 +20,28 @@ rdf:type knora-admin:UserGroup ; knora-admin:groupName "Meta-annotators"^^xsd:string ; - knora-admin:groupDescriptions "A group of users allowed to annotate data. Does not upload images nor files. Does not access to personal data."^^xsd:string ; + knora-admin:groupDescriptions "A group of users allowed to annotate data. Does not upload images nor files. Does not access to personal data."@en ; knora-admin:belongsToProject ; knora-admin:status "true"^^xsd:boolean ; knora-admin:hasSelfJoinEnabled "false"^^xsd:boolean . rdf:type knora-admin:UserGroup ; knora-admin:groupName "Drawings contributors"^^xsd:string ; - knora-admin:groupDescriptions "A group of users allowed to upload images, files and annotate data. Does not access to personal data."^^xsd:string ; + knora-admin:groupDescriptions "A group of users allowed to upload images, files and annotate data. Does not access to personal data."@en ; knora-admin:belongsToProject ; knora-admin:status "true"^^xsd:boolean ; knora-admin:hasSelfJoinEnabled "false"^^xsd:boolean . rdf:type knora-admin:UserGroup ; knora-admin:groupName "SNF team"^^xsd:string ; - knora-admin:groupDescriptions "A core group of members from the SNF project. Access to any data, including sensitive."^^xsd:string ; + knora-admin:groupDescriptions "A core group of members from the SNF project. Access to any data, including sensitive."@en ; knora-admin:belongsToProject ; knora-admin:status "true"^^xsd:boolean ; knora-admin:hasSelfJoinEnabled "false"^^xsd:boolean . rdf:type knora-admin:UserGroup ; knora-admin:groupName "Administrators"^^xsd:string ; - knora-admin:groupDescriptions "A custom admin group created to apply permission precedence rules. Replaces the built-in knora-admin:ProjectAdmin group, not used for this project."^^xsd:string ; + knora-admin:groupDescriptions "A custom admin group created to apply permission precedence rules. Replaces the built-in knora-admin:ProjectAdmin group, not used for this project."@en ; knora-admin:belongsToProject ; knora-admin:status "true"^^xsd:boolean ; knora-admin:hasSelfJoinEnabled "false"^^xsd:boolean . diff --git a/test_data/other.v2.LumieresLausanneV2E2ESpec/lumieres-lausanne_admin.ttl b/test_data/other.v2.LumieresLausanneV2E2ESpec/lumieres-lausanne_admin.ttl index e2a43c3ffb..42086c3d4d 100644 --- a/test_data/other.v2.LumieresLausanneV2E2ESpec/lumieres-lausanne_admin.ttl +++ b/test_data/other.v2.LumieresLausanneV2E2ESpec/lumieres-lausanne_admin.ttl @@ -25,42 +25,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."""^^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: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."""^^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: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."^^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: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."^^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: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."^^xsd:string ; + knora-admin:groupDescriptions "Béla Kapossy, Béatrice Lovis."@fr ; 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."^^xsd:string ; + knora-admin:groupDescriptions "Béatrice Lovis."@fr ; knora-admin:belongsToProject ; knora-admin:status "true"^^xsd:boolean ; knora-admin:hasSelfJoinEnabled "false"^^xsd:boolean . diff --git a/test_data/upgrade/BUILD.bazel b/test_data/upgrade/BUILD.bazel index f32844866a..d2d7311255 100644 --- a/test_data/upgrade/BUILD.bazel +++ b/test_data/upgrade/BUILD.bazel @@ -9,5 +9,6 @@ filegroup( "pr1372.trig", "pr1615.trig", "pr1746.trig", + "pr1921.trig", ], ) diff --git a/test_data/upgrade/pr1921.trig b/test_data/upgrade/pr1921.trig new file mode 100644 index 0000000000..f8d7a119e8 --- /dev/null +++ b/test_data/upgrade/pr1921.trig @@ -0,0 +1,55 @@ +@prefix xsd: . +@prefix rdf: . +@prefix knora-admin: . + + a knora-admin:knoraProject ; + knora-admin:projectLongname "Test Project"^^xsd:string ; + knora-admin:projectShortname "test-project"^^xsd:string ; + knora-admin:projectShortcode "0105"^^xsd:string ; + knora-admin:projectDescription "Project description"^^xsd:string ; + knora-admin:projectKeywords "Keyword"^^xsd:string ; + knora-admin:status "true"^^xsd:boolean ; + knora-admin:hasSelfJoinEnabled "false"^^xsd:boolean . + + rdf:type knora-admin:UserGroup ; + knora-admin:groupName "Group without language string 1"^^xsd:string ; + knora-admin:groupDescriptions "A group description without language attribute."^^xsd:string ; + knora-admin:belongsToProject ; + knora-admin:status "true"^^xsd:boolean ; + knora-admin:hasSelfJoinEnabled "false"^^xsd:boolean . + + rdf:type knora-admin:UserGroup ; + knora-admin:groupName "Group without language string 2"^^xsd:string ; + knora-admin:groupDescriptions "A group description without language attribute." ; + knora-admin:belongsToProject ; + knora-admin:status "true"^^xsd:boolean ; + knora-admin:hasSelfJoinEnabled "false"^^xsd:boolean . + + rdf:type knora-admin:UserGroup ; + knora-admin:groupName "Group without language string 3"^^xsd:string ; + knora-admin:groupDescription "A group description with old predicate name and without language attribute."^^xsd:string ; + knora-admin:belongsToProject ; + knora-admin:status "true"^^xsd:boolean ; + knora-admin:hasSelfJoinEnabled "false"^^xsd:boolean . + + rdf:type knora-admin:UserGroup ; + knora-admin:groupName "Group without language string 4"^^xsd:string ; + knora-admin:groupDescription "A group description with old predicate name and without language attribute." ; + knora-admin:belongsToProject ; + knora-admin:status "true"^^xsd:boolean ; + knora-admin:hasSelfJoinEnabled "false"^^xsd:boolean . + + rdf:type knora-admin:UserGroup ; + knora-admin:groupName "Group with language string"^^xsd:string ; + knora-admin:groupDescriptions "Eine Gruppe mit Sprachattribut."@de ; + knora-admin:belongsToProject ; + knora-admin:status "true"^^xsd:boolean ; + knora-admin:hasSelfJoinEnabled "false"^^xsd:boolean . + + rdf:type knora-admin:UserGroup ; + knora-admin:groupName "Group with language string"^^xsd:string ; + knora-admin:groupDescriptions "A group with language attribute."@en ; + knora-admin:belongsToProject ; + knora-admin:status "true"^^xsd:boolean ; + knora-admin:hasSelfJoinEnabled "false"^^xsd:boolean . + diff --git a/webapi/src/main/scala/org/knora/webapi/package.scala b/webapi/src/main/scala/org/knora/webapi/package.scala index 92ea6e889f..f76b10ca51 100644 --- a/webapi/src/main/scala/org/knora/webapi/package.scala +++ b/webapi/src/main/scala/org/knora/webapi/package.scala @@ -25,7 +25,7 @@ package object webapi { * The version of `knora-base` and of the other built-in ontologies that this version of Knora requires. * Must be the same as the object of `knora-base:ontologyVersion` in the `knora-base` ontology being used. */ - val KnoraBaseVersion: String = "knora-base v12" + val KnoraBaseVersion: String = "knora-base v13" /** * `IRI` is a synonym for `String`, used to improve code readability. diff --git a/webapi/src/main/scala/org/knora/webapi/store/triplestore/upgrade/RepositoryUpdatePlan.scala b/webapi/src/main/scala/org/knora/webapi/store/triplestore/upgrade/RepositoryUpdatePlan.scala index fade4726e9..b1b8781b2a 100644 --- a/webapi/src/main/scala/org/knora/webapi/store/triplestore/upgrade/RepositoryUpdatePlan.scala +++ b/webapi/src/main/scala/org/knora/webapi/store/triplestore/upgrade/RepositoryUpdatePlan.scala @@ -43,7 +43,11 @@ object RepositoryUpdatePlan { PluginForKnoraBaseVersion(versionNumber = 9, plugin = new UpgradePluginPR1746(featureFactoryConfig, log)), PluginForKnoraBaseVersion(versionNumber = 10, plugin = new NoopPlugin), // PR 1808 PluginForKnoraBaseVersion(versionNumber = 11, plugin = new NoopPlugin), // PR 1813 - PluginForKnoraBaseVersion(versionNumber = 12, plugin = new NoopPlugin) // PR 1891 + PluginForKnoraBaseVersion(versionNumber = 12, plugin = new NoopPlugin), // PR 1891 + PluginForKnoraBaseVersion( + versionNumber = 13, + plugin = new UpgradePluginPR1921(featureFactoryConfig, log) + ) // PR 1921 ) /** diff --git a/webapi/src/main/scala/org/knora/webapi/store/triplestore/upgrade/plugins/UpgradePluginPR1921.scala b/webapi/src/main/scala/org/knora/webapi/store/triplestore/upgrade/plugins/UpgradePluginPR1921.scala new file mode 100644 index 0000000000..b8d4d2a4f2 --- /dev/null +++ b/webapi/src/main/scala/org/knora/webapi/store/triplestore/upgrade/plugins/UpgradePluginPR1921.scala @@ -0,0 +1,113 @@ +/* + * Copyright © 2015-2021 Data and Service Center for the Humanities (DaSCH) + * + * This file is part of Knora. + * + * Knora is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Knora is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with Knora. If not, see . + */ + +package org.knora.webapi.store.triplestore.upgrade.plugins + +import com.typesafe.scalalogging.Logger +import org.knora.webapi.feature.FeatureFactoryConfig +import org.knora.webapi.messages.store.triplestoremessages.StringLiteralV2 +import org.knora.webapi.messages.util.rdf._ +import org.knora.webapi.store.triplestore.upgrade.UpgradePlugin + +/** + * Transforms a repository for Knora PR 1921. + */ +class UpgradePluginPR1921(featureFactoryConfig: FeatureFactoryConfig, log: Logger) extends UpgradePlugin { + private val nodeFactory: RdfNodeFactory = RdfFeatureFactory.getRdfNodeFactory(featureFactoryConfig) + // Group descriptions without language attribute get language attribute defined in DEFAULT_LANG + private val DEFAULT_LANG = "en" + + override def transform(model: RdfModel): Unit = { + val statementsToRemove: collection.mutable.Set[Statement] = collection.mutable.Set.empty + val statementsToAdd: collection.mutable.Set[Statement] = collection.mutable.Set.empty + + val newPredicateLabel: IriNode = + nodeFactory.makeIriNode("http://www.knora.org/ontology/knora-admin#groupDescriptions") + + def updateGroupDescription(statement: Statement, languageTag: Option[String]): Unit = + languageTag match { + // the group description did not have a language attribute + case Some(lang) => + val groupDescriptionWithLanguage: RdfLiteral = + nodeFactory.makeStringWithLanguage(statement.obj.stringValue, lang) + + statementsToRemove += statement + + statementsToAdd += nodeFactory.makeStatement( + subj = statement.subj, + pred = newPredicateLabel, + obj = groupDescriptionWithLanguage, + context = statement.context + ) + + log.warn( + s"Updated <${statement.subj}> <${statement.pred}> to <${newPredicateLabel.stringValue}> with <${groupDescriptionWithLanguage}>" + ) + + // the group description did already have a language attribute + case None => + statementsToRemove += statement + + statementsToAdd += nodeFactory.makeStatement( + subj = statement.subj, + pred = newPredicateLabel, + obj = statement.obj, + context = statement.context + ) + log.warn(s"Updated <${statement.pred}> to <${newPredicateLabel.stringValue}>") + } + + for (statement: Statement <- model) { + statement.pred match { + case predicate: IriNode => + if (predicate.stringValue == "http://www.knora.org/ontology/knora-admin#groupDescriptions") { + statement.obj match { + case stringWithLanguage: StringWithLanguage => + () + case stringWithLanguage: StringLiteralV2 => + () + case _ => + updateGroupDescription( + statement = statement, + languageTag = Some(DEFAULT_LANG) + ) + } + } + + if (predicate.stringValue == "http://www.knora.org/ontology/knora-admin#groupDescription") { + statement.obj match { + case stringWithLanguage: StringWithLanguage => + updateGroupDescription(statement, None) + case stringWithLanguage: StringLiteralV2 => + updateGroupDescription(statement, None) + case _ => + updateGroupDescription( + statement = statement, + languageTag = Some(DEFAULT_LANG) + ) + } + } + case _ => () + } + } + + model.removeStatements(statementsToRemove.toSet) + model.addStatements(statementsToAdd.toSet) + } +} 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 43d420e21e..d4bc3b078e 100644 --- a/webapi/src/test/scala/org/knora/webapi/sharedtestdata/SharedTestDataADM.scala +++ b/webapi/src/test/scala/org/knora/webapi/sharedtestdata/SharedTestDataADM.scala @@ -347,7 +347,7 @@ object SharedTestDataADM { def imagesReviewerGroup: GroupADM = GroupADM( id = "http://rdfh.ch/groups/00FF/images-reviewer", name = "Image reviewer", - descriptions = Seq(StringLiteralV2(value = "A group for image reviewers.", language = None)), + descriptions = Seq(StringLiteralV2(value = "A group for image reviewers.", language = Some("en"))), project = imagesProject, status = true, selfjoin = false diff --git a/webapi/src/test/scala/org/knora/webapi/store/triplestore/upgrade/plugins/BUILD.bazel b/webapi/src/test/scala/org/knora/webapi/store/triplestore/upgrade/plugins/BUILD.bazel index 8aab125c43..3389f28eb1 100644 --- a/webapi/src/test/scala/org/knora/webapi/store/triplestore/upgrade/plugins/BUILD.bazel +++ b/webapi/src/test/scala/org/knora/webapi/store/triplestore/upgrade/plugins/BUILD.bazel @@ -122,3 +122,22 @@ scala_test( "//webapi:test_library", ] + BASE_TEST_DEPENDENCIES, ) + +scala_test( + name = "UpgradePluginPR1921Spec", + size = "small", + srcs = [ + "UpgradePluginPR1921Spec.scala", + "UpgradePluginSpec.scala", + ], + data = [ + "//knora-ontologies", + "//test_data", + "//test_data/upgrade", + ], + jvm_flags = ["-Dconfig.resource=fuseki.conf"], + deps = ALL_WEBAPI_MAIN_DEPENDENCIES + [ + "//webapi:main_library", + "//webapi:test_library", + ] + BASE_TEST_DEPENDENCIES, +) diff --git a/webapi/src/test/scala/org/knora/webapi/store/triplestore/upgrade/plugins/UpgradePluginPR1921Spec.scala b/webapi/src/test/scala/org/knora/webapi/store/triplestore/upgrade/plugins/UpgradePluginPR1921Spec.scala new file mode 100644 index 0000000000..a4e4b2edb5 --- /dev/null +++ b/webapi/src/test/scala/org/knora/webapi/store/triplestore/upgrade/plugins/UpgradePluginPR1921Spec.scala @@ -0,0 +1,113 @@ +/* + * Copyright © 2015-2021 Data and Service Center for the Humanities (DaSCH) + * + * This file is part of Knora. + * + * Knora is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Knora is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with Knora. If not, see . + */ + +package org.knora.webapi.store.triplestore.upgrade.plugins + +import com.typesafe.scalalogging.LazyLogging +import org.knora.webapi.exceptions.AssertionException +import org.knora.webapi.messages.util.rdf._ + +class UpgradePluginPR1921Spec extends UpgradePluginSpec with LazyLogging { + private val nodeFactory: RdfNodeFactory = RdfFeatureFactory.getRdfNodeFactory(defaultFeatureFactoryConfig) + + private def checkLiteral(model: RdfModel, subj: IriNode, pred: IriNode, expectedObj: RdfLiteral): Unit = + model + .find( + subj = Some(subj), + pred = Some(pred), + obj = None + ) + .toSet + .headOption match { + case Some(statement: Statement) => + statement.obj match { + case rdfLiteral: RdfLiteral => assert(rdfLiteral == expectedObj) + case other => throw AssertionException(s"Unexpected object for $pred: $other") + } + + case None => throw AssertionException(s"No statement found with subject $subj and predicate $pred") + } + + "Upgrade plugin PR921" should { + // Parse the input file. + val model: RdfModel = trigFileToModel("test_data/upgrade/pr1921.trig") + // Use the plugin to transform the input. + val plugin = new UpgradePluginPR1921(defaultFeatureFactoryConfig, logger) + plugin.transform(model) + + "replace simple strings in group descriptions with language strings" in { + // Check that a group description without language attribute gets a language attribute. String is marked as string. + checkLiteral( + model = model, + subj = nodeFactory.makeIriNode("http://rdfh.ch/groups/0105/group-without-language-attribute-1"), + pred = nodeFactory.makeIriNode("http://www.knora.org/ontology/knora-admin#groupDescriptions"), + expectedObj = + nodeFactory.makeStringWithLanguage("A group description without language attribute.", language = "en") + ) + + // Check that a group description without language attribute gets a language attribute. String is not marked as string. + checkLiteral( + model = model, + subj = nodeFactory.makeIriNode("http://rdfh.ch/groups/0105/group-without-language-attribute-2"), + pred = nodeFactory.makeIriNode("http://www.knora.org/ontology/knora-admin#groupDescriptions"), + expectedObj = + nodeFactory.makeStringWithLanguage("A group description without language attribute.", language = "en") + ) + + // Check that a group description with old predicate name and without language attribute gets a language attribute. String is marked as string. + checkLiteral( + model = model, + subj = nodeFactory.makeIriNode("http://rdfh.ch/groups/0105/group-without-language-attribute-3"), + pred = nodeFactory.makeIriNode("http://www.knora.org/ontology/knora-admin#groupDescriptions"), + expectedObj = nodeFactory.makeStringWithLanguage( + "A group description with old predicate name and without language attribute.", + language = "en" + ) + ) + + // Check that a group description with old predicate name and without language attribute gets a language attribute. String is not marked as string. + checkLiteral( + model = model, + subj = nodeFactory.makeIriNode("http://rdfh.ch/groups/0105/group-without-language-attribute-4"), + pred = nodeFactory.makeIriNode("http://www.knora.org/ontology/knora-admin#groupDescriptions"), + expectedObj = nodeFactory.makeStringWithLanguage( + "A group description with old predicate name and without language attribute.", + language = "en" + ) + ) + } + "not change group descriptions which have language attributes" in { + // Check that a group description with a language attribute is not changed. + checkLiteral( + model = model, + subj = nodeFactory.makeIriNode("http://rdfh.ch/groups/0105/group-with-language-attribute-de"), + pred = nodeFactory.makeIriNode("http://www.knora.org/ontology/knora-admin#groupDescriptions"), + expectedObj = nodeFactory.makeStringWithLanguage(value = "Eine Gruppe mit Sprachattribut.", language = "de") + ) + + // Check that a group description with default language attribute is not changed. + checkLiteral( + model = model, + subj = nodeFactory.makeIriNode("http://rdfh.ch/groups/0105/group-with-language-attribute-en"), + pred = nodeFactory.makeIriNode("http://www.knora.org/ontology/knora-admin#groupDescriptions"), + expectedObj = nodeFactory.makeStringWithLanguage(value = "A group with language attribute.", language = "en") + ) + } + } +}