From 265cb998a93a6ea465200c12e1eb27440458156b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Kleinb=C3=B6lting?= Date: Fri, 17 Jan 2025 11:27:03 +0100 Subject: [PATCH] fix: Find the right doap when looking for by ForWhat (#3460) --- .../DspIngestTestContainer.scala | 1 + .../repo/service/AbstractEntityRepo.scala | 14 ++++----- .../AdministrativePermissionRepoLive.scala | 4 +-- ...efaultObjectAccessPermissionRepoLive.scala | 19 ++++++++---- .../repo/service/KnoraGroupRepoLive.scala | 4 +-- .../repo/service/KnoraProjectRepoLive.scala | 4 +-- .../repo/service/KnoraUserRepoLive.scala | 10 +++---- ...ltObjectAccessPermissionRepoLiveSpec.scala | 30 +++++++++++++++++-- 8 files changed, 61 insertions(+), 25 deletions(-) diff --git a/integration/src/test/scala/org/knora/webapi/testcontainers/DspIngestTestContainer.scala b/integration/src/test/scala/org/knora/webapi/testcontainers/DspIngestTestContainer.scala index 01f4b55ec7..6785d49ce2 100644 --- a/integration/src/test/scala/org/knora/webapi/testcontainers/DspIngestTestContainer.scala +++ b/integration/src/test/scala/org/knora/webapi/testcontainers/DspIngestTestContainer.scala @@ -36,6 +36,7 @@ object DspIngestTestContainer { .withEnv("DB_JDBC_URL", "jdbc:sqlite:/tmp/ingest.sqlite") .withFileSystemBind(imagesVolume.hostPath, assetDir, BindMode.READ_WRITE) .withFileSystemBind(tempVolume.hostPath, tempDir, BindMode.READ_WRITE) + .withLogConsumer(frame => print("DSP-INGEST:" + frame.getUtf8String)) } val layer: URLayer[SharedVolumes.Volumes, DspIngestTestContainer] = diff --git a/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/AbstractEntityRepo.scala b/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/AbstractEntityRepo.scala index cd3f9a3e9e..9e60615d7d 100644 --- a/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/AbstractEntityRepo.scala +++ b/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/AbstractEntityRepo.scala @@ -94,24 +94,24 @@ abstract class AbstractEntityRepo[E <: EntityWithId[Id], Id <: StringValue]( } } - protected def findOneByTriplePattern(pattern: RdfSubject => TriplePattern): Task[Option[E]] = - findOneByQuery(findByTriplePatternQuery(pattern)) + protected def findOneByPattern(pattern: RdfSubject => GraphPattern): Task[Option[E]] = + findOneByQuery(findByPatternQuery(pattern)) - protected def findAllByTriplePattern(pattern: RdfSubject => TriplePattern): Task[Chunk[E]] = - findAllByQuery(findByTriplePatternQuery(pattern)) + protected def findAllByPattern(pattern: RdfSubject => GraphPattern): Task[Chunk[E]] = + findAllByQuery(findByPatternQuery(pattern)) - private def findByTriplePatternQuery(pattern: RdfSubject => TriplePattern) = { + private def findByPatternQuery(pattern: RdfSubject => GraphPattern) = { val s = variable("s") val query: String = entityQuery(tripleP(s), graphP(s).and(pattern(s))).getQueryString Construct(query) } - protected def findOneByQuery(construct: Construct): Task[Option[E]] = + private def findOneByQuery(construct: Construct): Task[Option[E]] = runQuery(construct) .map(_.nextOption()) .flatMap(ZIO.foreach(_)(mapper.toEntity(_).mapError(TriplestoreResponseException.apply))) - protected def findAllByQuery(construct: Construct): Task[Chunk[E]] = + private def findAllByQuery(construct: Construct): Task[Chunk[E]] = runQuery(construct).flatMap( ZStream.fromIterator(_).mapZIO(mapper.toEntity(_).mapError(TriplestoreResponseException.apply)).runCollect, ) diff --git a/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/AdministrativePermissionRepoLive.scala b/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/AdministrativePermissionRepoLive.scala index 5913672901..65d8f0fd5b 100644 --- a/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/AdministrativePermissionRepoLive.scala +++ b/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/AdministrativePermissionRepoLive.scala @@ -60,13 +60,13 @@ final case class AdministrativePermissionRepoLive( groupIri: GroupIri, projectIri: ProjectIri, ): Task[Option[AdministrativePermission]] = - findOneByTriplePattern( + findOneByPattern( _.has(Vocabulary.KnoraAdmin.forGroup, Rdf.iri(groupIri.value)) .andHas(Vocabulary.KnoraAdmin.forProject, Rdf.iri(projectIri.value)), ) override def findByProject(projectIri: ProjectIri): Task[Chunk[AdministrativePermission]] = - findAllByTriplePattern(_.has(Vocabulary.KnoraAdmin.forProject, Rdf.iri(projectIri.value))) + findAllByPattern(_.has(Vocabulary.KnoraAdmin.forProject, Rdf.iri(projectIri.value))) } object AdministrativePermissionRepoLive { diff --git a/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/DefaultObjectAccessPermissionRepoLive.scala b/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/DefaultObjectAccessPermissionRepoLive.scala index 37c7d76606..b2431ff294 100644 --- a/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/DefaultObjectAccessPermissionRepoLive.scala +++ b/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/DefaultObjectAccessPermissionRepoLive.scala @@ -6,6 +6,7 @@ package org.knora.webapi.slice.admin.repo.service import org.eclipse.rdf4j.common.net.ParsedIRI +import org.eclipse.rdf4j.sparqlbuilder.core.SparqlBuilder.`var` as variable import org.eclipse.rdf4j.sparqlbuilder.graphpattern.TriplePattern import org.eclipse.rdf4j.sparqlbuilder.rdf.Iri import org.eclipse.rdf4j.sparqlbuilder.rdf.Rdf @@ -54,15 +55,23 @@ final case class DefaultObjectAccessPermissionRepoLive( ) override def findByProject(projectIri: ProjectIri): Task[Chunk[DefaultObjectAccessPermission]] = - findAllByTriplePattern(_.has(Vocabulary.KnoraAdmin.forProject, Rdf.iri(projectIri.value))) + findAllByPattern(_.has(Vocabulary.KnoraAdmin.forProject, Rdf.iri(projectIri.value))) def findByProjectAndForWhat(projectIri: ProjectIri, forWhat: ForWhat): Task[Option[DefaultObjectAccessPermission]] = - findOneByTriplePattern(p => + findOneByPattern(p => val pattern = p.has(Vocabulary.KnoraAdmin.forProject, Rdf.iri(projectIri.value)) forWhat match { - case Group(g) => pattern.andHas(Vocabulary.KnoraAdmin.forGroup, Rdf.iri(g.value)) - case ResourceClass(rc) => pattern.andHas(Vocabulary.KnoraAdmin.forResourceClass, Rdf.iri(rc.value)) - case Property(prop) => pattern.andHas(Vocabulary.KnoraAdmin.forProperty, Rdf.iri(prop.value)) + case Group(g) => pattern.andHas(Vocabulary.KnoraAdmin.forGroup, Rdf.iri(g.value)) + case ResourceClass(rc) => + pattern + .andHas(Vocabulary.KnoraAdmin.forResourceClass, Rdf.iri(rc.value)) + .filterNotExists(p.has(Vocabulary.KnoraAdmin.forProperty, variable("prop"))) + + case Property(prop) => + pattern + .andHas(Vocabulary.KnoraAdmin.forProperty, Rdf.iri(prop.value)) + .filterNotExists(p.has(Vocabulary.KnoraAdmin.forResourceClass, variable("rc"))) + case ResourceClassAndProperty(rc, prop) => pattern .andHas(Vocabulary.KnoraAdmin.forResourceClass, Rdf.iri(rc.value)) diff --git a/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/KnoraGroupRepoLive.scala b/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/KnoraGroupRepoLive.scala index 32af7df8cb..5e257dad12 100644 --- a/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/KnoraGroupRepoLive.scala +++ b/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/KnoraGroupRepoLive.scala @@ -58,11 +58,11 @@ final case class KnoraGroupRepoLive( super.save(group) override def findByName(name: GroupName): Task[Option[KnoraGroup]] = - findOneByTriplePattern(_.has(groupName, Rdf.literalOf(name.value))) + findOneByPattern(_.has(groupName, Rdf.literalOf(name.value))) .map(_.orElse(KnoraGroupRepo.builtIn.findOneBy(_.groupName == name))) override def findByProjectIri(projectIri: ProjectIri): Task[Chunk[KnoraGroup]] = - findAllByTriplePattern(_.has(belongsToProject, Rdf.iri(projectIri.value))) + findAllByPattern(_.has(belongsToProject, Rdf.iri(projectIri.value))) } object KnoraGroupRepoLive { diff --git a/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/KnoraProjectRepoLive.scala b/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/KnoraProjectRepoLive.scala index ed3097a541..a56d446dfb 100644 --- a/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/KnoraProjectRepoLive.scala +++ b/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/KnoraProjectRepoLive.scala @@ -55,11 +55,11 @@ final case class KnoraProjectRepoLive( super.findById(id).map(_.orElse(KnoraProjectRepo.builtIn.findOneBy(_.id == id))) override def findByShortcode(shortcode: Shortcode): Task[Option[KnoraProject]] = - findOneByTriplePattern(_.has(Vocabulary.KnoraAdmin.projectShortcode, shortcode.value)) + findOneByPattern(_.has(Vocabulary.KnoraAdmin.projectShortcode, shortcode.value)) .map(_.orElse(KnoraProjectRepo.builtIn.findOneBy(_.shortcode == shortcode))) override def findByShortname(shortname: Shortname): Task[Option[KnoraProject]] = - findOneByTriplePattern(_.has(Vocabulary.KnoraAdmin.projectShortname, shortname.value)) + findOneByPattern(_.has(Vocabulary.KnoraAdmin.projectShortname, shortname.value)) .map(_.orElse(KnoraProjectRepo.builtIn.findOneBy(_.shortname == shortname))) override def findAll(): Task[Chunk[KnoraProject]] = super.findAll().map(_ ++ KnoraProjectRepo.builtIn.all) diff --git a/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/KnoraUserRepoLive.scala b/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/KnoraUserRepoLive.scala index 9d328a589a..3af1704d8f 100644 --- a/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/KnoraUserRepoLive.scala +++ b/webapi/src/main/scala/org/knora/webapi/slice/admin/repo/service/KnoraUserRepoLive.scala @@ -59,23 +59,23 @@ final case class KnoraUserRepoLive( super.findById(id).map(_.orElse(KnoraUserRepo.builtIn.findOneBy(_.id == id))) override def findByProjectAdminMembership(projectIri: ProjectIri): Task[Chunk[KnoraUser]] = - findAllByTriplePattern(_.has(isInProjectAdminGroup, Rdf.iri(projectIri.value))) + findAllByPattern(_.has(isInProjectAdminGroup, Rdf.iri(projectIri.value))) .map(_ ++ KnoraUserRepo.builtIn.findAllBy(_.isInProjectAdminGroup.contains(projectIri))) override def findByProjectMembership(projectIri: ProjectIri): Task[Chunk[KnoraUser]] = - findAllByTriplePattern(_.has(isInProject, Rdf.iri(projectIri.value))) + findAllByPattern(_.has(isInProject, Rdf.iri(projectIri.value))) .map(_ ++ KnoraUserRepo.builtIn.findAllBy(_.isInProject.contains(projectIri))) override def findByGroupMembership(groupIri: GroupIri): Task[Chunk[KnoraUser]] = - findAllByTriplePattern(_.has(isInGroup, Rdf.iri(groupIri.value))) + findAllByPattern(_.has(isInGroup, Rdf.iri(groupIri.value))) .map(_ ++ KnoraUserRepo.builtIn.findAllBy(_.isInGroup.contains(groupIri))) override def findByEmail(mail: Email): Task[Option[KnoraUser]] = - findOneByTriplePattern(_.has(email, Rdf.literalOf(mail.value))) + findOneByPattern(_.has(email, Rdf.literalOf(mail.value))) .map(_.orElse(KnoraUserRepo.builtIn.findOneBy(_.email == mail))) override def findByUsername(name: Username): Task[Option[KnoraUser]] = - findOneByTriplePattern(_.has(username, Rdf.literalOf(name.value))) + findOneByPattern(_.has(username, Rdf.literalOf(name.value))) .map(_.orElse(KnoraUserRepo.builtIn.findOneBy(_.username == name))) override def save(user: KnoraUser): Task[KnoraUser] = diff --git a/webapi/src/test/scala/org/knora/webapi/slice/admin/repo/service/DefaultObjectAccessPermissionRepoLiveSpec.scala b/webapi/src/test/scala/org/knora/webapi/slice/admin/repo/service/DefaultObjectAccessPermissionRepoLiveSpec.scala index c985334b5b..d71ecfd364 100644 --- a/webapi/src/test/scala/org/knora/webapi/slice/admin/repo/service/DefaultObjectAccessPermissionRepoLiveSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/slice/admin/repo/service/DefaultObjectAccessPermissionRepoLiveSpec.scala @@ -40,21 +40,47 @@ object DefaultObjectAccessPermissionRepoLiveSpec extends ZIOSpecDefault { private def permission(forWhat: ForWhat, permissions: Chunk[DefaultObjectAccessPermissionPart]) = DefaultObjectAccessPermission(PermissionIri.makeNew(shortcode), projectIri, forWhat, permissions) + private val resourceClassIri: InternalIri = InternalIri("https://example.com/rc") + private val propertyIri: InternalIri = InternalIri("https://example.com/p") private val expected = permission( - ForWhat.ResourceClassAndProperty(InternalIri("https://example.com/rc"), InternalIri("https://example.com/p")), + ForWhat.ResourceClassAndProperty(resourceClassIri, propertyIri), Chunk( DefaultObjectAccessPermissionPart(RestrictedView, NonEmptyChunk(groupIri)), DefaultObjectAccessPermissionPart(View, NonEmptyChunk(GroupIri.makeNew(shortcode), GroupIri.makeNew(shortcode))), ), ) - val spec = suite("AdministrativePermissionRepoLive")( + val spec = suite("DefaultObjectAccessPermissionRepoLive")( test("should save and find") { for { saved <- repo(_.save(expected)) found <- repo(_.findById(saved.id)) } yield assertTrue(found.contains(saved), saved == expected) }, + test("given ForWhat Property and ForWhat ResourceClassAndProperty exist should findByProjectAndForWhat") { + val rc = permission( + ForWhat.ResourceClass(resourceClassIri), + Chunk(DefaultObjectAccessPermissionPart(View, NonEmptyChunk(GroupIri.makeNew(shortcode)))), + ) + val p = permission( + ForWhat.Property(propertyIri), + Chunk(DefaultObjectAccessPermissionPart(View, NonEmptyChunk(GroupIri.makeNew(shortcode)))), + ) + val rcp = permission( + ForWhat.ResourceClassAndProperty(resourceClassIri, propertyIri), + Chunk(DefaultObjectAccessPermissionPart(View, NonEmptyChunk(GroupIri.makeNew(shortcode)))), + ) + for { + _ <- repo(_.saveAll(List(p, rc, rcp))) + foundPp <- repo(_.findByProjectAndForWhat(projectIri, p.forWhat)) + foundRc <- repo(_.findByProjectAndForWhat(projectIri, rc.forWhat)) + foundRcp <- repo(_.findByProjectAndForWhat(projectIri, rcp.forWhat)) + } yield assertTrue( + foundPp.contains(p), + foundRc.contains(rc), + foundRcp.contains(rcp), + ) + }, test("should delete") { for { saved <- repo(_.save(expected))