Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add check for can a cardinality be set for specific class and property #2382

Merged
merged 22 commits into from Jan 16, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
06068eb
Move knora-ontologies to webapi/src/main/resources and keep symbolic …
seakayone Dec 23, 2022
33f1363
Rename parameter, add scaladoc
seakayone Jan 13, 2023
8a95323
Add scaladoc and fmt
seakayone Jan 13, 2023
31fb6a1
Merge branch 'main' into wip/widen-cardinality-rebased
seakayone Jan 13, 2023
e0c2238
Update webapi/src/main/scala/org/knora/webapi/messages/StringFormatte…
seakayone Jan 13, 2023
95d5774
Update webapi/src/main/scala/org/knora/webapi/slice/ontology/domain/s…
seakayone Jan 13, 2023
c041ac4
Rename getUserADMZ
seakayone Jan 13, 2023
ef9523e
Remove StringFormatter.toInternalSmartIri
seakayone Jan 13, 2023
f3784dd
Update webapi/src/main/scala/org/knora/webapi/routing/UnsafeZioRun.scala
seakayone Jan 13, 2023
4f3024c
Rename RestCardinalityService.canChangeCardinality
seakayone Jan 13, 2023
d0c0043
Move IriConverterLiveSpec to test source set and simplify implementation
seakayone Jan 16, 2023
5c7dc3a
Fix test
seakayone Jan 16, 2023
93e7f2c
Remove unused CanChangeCardinalitiesRequestV2
seakayone Jan 16, 2023
53cb70d
Update documentation of the isPropertyUsed query
seakayone Jan 16, 2023
8ac006d
fmt
seakayone Jan 16, 2023
787b27e
Update webapi/src/main/scala/org/knora/webapi/routing/Authenticator.s…
seakayone Jan 16, 2023
541ab66
Update webapi/src/main/scala/org/knora/webapi/slice/ontology/domain/s…
seakayone Jan 16, 2023
d98a72a
Update webapi/src/main/scala/org/knora/webapi/slice/ontology/domain/s…
seakayone Jan 16, 2023
f0b1494
Update webapi/src/main/scala/org/knora/webapi/slice/ontology/domain/s…
seakayone Jan 16, 2023
558d36f
to lower case
seakayone Jan 16, 2023
a471733
Update webapi/src/main/scala/org/knora/webapi/slice/common/service/Re…
seakayone Jan 16, 2023
e34d19c
Mark old dsp.schema.domain.Cardinaltiy as deprecated
seakayone Jan 16, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions dsp-shared/src/main/scala/dsp/errors/Errors.scala
Expand Up @@ -85,6 +85,12 @@ object RequestRejectedException {
* @param message a description of the error.
*/
case class BadRequestException(message: String) extends RequestRejectedException(message)
object BadRequestException {
def invalidQueryParamValue(key: String): BadRequestException =
BadRequestException(s"Invalid value for query parameter '$key'")
def missingQueryParamValue(key: String): BadRequestException =
BadRequestException(s"Missing query parameter '$key'")
}

/**
* An exception indicating that a user has provided bad credentials.
Expand Down
19 changes: 9 additions & 10 deletions webapi/src/it/scala/org/knora/webapi/R2RSpec.scala
Expand Up @@ -5,6 +5,7 @@

package org.knora.webapi

import akka.actor.ActorRef
import akka.http.scaladsl.model.HttpResponse
import akka.http.scaladsl.testkit.ScalatestRouteTest
import com.typesafe.scalalogging.Logger
Expand All @@ -13,16 +14,17 @@ import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpec
import zio._
import zio.logging.backend.SLF4J

import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.util.concurrent.TimeUnit
import scala.concurrent.Await
import scala.concurrent.Future

import org.knora.webapi.config.AppConfig
import org.knora.webapi.core.AppRouter
import org.knora.webapi.core.AppServer
import org.knora.webapi.core.LayersTest.DefaultTestEnvironmentWithoutSipi
import org.knora.webapi.core.TestStartupUtils
import org.knora.webapi.messages.store.triplestoremessages.RdfDataObject
import org.knora.webapi.messages.util.rdf._
Expand Down Expand Up @@ -50,7 +52,8 @@ abstract class R2RSpec
* The effect layers from which the App is built.
* Can be overriden in specs that need other implementations.
*/
lazy val effectLayers = core.LayersTest.integrationTestsWithFusekiTestcontainers(Some(system))
lazy val effectLayers: ULayer[DefaultTestEnvironmentWithoutSipi] =
core.LayersTest.integrationTestsWithFusekiTestcontainers(Some(system))

/**
* `Bootstrap` will ensure that everything is instantiated when the Runtime is created
Expand All @@ -63,10 +66,7 @@ abstract class R2RSpec
] = ZLayer.empty ++ Runtime.removeDefaultLoggers ++ SLF4J.slf4j ++ effectLayers

// create a configured runtime
private val runtime = Unsafe.unsafe { implicit u =>
Runtime.unsafe
.fromLayer(bootstrap)
}
val runtime: Runtime.Scoped[Environment] = Unsafe.unsafe(implicit u => Runtime.unsafe.fromLayer(bootstrap))

// An effect for getting stuff out, so that we can pass them
// to some legacy code
Expand All @@ -90,11 +90,11 @@ abstract class R2RSpec
// main difference to other specs (no own systen and executionContext defined)
lazy val rdfDataObjects = List.empty[RdfDataObject]
val log: Logger = Logger(this.getClass())
val appActor = router.ref
val appActor: ActorRef = router.ref

// needed by some tests
val routeData = KnoraRouteData(system, appActor, config)
val appConfig = config
val routeData: KnoraRouteData = KnoraRouteData(system, appActor, config)
val appConfig: AppConfig = config

final override def beforeAll(): Unit =
/* Here we start our app and initialize the repository before each suit runs */
Expand All @@ -110,7 +110,6 @@ abstract class R2RSpec
}

final override def afterAll(): Unit = {

/* Stop ZIO runtime and release resources (e.g., running docker containers) */
Unsafe.unsafe { implicit u =>
runtime.unsafe.shutdown()
Expand Down
11 changes: 11 additions & 0 deletions webapi/src/it/scala/org/knora/webapi/core/LayersTest.scala
Expand Up @@ -7,7 +7,12 @@ import org.knora.webapi.auth.JWTService
import org.knora.webapi.config.AppConfig
import org.knora.webapi.config.AppConfigForTestContainers
import org.knora.webapi.messages.StringFormatter
import org.knora.webapi.responders.ActorDeps
import org.knora.webapi.routing.ApiRoutes
import org.knora.webapi.slice.ontology.api.service.RestCardinalityService
import org.knora.webapi.slice.ontology.domain.service.CardinalityService
import org.knora.webapi.slice.ontology.repo.service.OntologyCache
import org.knora.webapi.slice.ontology.repo.service.OntologyRepoLive
import org.knora.webapi.slice.resourceinfo.api.RestResourceInfoService
import org.knora.webapi.slice.resourceinfo.domain.IriConverter
import org.knora.webapi.slice.resourceinfo.domain.ResourceInfoRepo
Expand Down Expand Up @@ -44,6 +49,7 @@ object LayersTest {
with IriConverter
with RepositoryUpdater
with ResourceInfoRepo
with RestCardinalityService
with RestResourceInfoService
with State
with StringFormatter
Expand All @@ -53,15 +59,20 @@ object LayersTest {

private val commonLayersForAllIntegrationTests =
ZLayer.makeSome[CommonR0, CommonR](
ActorDeps.layer,
ApiRoutes.layer,
AppRouter.layer,
CacheServiceInMemImpl.layer,
CacheServiceManager.layer,
CardinalityService.layer,
HttpServer.layer,
IIIFServiceManager.layer,
IriConverter.layer,
OntologyCache.layer,
OntologyRepoLive.layer,
RepositoryUpdater.layer,
ResourceInfoRepo.layer,
RestCardinalityService.layer,
RestResourceInfoService.layer,
State.layer,
StringFormatter.test,
Expand Down
Expand Up @@ -64,9 +64,9 @@ class OntologyV2R2RSpec extends R2RSpec {
private implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance

private val ontologiesPath =
DSPApiDirectives.handleErrors(system, appConfig)(new OntologiesRouteV2(routeData).makeRoute)
DSPApiDirectives.handleErrors(system, appConfig)(new OntologiesRouteV2(routeData, runtime).makeRoute)
private val resourcesPath =
DSPApiDirectives.handleErrors(system, appConfig)(new ResourcesRouteV2(routeData, null).makeRoute)
DSPApiDirectives.handleErrors(system, appConfig)(new ResourcesRouteV2(routeData, runtime).makeRoute)

implicit def default(implicit system: ActorSystem): RouteTestTimeout = RouteTestTimeout(
appConfig.defaultTimeoutAsDuration
Expand Down Expand Up @@ -1010,7 +1010,7 @@ class OntologyV2R2RSpec extends R2RSpec {
val expectedResponse: String =
s"""{
| "knora-api:lastModificationDate": {
| "@value": "${newFreetestLastModDate}",
| "@value": "$newFreetestLastModDate",
| "@type": "xsd:dateTimeStamp"
| },
| "rdfs:label": "freetest",
Expand Down Expand Up @@ -1092,7 +1092,7 @@ class OntologyV2R2RSpec extends R2RSpec {
val expectedResponse: String =
s"""{
| "knora-api:lastModificationDate": {
| "@value": "${newFreetestLastModDate}",
| "@value": "$newFreetestLastModDate",
| "@type": "xsd:dateTimeStamp"
| },
| "rdfs:label": "freetest",
Expand Down Expand Up @@ -1718,7 +1718,7 @@ class OntologyV2R2RSpec extends R2RSpec {
"add all IRIs to newly created link value property again" in {
val url = URLEncoder.encode(s"${SharedOntologyTestDataADM.ANYTHING_ONTOLOGY_IRI_LocalHost}", "UTF-8")
Get(
s"/v2/ontologies/allentities/${url}"
s"/v2/ontologies/allentities/$url"
seakayone marked this conversation as resolved.
Show resolved Hide resolved
) ~> ontologiesPath ~> check {
val responseStr: String = responseAs[String]
assert(status == StatusCodes.OK, response.toString)
Expand Down Expand Up @@ -1754,7 +1754,7 @@ class OntologyV2R2RSpec extends R2RSpec {
iris should equal(expectedIris)

val isEditable = hasOtherNothingValue.requireBoolean(OntologyConstants.KnoraApiV2Complex.IsEditable)
isEditable shouldBe (true)
isEditable shouldBe true
}
}

Expand Down Expand Up @@ -1816,7 +1816,7 @@ class OntologyV2R2RSpec extends R2RSpec {
// load back the ontology to verify that the updated property still is editable
val encodedIri = URLEncoder.encode(s"${SharedOntologyTestDataADM.ANYTHING_ONTOLOGY_IRI_LocalHost}", "UTF-8")
Get(
s"/v2/ontologies/allentities/${encodedIri}"
s"/v2/ontologies/allentities/$encodedIri"
) ~> ontologiesPath ~> check {
val responseStr: String = responseAs[String]
assert(status == StatusCodes.OK, response.toString)
Expand Down Expand Up @@ -1889,7 +1889,7 @@ class OntologyV2R2RSpec extends R2RSpec {
// load back the ontology to verify that the updated property still is editable
val encodedIri = URLEncoder.encode(s"${SharedOntologyTestDataADM.ANYTHING_ONTOLOGY_IRI_LocalHost}", "UTF-8")
Get(
s"/v2/ontologies/allentities/${encodedIri}"
s"/v2/ontologies/allentities/$encodedIri"
) ~> ontologiesPath ~> check {
val responseStr: String = responseAs[String]
assert(status == StatusCodes.OK, response.toString)
Expand Down Expand Up @@ -1935,7 +1935,7 @@ class OntologyV2R2RSpec extends R2RSpec {
// load back the ontology to verify that the updated property still is editable
val encodedIri = URLEncoder.encode(s"${SharedOntologyTestDataADM.ANYTHING_ONTOLOGY_IRI_LocalHost}", "UTF-8")
Get(
s"/v2/ontologies/allentities/${encodedIri}"
s"/v2/ontologies/allentities/$encodedIri"
) ~> ontologiesPath ~> check {
val responseStr: String = responseAs[String]
assert(status == StatusCodes.OK, response.toString)
Expand Down Expand Up @@ -2008,7 +2008,7 @@ class OntologyV2R2RSpec extends R2RSpec {
// load back the ontology to verify that the updated property still is editable
val encodedIri = URLEncoder.encode(s"${SharedOntologyTestDataADM.ANYTHING_ONTOLOGY_IRI_LocalHost}", "UTF-8")
Get(
s"/v2/ontologies/allentities/${encodedIri}"
s"/v2/ontologies/allentities/$encodedIri"
) ~> ontologiesPath ~> check {
val responseStr: String = responseAs[String]
assert(status == StatusCodes.OK, response.toString)
Expand Down Expand Up @@ -3712,7 +3712,7 @@ class OntologyV2R2RSpec extends R2RSpec {
// check the ontology to see if all worked as it should
val url = URLEncoder.encode(s"http://0.0.0.0:3333/ontology/0001/freetest/v2", "UTF-8")
Get(
s"/v2/ontologies/allentities/${url}"
s"/v2/ontologies/allentities/$url"
) ~> ontologiesPath ~> check {
val responseStr: String = responseAs[String]
assert(status == StatusCodes.OK, response.toString)
Expand Down Expand Up @@ -3845,7 +3845,7 @@ class OntologyV2R2RSpec extends R2RSpec {
// check the ontology to see if all worked as it should
val url = URLEncoder.encode(s"http://0.0.0.0:3333/ontology/0001/freetest/v2", "UTF-8")
Get(
s"/v2/ontologies/allentities/${url}"
s"/v2/ontologies/allentities/$url"
) ~> ontologiesPath ~> check {
val responseStr: String = responseAs[String]
assert(status == StatusCodes.OK, response.toString)
Expand Down
Expand Up @@ -21,15 +21,14 @@ import org.xmlunit.builder.Input
import org.xmlunit.diff.Diff
import spray.json.JsValue
import spray.json.JsonParser

import java.net.URLEncoder
import java.nio.file.Paths
import java.time.Instant
import scala.collection.mutable.ArrayBuffer
import scala.concurrent.Await
import scala.concurrent.duration._

import dsp.errors.AssertionException

import org.knora.webapi._
import org.knora.webapi.e2e.ClientTestDataCollector
import org.knora.webapi.e2e.InstanceChecker
Expand Down Expand Up @@ -2113,7 +2112,7 @@ class ResourcesRouteV2E2ESpec extends E2ESpec {

"correctly update the ontology cache when adding a resource, so that the resource can afterwards be found by gravsearch" in {
val freetestLastModDate: Instant = Instant.parse("2012-12-12T12:12:12.12Z")
DSPApiDirectives.handleErrors(system, appConfig)(new OntologiesRouteV2(routeData).makeRoute)
DSPApiDirectives.handleErrors(system, appConfig)(new OntologiesRouteV2(routeData, runtime).makeRoute)
val auth = BasicHttpCredentials(SharedTestDataADM.anythingAdminUser.email, SharedTestDataADM.testPass)

// create a new resource class and add a property with cardinality to it
Expand Down
Expand Up @@ -2324,7 +2324,7 @@ class ResourcesResponderV2Spec extends CoreSpec with ImplicitSender {

val isEntityUsedSparql: String = org.knora.webapi.messages.twirl.queries.sparql.v2.txt
.isEntityUsed(
entityIri = resourceIriToErase.get.toSmartIri,
entityIri = resourceIriToErase.get.toSmartIri.toInternalIri,
seakayone marked this conversation as resolved.
Show resolved Hide resolved
ignoreKnoraConstraints = true
)
.toString()
Expand Down
Expand Up @@ -8,7 +8,6 @@ package org.knora.webapi.responders.v2.ontology
import akka.util.Timeout

import org.knora.webapi.CoreSpec
import org.knora.webapi.InternalSchema
import org.knora.webapi.messages.IriConversions._
import org.knora.webapi.messages.SmartIri
import org.knora.webapi.messages.StringFormatter
Expand All @@ -25,17 +24,17 @@ class CardinalitiesSpec extends CoreSpec {

"Cardinalities.isPropertyUsedInResources()" should {
"detect that property is in use, when used in a resource" in {
val internalPropertyIri = freetestOntologyIri.makeEntityIri("hasText").toOntologySchema(InternalSchema)
val internalClassIri = freetestOntologyIri.makeEntityIri("FreeTest").toOntologySchema(InternalSchema)
val internalPropertyIri = freetestOntologyIri.makeEntityIri("hasText").toInternalIri
val internalClassIri = freetestOntologyIri.makeEntityIri("FreeTest").toInternalIri
println(s"internalPropertyIri: $internalPropertyIri")

val resF = CardinalityHandler.isPropertyUsedInResources(appActor, internalClassIri, internalPropertyIri)
resF map { res => println(res); assert(res, "property is used in resource (instance of that resource class)") }
}

"detect that property is not in use, when not used in a resource" in {
val internalPropertyIri = freetestOntologyIri.makeEntityIri("hasText").toOntologySchema(InternalSchema)
val internalClassIri = freetestOntologyIri.makeEntityIri("FreeTestResourceClass").toOntologySchema(InternalSchema)
val internalPropertyIri = freetestOntologyIri.makeEntityIri("hasText").toInternalIri
val internalClassIri = freetestOntologyIri.makeEntityIri("FreeTestResourceClass").toInternalIri
println(s"internalPropertyIri: $internalPropertyIri")

val resF = CardinalityHandler.isPropertyUsedInResources(appActor, internalClassIri, internalPropertyIri)
Expand All @@ -45,8 +44,8 @@ class CardinalitiesSpec extends CoreSpec {
}

"detect that property is not in use, when not used in a resource of that class (even when used in another class)" in {
val internalPropertyIri = freetestOntologyIri.makeEntityIri("hasIntegerProperty").toOntologySchema(InternalSchema)
val internalClassIri = freetestOntologyIri.makeEntityIri("FreeTest").toOntologySchema(InternalSchema)
val internalPropertyIri = freetestOntologyIri.makeEntityIri("hasIntegerProperty").toInternalIri
val internalClassIri = freetestOntologyIri.makeEntityIri("FreeTest").toInternalIri
println(s"internalPropertyIri: $internalPropertyIri")

val resF = CardinalityHandler.isPropertyUsedInResources(appActor, internalClassIri, internalPropertyIri)
Expand All @@ -57,17 +56,17 @@ class CardinalitiesSpec extends CoreSpec {

"detect that link property is in use, when used in a resource" in {
val anythingOntologyIri = "http://0.0.0.0:3333/ontology/0001/anything/v2".toSmartIri
val internalPropertyIri = anythingOntologyIri.makeEntityIri("isPartOfOtherThing").toOntologySchema(InternalSchema)
val internalClassIri = anythingOntologyIri.makeEntityIri("Thing").toOntologySchema(InternalSchema)
val internalPropertyIri = anythingOntologyIri.makeEntityIri("isPartOfOtherThing").toInternalIri
val internalClassIri = anythingOntologyIri.makeEntityIri("Thing").toInternalIri
println(s"internalPropertyIri: $internalPropertyIri")

val resF = CardinalityHandler.isPropertyUsedInResources(appActor, internalClassIri, internalPropertyIri)
resF map { res => println(res); assert(res, "property is used in resource (instance of resource class)") }
}

"detect that property is in use, when used in a resource of a subclass" in {
val internalPropertyIri = freetestOntologyIri.makeEntityIri("hasDecimal").toOntologySchema(InternalSchema)
val internalClassIri = freetestOntologyIri.makeEntityIri("FreeTest").toOntologySchema(InternalSchema)
val internalPropertyIri = freetestOntologyIri.makeEntityIri("hasDecimal").toInternalIri
val internalClassIri = freetestOntologyIri.makeEntityIri("FreeTest").toInternalIri
println(s"internalPropertyIri: $internalPropertyIri")

val resF = CardinalityHandler.isPropertyUsedInResources(appActor, internalClassIri, internalPropertyIri)
Expand Down