From 382826ff576ca92870500d659ad0c766b0bffb0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Kleinb=C3=B6lting?= Date: Wed, 2 Oct 2024 21:41:04 +0200 Subject: [PATCH] refactor: Simplify Value create code and use ProjectIri instead of String (#3378) --- .../admin/PermissionsResponderSpec.scala | 165 +++++++-------- .../v2/OntologyResponderV2Spec.scala | 1 - .../admin/PermissionsResponder.scala | 192 ++++++++---------- .../responders/v2/ValuesResponderV2.scala | 17 +- .../resources/CreateResourceV2Handler.scala | 84 ++------ 5 files changed, 189 insertions(+), 270 deletions(-) diff --git a/integration/src/test/scala/org/knora/webapi/responders/admin/PermissionsResponderSpec.scala b/integration/src/test/scala/org/knora/webapi/responders/admin/PermissionsResponderSpec.scala index 0ca35956b3..92b51bad0a 100644 --- a/integration/src/test/scala/org/knora/webapi/responders/admin/PermissionsResponderSpec.scala +++ b/integration/src/test/scala/org/knora/webapi/responders/admin/PermissionsResponderSpec.scala @@ -526,7 +526,7 @@ class PermissionsResponderSpec extends CoreSpec with ImplicitSender { "return the default object access permissions 'string' for the 'knora-base:LinkObj' resource class (system resource class)" in { val actual = UnsafeZioRun.runOrThrow( permissionsResponder( - _.getDefaultResourcePermissions( + _.newResourceDefaultObjectAccessPermissions( ProjectIri.unsafeFrom(SharedTestDataADM.incunabulaProjectIri), OntologyConstants.KnoraBase.LinkObj.toSmartIri, SharedTestDataADM.incunabulaProjectAdminUser, @@ -541,26 +541,29 @@ class PermissionsResponderSpec extends CoreSpec with ImplicitSender { } "return the default object access permissions 'string' for the 'knora-base:hasStillImageFileValue' property (system property)" in { - UnsafeZioRun + val actual = UnsafeZioRun .runOrThrow( permissionsResponder( - _.getDefaultValuePermissions( - projectIri = SharedTestDataADM.incunabulaProjectIri, - resourceClassIri = stringFormatter.toSmartIri(OntologyConstants.KnoraBase.StillImageRepresentation), - propertyIri = stringFormatter.toSmartIri(OntologyConstants.KnoraBase.HasStillImageFileValue), - targetUser = SharedTestDataADM.incunabulaProjectAdminUser, + _.newValueDefaultObjectAccessPermissions( + ProjectIri.unsafeFrom(SharedTestDataADM.incunabulaProjectIri), + stringFormatter.toSmartIri(OntologyConstants.KnoraBase.StillImageRepresentation), + stringFormatter.toSmartIri(OntologyConstants.KnoraBase.HasStillImageFileValue), + SharedTestDataADM.incunabulaProjectAdminUser, ), ), ) - .shouldEqual( + + assert( + actual == DefaultObjectAccessPermissionsStringResponseADM( "M knora-admin:Creator,knora-admin:ProjectMember|V knora-admin:KnownUser,knora-admin:UnknownUser", - ) + ), + ) } "return the default object access permissions 'string' for the 'incunabula:book' resource class (project resource class)" in { val actual = UnsafeZioRun.runOrThrow( permissionsResponder( - _.getDefaultResourcePermissions( + _.newResourceDefaultObjectAccessPermissions( ProjectIri.unsafeFrom(SharedTestDataADM.incunabulaProjectIri), SharedOntologyTestDataADM.INCUNABULA_BOOK_RESOURCE_CLASS.toSmartIri, SharedTestDataADM.incunabulaProjectAdminUser, @@ -577,7 +580,7 @@ class PermissionsResponderSpec extends CoreSpec with ImplicitSender { "return the default object access permissions 'string' for the 'incunabula:page' resource class (project resource class)" in { val actual = UnsafeZioRun.runOrThrow( permissionsResponder( - _.getDefaultResourcePermissions( + _.newResourceDefaultObjectAccessPermissions( ProjectIri.unsafeFrom(SharedTestDataADM.incunabulaProjectIri), SharedOntologyTestDataADM.INCUNABULA_PAGE_RESOURCE_CLASS.toSmartIri, SharedTestDataADM.incunabulaProjectAdminUser, @@ -592,26 +595,28 @@ class PermissionsResponderSpec extends CoreSpec with ImplicitSender { } "return the default object access permissions 'string' for the 'anything:hasInterval' property" in { - UnsafeZioRun - .runOrThrow( - permissionsResponder( - _.getDefaultValuePermissions( - projectIri = SharedTestDataADM.anythingProjectIri, - resourceClassIri = stringFormatter.toSmartIri("http://www.knora.org/ontology/0001/anything#Thing"), - propertyIri = stringFormatter.toSmartIri("http://www.knora.org/ontology/0001/anything#hasInterval"), - targetUser = SharedTestDataADM.anythingUser2, - ), + val actual = UnsafeZioRun.runOrThrow( + permissionsResponder( + _.newValueDefaultObjectAccessPermissions( + ProjectIri.unsafeFrom(SharedTestDataADM.anythingProjectIri), + stringFormatter.toSmartIri("http://www.knora.org/ontology/0001/anything#Thing"), + stringFormatter.toSmartIri("http://www.knora.org/ontology/0001/anything#hasInterval"), + SharedTestDataADM.anythingUser2, ), - ) - .shouldEqual( + ), + ) + + assert( + actual == DefaultObjectAccessPermissionsStringResponseADM( "CR knora-admin:Creator|M knora-admin:ProjectMember|V knora-admin:KnownUser|RV knora-admin:UnknownUser", - ) + ), + ) } "return the default object access permissions 'string' for the 'anything:Thing' class" in { val actual = UnsafeZioRun.runOrThrow( permissionsResponder( - _.getDefaultResourcePermissions( + _.newResourceDefaultObjectAccessPermissions( ProjectIri.unsafeFrom(SharedTestDataADM.anythingProjectIri), "http://www.knora.org/ontology/0001/anything#Thing".toSmartIri, SharedTestDataADM.anythingUser2, @@ -626,102 +631,90 @@ class PermissionsResponderSpec extends CoreSpec with ImplicitSender { } "return the default object access permissions 'string' for the 'anything:Thing' class and 'anything:hasText' property" in { - UnsafeZioRun + val actual = UnsafeZioRun .runOrThrow( permissionsResponder( - _.getDefaultValuePermissions( - projectIri = SharedTestDataADM.anythingProjectIri, + _.newValueDefaultObjectAccessPermissions( + projectIri = ProjectIri.unsafeFrom(SharedTestDataADM.anythingProjectIri), resourceClassIri = stringFormatter.toSmartIri("http://www.knora.org/ontology/0001/anything#Thing"), propertyIri = stringFormatter.toSmartIri("http://www.knora.org/ontology/0001/anything#hasText"), targetUser = SharedTestDataADM.anythingUser1, ), ), ) - .shouldEqual("CR knora-admin:Creator") + actual.permissionLiteral shouldEqual "CR knora-admin:Creator" } "return the default object access permissions 'string' for the 'images:Bild' class and 'anything:hasText' property" in { - UnsafeZioRun + val actual = UnsafeZioRun .runOrThrow( permissionsResponder( - _.getDefaultValuePermissions( - projectIri = SharedTestDataADM.anythingProjectIri, - resourceClassIri = stringFormatter.toSmartIri(s"${SharedOntologyTestDataADM.IMAGES_ONTOLOGY_IRI}#bild"), - propertyIri = stringFormatter.toSmartIri("http://www.knora.org/ontology/0001/anything#hasText"), - targetUser = SharedTestDataADM.anythingUser2, + _.newValueDefaultObjectAccessPermissions( + ProjectIri.unsafeFrom(SharedTestDataADM.anythingProjectIri), + stringFormatter.toSmartIri(s"${SharedOntologyTestDataADM.IMAGES_ONTOLOGY_IRI}#bild"), + stringFormatter.toSmartIri("http://www.knora.org/ontology/0001/anything#hasText"), + SharedTestDataADM.anythingUser2, ), ), ) - .shouldEqual( - "CR knora-admin:Creator|M knora-admin:ProjectMember|V knora-admin:KnownUser|RV knora-admin:UnknownUser", - ) - } - "return 'BadRequest' if the supplied project IRI DefaultObjectAccessPermissionsStringForPropertyGetADM is not valid" in { - val projectIri = "" - UnsafeZioRun - .runOrThrow( - permissionsResponder( - _.getDefaultValuePermissions( - projectIri = projectIri, - resourceClassIri = stringFormatter.toSmartIri(SharedOntologyTestDataADM.IMAGES_BILD_RESOURCE_CLASS), - propertyIri = stringFormatter.toSmartIri(SharedOntologyTestDataADM.IMAGES_TITEL_PROPERTY), - targetUser = SharedTestDataADM.imagesUser02, - ), - ).flip.map(_.getMessage), - ) - .shouldEqual(s"Invalid project IRI $projectIri") + assert( + actual == DefaultObjectAccessPermissionsStringResponseADM( + "CR knora-admin:Creator|M knora-admin:ProjectMember|V knora-admin:KnownUser|RV knora-admin:UnknownUser", + ), + ) } "return 'BadRequest' if the supplied resourceClass IRI for DefaultObjectAccessPermissionsStringForPropertyGetADM is not valid" in { - UnsafeZioRun - .runOrThrow( + val exit = UnsafeZioRun + .run( permissionsResponder( - _.getDefaultValuePermissions( - projectIri = SharedTestDataADM.imagesProjectIri, - resourceClassIri = stringFormatter.toSmartIri(SharedTestDataADM.customResourceIRI), - propertyIri = stringFormatter.toSmartIri(SharedOntologyTestDataADM.IMAGES_TITEL_PROPERTY), - targetUser = SharedTestDataADM.imagesReviewerUser, + _.newValueDefaultObjectAccessPermissions( + ProjectIri.unsafeFrom(SharedTestDataADM.imagesProjectIri), + stringFormatter.toSmartIri(SharedTestDataADM.customResourceIRI), + stringFormatter.toSmartIri(SharedOntologyTestDataADM.IMAGES_TITEL_PROPERTY), + SharedTestDataADM.imagesReviewerUser, ), - ).flip.map(_.getMessage), + ), ) - .shouldEqual(s"Invalid resource class IRI: ${SharedTestDataADM.customResourceIRI}") + assertFailsWithA[BadRequestException]( + exit, + s"Invalid resource class IRI: ${SharedTestDataADM.customResourceIRI}", + ) } "return 'BadRequest' if the supplied property IRI for DefaultObjectAccessPermissionsStringForPropertyGetADM is not valid" in { - UnsafeZioRun - .runOrThrow( - permissionsResponder( - _.getDefaultValuePermissions( - projectIri = SharedTestDataADM.imagesProjectIri, - resourceClassIri = stringFormatter.toSmartIri(SharedOntologyTestDataADM.IMAGES_BILD_RESOURCE_CLASS), - propertyIri = stringFormatter.toSmartIri(SharedTestDataADM.customValueIRI), - targetUser = SharedTestDataADM.imagesReviewerUser, - ), - ).flip.map(_.getMessage), - ) - .shouldEqual(s"Invalid property IRI: ${SharedTestDataADM.customValueIRI}") + val exit = UnsafeZioRun.run( + permissionsResponder( + _.newValueDefaultObjectAccessPermissions( + ProjectIri.unsafeFrom(SharedTestDataADM.imagesProjectIri), + stringFormatter.toSmartIri(SharedOntologyTestDataADM.IMAGES_BILD_RESOURCE_CLASS), + stringFormatter.toSmartIri(SharedTestDataADM.customValueIRI), + SharedTestDataADM.imagesReviewerUser, + ), + ), + ) + assertFailsWithA[BadRequestException](exit, s"Invalid property IRI: ${SharedTestDataADM.customValueIRI}") } "return 'BadRequest' if the target user of DefaultObjectAccessPermissionsStringForPropertyGetADM is an Anonymous user" in { - UnsafeZioRun - .runOrThrow( - permissionsResponder( - _.getDefaultValuePermissions( - projectIri = SharedTestDataADM.imagesProjectIri, - resourceClassIri = stringFormatter.toSmartIri(SharedOntologyTestDataADM.IMAGES_BILD_RESOURCE_CLASS), - propertyIri = stringFormatter.toSmartIri(SharedOntologyTestDataADM.IMAGES_TITEL_PROPERTY), - targetUser = SharedTestDataADM.anonymousUser, - ), - ).flip.map(_.getMessage), - ) - .shouldEqual("Anonymous Users are not allowed.") + val exit = UnsafeZioRun.run( + permissionsResponder( + _.newValueDefaultObjectAccessPermissions( + ProjectIri.unsafeFrom(SharedTestDataADM.imagesProjectIri), + stringFormatter.toSmartIri(SharedOntologyTestDataADM.IMAGES_BILD_RESOURCE_CLASS), + stringFormatter.toSmartIri(SharedOntologyTestDataADM.IMAGES_TITEL_PROPERTY), + SharedTestDataADM.anonymousUser, + ), + ), + ) + assertFailsWithA[BadRequestException](exit, "Anonymous Users are not allowed.") } "return the default object access permissions 'string' for the 'anything:Thing' resource class for the root user (system admin and not member of project)" in { val actual = UnsafeZioRun.runOrThrow( permissionsResponder( - _.getDefaultResourcePermissions( + _.newResourceDefaultObjectAccessPermissions( ProjectIri.unsafeFrom(SharedTestDataADM.anythingProjectIri), "http://www.knora.org/ontology/0001/anything#Thing".toSmartIri, SharedTestDataADM.rootUser, diff --git a/integration/src/test/scala/org/knora/webapi/responders/v2/OntologyResponderV2Spec.scala b/integration/src/test/scala/org/knora/webapi/responders/v2/OntologyResponderV2Spec.scala index 33359d99c3..a5cb1fe28c 100644 --- a/integration/src/test/scala/org/knora/webapi/responders/v2/OntologyResponderV2Spec.scala +++ b/integration/src/test/scala/org/knora/webapi/responders/v2/OntologyResponderV2Spec.scala @@ -8,7 +8,6 @@ package org.knora.webapi.responders.v2 import org.apache.pekko.actor.Status.Failure import org.apache.pekko.pattern.ask import org.apache.pekko.testkit.ImplicitSender -import org.scalatest.Assertion import zio.ZIO import java.time.Instant diff --git a/webapi/src/main/scala/org/knora/webapi/responders/admin/PermissionsResponder.scala b/webapi/src/main/scala/org/knora/webapi/responders/admin/PermissionsResponder.scala index 7e5461e455..45bd2a80e1 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/admin/PermissionsResponder.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/admin/PermissionsResponder.scala @@ -13,7 +13,6 @@ import scala.collection.mutable.ListBuffer import dsp.errors.* import org.knora.webapi.* -import org.knora.webapi.config.AppConfig import org.knora.webapi.messages.OntologyConstants import org.knora.webapi.messages.SmartIri import org.knora.webapi.messages.StringFormatter @@ -45,20 +44,21 @@ import org.knora.webapi.store.triplestore.api.TriplestoreService.Queries.Select import org.knora.webapi.store.triplestore.api.TriplestoreService.Queries.Update final case class PermissionsResponder( - appConfig: AppConfig, - groupService: GroupService, - iriService: IriService, - knoraProjectService: KnoraProjectService, - triplestore: TriplestoreService, - auth: AuthorizationRestService, - administrativePermissionService: AdministrativePermissionService, + private val groupService: GroupService, + private val iriService: IriService, + private val knoraProjectService: KnoraProjectService, + private val triplestore: TriplestoreService, + private val auth: AuthorizationRestService, + private val administrativePermissionService: AdministrativePermissionService, )(implicit val stringFormatter: StringFormatter) extends LazyLogging { private val PERMISSIONS_GLOBAL_LOCK_IRI = "http://rdfh.ch/permissions" - /* Entity types used to more clearly distinguish what kind of entity is meant */ - private val ResourceEntityType = "resource" - private val PropertyEntityType = "property" + + private enum EntityType { + case Resource + case Property + } def getPermissionsApByProjectIri(projectIRI: IRI): Task[AdministrativePermissionsForProjectGetResponseADM] = for { @@ -305,20 +305,22 @@ final case class PermissionsResponder( * @return an optional [[DefaultObjectAccessPermissionADM]] */ private def defaultObjectAccessPermissionGetADM( - projectIri: IRI, + projectIri: ProjectIri, groupIri: Option[IRI], resourceClassIri: Option[IRI], propertyIri: Option[IRI], ): Task[Option[DefaultObjectAccessPermissionADM]] = triplestore .query( - Select(sparql.admin.txt.getDefaultObjectAccessPermission(projectIri, groupIri, resourceClassIri, propertyIri)), + Select( + sparql.admin.txt.getDefaultObjectAccessPermission(projectIri.value, groupIri, resourceClassIri, propertyIri), + ), ) .flatMap(toDefaultObjectAccessPermission(_, projectIri, groupIri, resourceClassIri, propertyIri)) private def toDefaultObjectAccessPermission( result: SparqlSelectResult, - projectIri: IRI, + projectIri: ProjectIri, groupIri: Option[IRI], resourceClassIri: Option[IRI], propertyIri: Option[IRI], @@ -332,7 +334,7 @@ final case class PermissionsResponder( val doapCount: Int = rows.groupBy(_.rowMap("s")).size if (doapCount > 1) throw InconsistentRepositoryDataException( - s"Only one default object permission instance allowed for project: $projectIri and combination of group: $groupIri, resourceClass: $resourceClassIri, property: $propertyIri combination, but found: $doapCount.", + s"Only one default object permission instance allowed for project: ${projectIri.value} and combination of group: $groupIri, resourceClass: $resourceClassIri, property: $propertyIri combination, but found: $doapCount.", ) /* get the iri of the retrieved permission */ @@ -371,7 +373,7 @@ final case class PermissionsResponder( * @param groups the list of groups for which default object access permissions are retrieved and combined. * @return a set of [[PermissionADM]]. */ - private def getDefaultObjectAccessPermissions(projectIri: IRI, groups: Seq[IRI]): Task[Set[PermissionADM]] = + private def getDefaultObjectAccessPermissions(projectIri: ProjectIri, groups: Seq[IRI]): Task[Set[PermissionADM]] = ZIO .foreach(groups) { groupIri => defaultObjectAccessPermissionGetADM(projectIri, Some(groupIri), None, None).map { @@ -389,21 +391,13 @@ final case class PermissionsResponder( * @return a set of [[PermissionADM]]. */ private def defaultObjectAccessPermissionsForResourceClassGetADM( - projectIri: IRI, + projectIri: ProjectIri, resourceClassIri: IRI, ): Task[Set[PermissionADM]] = - for { - defaultPermissionsOption <- defaultObjectAccessPermissionGetADM( - projectIri = projectIri, - groupIri = None, - resourceClassIri = Some(resourceClassIri), - propertyIri = None, - ) - defaultPermissions: Set[PermissionADM] = defaultPermissionsOption match { - case Some(doap) => doap.hasPermissions - case None => Set.empty[PermissionADM] - } - } yield defaultPermissions + defaultObjectAccessPermissionGetADM(projectIri, None, Some(resourceClassIri), None).map { + case Some(doap) => doap.hasPermissions + case None => Set.empty + } /** * Convenience method returning a set with default object access permissions defined on a resource class / property combination. @@ -414,22 +408,14 @@ final case class PermissionsResponder( * @return a set of [[PermissionADM]]. */ private def defaultObjectAccessPermissionsForResourceClassPropertyGetADM( - projectIri: IRI, + projectIri: ProjectIri, resourceClassIri: IRI, propertyIri: IRI, ): Task[Set[PermissionADM]] = - for { - defaultPermissionsOption <- defaultObjectAccessPermissionGetADM( - projectIri = projectIri, - groupIri = None, - resourceClassIri = Some(resourceClassIri), - propertyIri = Some(propertyIri), - ) - defaultPermissions: Set[PermissionADM] = defaultPermissionsOption match { - case Some(doap) => doap.hasPermissions - case None => Set.empty[PermissionADM] - } - } yield defaultPermissions + defaultObjectAccessPermissionGetADM(projectIri, None, Some(resourceClassIri), Some(propertyIri)).map { + case Some(doap) => doap.hasPermissions + case None => Set.empty[PermissionADM] + } /** * Convenience method returning a set with default object access permissions defined on a property. @@ -439,21 +425,13 @@ final case class PermissionsResponder( * @return a set of [[PermissionADM]]. */ private def defaultObjectAccessPermissionsForPropertyGetADM( - projectIri: IRI, + projectIri: ProjectIri, propertyIri: IRI, ): Task[Set[PermissionADM]] = - for { - defaultPermissionsOption <- defaultObjectAccessPermissionGetADM( - projectIri = projectIri, - groupIri = None, - resourceClassIri = None, - propertyIri = Some(propertyIri), - ) - defaultPermissions: Set[PermissionADM] = defaultPermissionsOption match { - case Some(doap) => doap.hasPermissions - case None => Set.empty[PermissionADM] - } - } yield defaultPermissions + defaultObjectAccessPermissionGetADM(projectIri, None, None, Some(propertyIri)).map { + case Some(doap) => doap.hasPermissions + case None => Set.empty[PermissionADM] + } /** * Returns a string containing default object permissions statements ready for usage during creation of a new resource. @@ -467,16 +445,18 @@ final case class PermissionsResponder( * @return an optional string with object access permission statements */ private def defaultObjectAccessPermissionsStringForEntityGetADM( - projectIri: IRI, + projectIri: ProjectIri, resourceClassIri: IRI, propertyIri: Option[IRI], - entityType: IRI, + entityType: EntityType, targetUser: User, ): Task[DefaultObjectAccessPermissionsStringResponseADM] = for { /* Get the groups the user is member of. */ userGroups <- - ZIO.attempt(targetUser.permissions.groupsPerProject.get(projectIri).map(_.toSet).getOrElse(Set.empty[IRI])) + ZIO.attempt( + targetUser.permissions.groupsPerProject.get(projectIri.value).map(_.toSet).getOrElse(Set.empty[IRI]), + ) /* Explicitly add 'SystemAdmin' and 'KnownUser' groups. */ extendedUserGroups: List[IRI] = @@ -515,7 +495,7 @@ final case class PermissionsResponder( /////////////////////////////// /* project resource class / property combination */ defaultPermissionsOnProjectResourceClassProperty <- { - if (entityType == PropertyEntityType && permissionsListBuffer.isEmpty) { + if (entityType == EntityType.Property && permissionsListBuffer.isEmpty) { defaultObjectAccessPermissionsForResourceClassPropertyGetADM( projectIri = projectIri, resourceClassIri = resourceClassIri, @@ -536,10 +516,9 @@ final case class PermissionsResponder( /* system resource class / property combination */ defaultPermissionsOnSystemResourceClassProperty <- { - if (entityType == PropertyEntityType && permissionsListBuffer.isEmpty) { - val systemProject = KnoraProjectRepo.builtIn.SystemProject.id.value + if (entityType == EntityType.Property && permissionsListBuffer.isEmpty) { defaultObjectAccessPermissionsForResourceClassPropertyGetADM( - projectIri = systemProject, + projectIri = KnoraProjectRepo.builtIn.SystemProject.id, resourceClassIri = resourceClassIri, propertyIri = propertyIri.getOrElse(throw BadRequestException("PropertyIri needs to be supplied.")), ) @@ -556,7 +535,7 @@ final case class PermissionsResponder( /////////////////////// /* Get the default object access permissions defined on the resource class for the current project */ defaultPermissionsOnProjectResourceClass <- { - if (entityType == ResourceEntityType && permissionsListBuffer.isEmpty) { + if (entityType == EntityType.Resource && permissionsListBuffer.isEmpty) { defaultObjectAccessPermissionsForResourceClassGetADM( projectIri = projectIri, resourceClassIri = resourceClassIri, @@ -571,11 +550,10 @@ final case class PermissionsResponder( /* Get the default object access permissions defined on the resource class inside the SystemProject */ defaultPermissionsOnSystemResourceClass <- { - if (entityType == ResourceEntityType && permissionsListBuffer.isEmpty) { - val systemProject = KnoraProjectRepo.builtIn.SystemProject.id.value + if (entityType == EntityType.Resource && permissionsListBuffer.isEmpty) { defaultObjectAccessPermissionsForResourceClassGetADM( - projectIri = systemProject, - resourceClassIri = resourceClassIri, + KnoraProjectRepo.builtIn.SystemProject.id, + resourceClassIri, ) } else { ZIO.attempt(Set.empty[PermissionADM]) @@ -590,7 +568,7 @@ final case class PermissionsResponder( /////////////////////// /* project property */ defaultPermissionsOnProjectProperty <- { - if (entityType == PropertyEntityType && permissionsListBuffer.isEmpty) { + if (entityType == EntityType.Property && permissionsListBuffer.isEmpty) { defaultObjectAccessPermissionsForPropertyGetADM( projectIri = projectIri, propertyIri = propertyIri.getOrElse(throw BadRequestException("PropertyIri needs to be supplied.")), @@ -605,11 +583,10 @@ final case class PermissionsResponder( /* system property */ defaultPermissionsOnSystemProperty <- { - if (entityType == PropertyEntityType && permissionsListBuffer.isEmpty) { - val systemProject = KnoraProjectRepo.builtIn.SystemProject.id.value + if (entityType == EntityType.Property && permissionsListBuffer.isEmpty) { defaultObjectAccessPermissionsForPropertyGetADM( - projectIri = systemProject, - propertyIri = propertyIri.getOrElse(throw BadRequestException("PropertyIri needs to be supplied.")), + KnoraProjectRepo.builtIn.SystemProject.id, + propertyIri.getOrElse(throw BadRequestException("PropertyIri needs to be supplied.")), ) } else { ZIO.attempt(Set.empty[PermissionADM]) @@ -757,16 +734,14 @@ final case class PermissionsResponder( */ val createPermissionTask = for { - _ <- validate(createRequest) - projectIri <- ZIO - .fromEither(ProjectIri.from(createRequest.forProject)) - .mapError(BadRequestException.apply) + _ <- validate(createRequest) + projectIri <- ZIO.fromEither(ProjectIri.from(createRequest.forProject)).mapError(BadRequestException.apply) project <- knoraProjectService .findById(projectIri) .someOrFail(NotFoundException(s"Project ${projectIri.value} not found")) _ <- auth.ensureSystemAdminOrProjectAdmin(user, project) checkResult <- defaultObjectAccessPermissionGetADM( - createRequest.forProject, + projectIri, createRequest.forGroup, createRequest.forResourceClass, createRequest.forProperty, @@ -842,7 +817,7 @@ final case class PermissionsResponder( // try to retrieve the newly created permission maybePermission <- defaultObjectAccessPermissionGetADM( - createRequest.forProject, + projectIri, createRequest.forGroup, createRequest.forResourceClass, createRequest.forProperty, @@ -1496,50 +1471,63 @@ final case class PermissionsResponder( ) } yield () + /** + * Gets the default permissions for new values. + * + * @param projectIri the IRI of the project of the containing resource. + * @param resourceClassIri the internal IRI of the resource class. + * @param propertyIris the internal IRIs of the properties that points to the values. + * @param targetUser the user that is creating the value. + * @return a permission string. + */ + def newValueDefaultObjectAccessPermissions( + projectIri: ProjectIri, + resourceClassIri: SmartIri, + propertyIris: Set[SmartIri], + targetUser: User, + ): Task[Map[SmartIri, DefaultObjectAccessPermissionsStringResponseADM]] = + ZIO + .foreach(propertyIris) { propertyIri => + newValueDefaultObjectAccessPermissions(projectIri, resourceClassIri, propertyIri, targetUser) + .map(propertyIri -> _) + } + .map(_.toMap) + /** * Gets the default permissions for a new value. * * @param projectIri the IRI of the project of the containing resource. * @param resourceClassIri the internal IRI of the resource class. * @param propertyIri the internal IRI of the property that points to the value. - * @param targetUser the user that is creating the value. + * @param targetUser the user that is creating the value. * @return a permission string. */ - def getDefaultValuePermissions( - projectIri: IRI, + def newValueDefaultObjectAccessPermissions( + projectIri: ProjectIri, resourceClassIri: SmartIri, propertyIri: SmartIri, targetUser: User, - ): Task[String] = + ): Task[DefaultObjectAccessPermissionsStringResponseADM] = for { - _ <- ZIO.getOrFailWith(BadRequestException(s"Invalid project IRI $projectIri"))( - ProjectIri.from(projectIri).toOption, - ) - _ <- ZIO.unless(resourceClassIri.isKnoraEntityIri) { ZIO.fail(BadRequestException(s"Invalid resource class IRI: $resourceClassIri")) } - _ <- ZIO.unless(propertyIri.isKnoraEntityIri) { ZIO.fail(BadRequestException(s"Invalid property IRI: $propertyIri")) } - _ <- ZIO.when(targetUser.isAnonymousUser) { ZIO.fail(BadRequestException("Anonymous Users are not allowed.")) } + permission <- defaultObjectAccessPermissionsStringForEntityGetADM( + projectIri, + resourceClassIri.toString, + Some(propertyIri.toString), + EntityType.Property, + targetUser, + ) + } yield permission - permissionLiteral <- defaultObjectAccessPermissionsStringForEntityGetADM( - projectIri = projectIri, - resourceClassIri = resourceClassIri.toString, - propertyIri = Some(propertyIri.toString), - entityType = PropertyEntityType, - targetUser = targetUser, - ).map { - _.permissionLiteral - } - } yield permissionLiteral - - def getDefaultResourcePermissions( + def newResourceDefaultObjectAccessPermissions( projectIri: ProjectIri, resourceClassIri: SmartIri, targetUser: User, @@ -1548,10 +1536,10 @@ final case class PermissionsResponder( .fail(BadRequestException(s"Invalid resource class IRI: $resourceClassIri")) .when(!resourceClassIri.isKnoraEntityIri) *> defaultObjectAccessPermissionsStringForEntityGetADM( - projectIri.value, + projectIri, resourceClassIri.toString, None, - ResourceEntityType, + EntityType.Resource, targetUser, ) } diff --git a/webapi/src/main/scala/org/knora/webapi/responders/v2/ValuesResponderV2.scala b/webapi/src/main/scala/org/knora/webapi/responders/v2/ValuesResponderV2.scala index ef8c2dd3b8..1890cb920d 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/v2/ValuesResponderV2.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/v2/ValuesResponderV2.scala @@ -264,13 +264,12 @@ final case class ValuesResponderV2Live( } // Get the default permissions for the new value. - defaultValuePermissions <- - permissionsResponder.getDefaultValuePermissions( - projectIri = resourceInfo.projectADM.id, - resourceClassIri = resourceInfo.resourceClassIri, - propertyIri = submittedInternalPropertyIri, - targetUser = requestingUser, - ) + defaultValuePermissions <- permissionsResponder.newValueDefaultObjectAccessPermissions( + resourceInfo.projectADM.projectIri, + resourceInfo.resourceClassIri, + submittedInternalPropertyIri, + requestingUser, + ) // Did the user submit permissions for the new value? newValuePermissionLiteral <- @@ -289,7 +288,7 @@ final case class ValuesResponderV2Live( PermissionUtilADM.comparePermissionsADM( entityProject = resourceInfo.projectADM.id, permissionLiteralA = validatedCustomPermissions, - permissionLiteralB = defaultValuePermissions, + permissionLiteralB = defaultValuePermissions.permissionLiteral, requestingUser = requestingUser, ) @@ -305,7 +304,7 @@ final case class ValuesResponderV2Live( case None => // No. Use the default permissions. - ZIO.succeed(defaultValuePermissions) + ZIO.succeed(defaultValuePermissions.permissionLiteral) } dataNamedGraph: IRI = ProjectService.projectDataNamedGraphV2(resourceInfo.projectADM).value diff --git a/webapi/src/main/scala/org/knora/webapi/responders/v2/resources/CreateResourceV2Handler.scala b/webapi/src/main/scala/org/knora/webapi/responders/v2/resources/CreateResourceV2Handler.scala index 87586fcd2e..6a625f4f45 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/v2/resources/CreateResourceV2Handler.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/v2/resources/CreateResourceV2Handler.scala @@ -35,7 +35,6 @@ import org.knora.webapi.responders.IriService import org.knora.webapi.responders.admin.PermissionsResponder import org.knora.webapi.responders.v2.* import org.knora.webapi.slice.admin.api.model.* -import org.knora.webapi.slice.admin.domain.model.KnoraProject.ProjectIri import org.knora.webapi.slice.admin.domain.model.Permission import org.knora.webapi.slice.admin.domain.model.User import org.knora.webapi.slice.admin.domain.service.KnoraGroupRepo @@ -221,19 +220,18 @@ final case class CreateResourceV2Handler( ) // Get the default permissions of the resource class. - defaultResourcePermissionsMap <- getResourceClassDefaultPermissions( - createResourceRequestV2.createResource.projectADM.id, - Set(internalCreateResource.resourceClassIri), - createResourceRequestV2.requestingUser, - ) + defaultResourcePermissions <- permissionsResponder.newResourceDefaultObjectAccessPermissions( + createResourceRequestV2.createResource.projectADM.projectIri, + internalCreateResource.resourceClassIri, + createResourceRequestV2.requestingUser, + ) // Get the default permissions of each property used. - defaultPropertyPermissionsMap <- getDefaultPropertyPermissions( - projectIri = createResourceRequestV2.createResource.projectADM.id, - resourceClassProperties = Map( - internalCreateResource.resourceClassIri -> internalCreateResource.values.keySet, - ), - requestingUser = createResourceRequestV2.requestingUser, + defaultPropertyPermissionsMap <- permissionsResponder.newValueDefaultObjectAccessPermissions( + createResourceRequestV2.createResource.projectADM.projectIri, + internalCreateResource.resourceClassIri, + internalCreateResource.values.keySet, + createResourceRequestV2.requestingUser, ) // Do the remaining pre-update checks and make a ResourceReadyToCreate describing the SPARQL @@ -245,8 +243,8 @@ final case class CreateResourceV2Handler( linkTargetClasses = linkTargetClasses, entityInfo = allEntityInfo, clientResourceIDs = Map.empty[IRI, String], - defaultResourcePermissions = defaultResourcePermissionsMap(internalCreateResource.resourceClassIri), - defaultPropertyPermissions = defaultPropertyPermissionsMap(internalCreateResource.resourceClassIri), + defaultResourcePermissions = defaultResourcePermissions.permissionLiteral, + defaultPropertyPermissions = defaultPropertyPermissionsMap.map((k, v) => (k, v.permissionLiteral)), creationDate = internalCreateResource.creationDate.getOrElse(Instant.now), requestingUser = createResourceRequestV2.requestingUser, ) @@ -895,68 +893,10 @@ final case class CreateResourceV2Handler( ZioHelper.sequence(propertyValuesWithValidatedPermissionsFutures.map { case (k, v) => k -> ZIO.collectAll(v) }) } - /** - * Gets the default permissions for resource classs in a project. - * - * @param projectIri the IRI of the project. - * @param resourceClassIris the internal IRIs of the resource classes. - * @param requestingUser the user making the request. - * @return a map of resource class IRIs to default permission strings. - */ - private def getResourceClassDefaultPermissions( - projectIri: IRI, - resourceClassIris: Set[SmartIri], - targetUser: User, - ): Task[Map[SmartIri, String]] = - for { - projectIri <- - ZIO.fromEither(ProjectIri.from(projectIri)).orElseFail(BadRequestException(s"Invalid project IRI $projectIri")) - _ <- ZIO.fail(BadRequestException("Anonymous Users are not allowed.")).when(targetUser.isAnonymousUser) - result <- ZIO - .foreach(resourceClassIris.toSeq) { resourceClassIri => - permissionsResponder - .getDefaultResourcePermissions(projectIri, resourceClassIri, targetUser) - .map(p => (resourceClassIri, p.permissionLiteral)) - } - .map(_.toMap) - } yield result - - /** - * Gets the default permissions for properties in a resource class in a project. - * - * @param projectIri the IRI of the project. - * @param resourceClassProperties a map of internal resource class IRIs to sets of internal property IRIs. - * @param requestingUser the user making the request. - * @return a map of internal resource class IRIs to maps of property IRIs to default permission strings. - */ - private def getDefaultPropertyPermissions( - projectIri: IRI, - resourceClassProperties: Map[SmartIri, Set[SmartIri]], - requestingUser: User, - ): Task[Map[SmartIri, Map[SmartIri, String]]] = { - val permissionsFutures: Map[SmartIri, Task[Map[SmartIri, String]]] = resourceClassProperties.map { - case (resourceClassIri, propertyIris) => - val propertyPermissionsFutures: Map[SmartIri, Task[String]] = propertyIris.toSeq.map { propertyIri => - propertyIri -> - permissionsResponder.getDefaultValuePermissions( - projectIri = projectIri, - resourceClassIri = resourceClassIri, - propertyIri = propertyIri, - targetUser = requestingUser, - ) - }.toMap - - resourceClassIri -> ZioHelper.sequence(propertyPermissionsFutures) - } - - ZioHelper.sequence(permissionsFutures) - } - /** * Checks that a resource was created. * * @param resourceIri the IRI of the resource that should have been created. - * @param projectIri the IRI of the project in which the resource should have been created. * @param requestingUser the user that attempted to create the resource. * @return a preview of the resource that was created. */