Skip to content

Commit

Permalink
feat(projectsADM): add possibility to get project and members by UUID (
Browse files Browse the repository at this point in the history
  • Loading branch information
mpro7 committed Nov 18, 2022
1 parent c59e3e9 commit 4b66682
Show file tree
Hide file tree
Showing 42 changed files with 993 additions and 627 deletions.
4 changes: 2 additions & 2 deletions docs/03-apis/api-admin/projects.md
Expand Up @@ -13,7 +13,7 @@

- `POST: /admin/projects` : create a new project

- `GET: /admin/projects/[iri | shortname | shortcode]/<identifier>` : returns a single project identified either through iri, shortname, or shortcode
- `GET: /admin/projects/[iri | shortname | shortcode | uuid]/<identifier>` : returns a single project identified either through iri, shortname, shortcode or UUID

- `PUT: /admin/projects/iri/<identifier>` : update a project identified by iri

Expand All @@ -23,7 +23,7 @@

**Project Member Operations:**

- `GET: /admin/projects/[iri | shortname | shortcode]/<identifier>/members` : returns all members part of a project identified through iri, shortname or shortcode
- `GET: /admin/projects/[iri | shortname | shortcode | uuid]/<identifier>/members` : returns all members part of a project identified through iri, shortname, shortcode or UUID

**Project Admin Member Operations:**

Expand Down
20 changes: 20 additions & 0 deletions dsp-shared/src/main/scala/dsp/valueobjects/Iri.scala
Expand Up @@ -132,6 +132,24 @@ object Iri {
}
}

/**
* Base64Uuid value object.
* This is base64 encoded UUID version without paddings.
*
* @param value to validate.
*/
sealed abstract case class Base64Uuid private (value: String)
object Base64Uuid {
def make(value: String): Validation[ValidationException, Base64Uuid] =
if (value.isEmpty) {
Validation.fail(ValidationException(IriErrorMessages.UuidMissing))
} else if (!V2UuidValidation.hasUuidLength(value)) {
Validation.fail(ValidationException(IriErrorMessages.UuidInvalid(value)))
} else if (!V2UuidValidation.isUuidVersion4Or5(value)) {
Validation.fail(ValidationException(IriErrorMessages.UuidVersionInvalid))
} else Validation.succeed(new Base64Uuid(value) {})
}

/**
* RoleIri value object.
*/
Expand Down Expand Up @@ -221,6 +239,8 @@ object IriErrorMessages {
val RoleIriInvalid = (iri: String) => s"Role IRI: $iri is invalid."
val UserIriMissing = "User IRI cannot be empty."
val UserIriInvalid = (iri: String) => s"User IRI: $iri is invalid."
val UuidMissing = "UUID cannot be empty"
val UuidInvalid = (uuid: String) => s"'$uuid' is not a UUID"
val UuidVersionInvalid = "Invalid UUID used to create IRI. Only versions 4 and 5 are supported."
val PropertyIriMissing = "Property IRI cannot be empty."
}
15 changes: 11 additions & 4 deletions dsp-shared/src/main/scala/dsp/valueobjects/V2.scala
Expand Up @@ -225,15 +225,22 @@ object V2UuidValidation {
getUUIDVersion(s) == 4 || getUUIDVersion(s) == 5

/**
* Gets the last segment of IRI, decodes UUID and gets the version.
* @param s the string (IRI) to be checked.
* Decodes Base64 encoded UUID and gets its version.
* @param uuid the Base64 encoded UUID as [[String]] to be checked.
* @return UUID version.
*/
def getUUIDVersion(s: String): Int = {
val encodedUUID = s.split("/").last
def getUUIDVersion(uuid: String): Int = {
val encodedUUID = getUuidFromIri(uuid)
decodeUuid(encodedUUID).version()
}

/**
* Gets the last IRI segment - Base64 encoded UUID.
* @param iri the IRI [[String]] to get the UUID from.
* @return Base64 encoded UUID as [[String]]
*/
def getUuidFromIri(iri: String): String = iri.split("/").last

/**
* Calls `decodeUuidWithErr`, throwing [[InconsistentRepositoryDataException]] if the string cannot be parsed.
*/
Expand Down
32 changes: 29 additions & 3 deletions dsp-shared/src/test/scala/dsp/valueobjects/IriSpec.scala
Expand Up @@ -12,6 +12,7 @@ import zio.test._
import dsp.errors.BadRequestException
import dsp.errors.ValidationException
import dsp.valueobjects.Iri._
import dsp.valueobjects.V2UuidValidation._

/**
* This spec is used to test the [[Iri]] value objects creation.
Expand All @@ -35,7 +36,11 @@ object IriSpec extends ZIOSpecDefault {
val validUserIri = "http://rdfh.ch/users/jDEEitJESRi3pDaDjjQ1WQ"
val userIriWithUUIDVersion3 = "http://rdfh.ch/users/cCmdcpn2MO211YYOplR1hQ"

def spec = (groupIriTest + listIriTest + projectIriTest + RoleIriTest + UserIriTest)
val invalidUuid = "MAgdcpn2MO211YYOplR32v"
val uuidVersion3 = getUuidFromIri(userIriWithUUIDVersion3)
val supportedUuid = getUuidFromIri(validUserIri)

def spec = (groupIriTest + listIriTest + projectIriTest + uuidTest + roleIriTest + userIriTest)

private val groupIriTest = suite("IriSpec - GroupIri")(
test("pass an empty value and return an error") {
Expand Down Expand Up @@ -190,7 +195,28 @@ object IriSpec extends ZIOSpecDefault {
}
)

private val RoleIriTest = suite("IriSpec - roleIri")(
private val uuidTest = suite("IriSpec - Base64Uuid")(
test("pass an empty value and return an error") {
assertTrue(Base64Uuid.make("") == Validation.fail(ValidationException(IriErrorMessages.UuidMissing)))
},
test("pass an invalid UUID and return an error") {
assertTrue(
Base64Uuid.make(invalidIri) == Validation.fail(ValidationException(IriErrorMessages.UuidInvalid(invalidIri)))
)
},
test("pass an valid UUID, which has not supported version 3") {
assertTrue(
Base64Uuid.make(uuidVersion3) == Validation.fail(ValidationException(IriErrorMessages.UuidVersionInvalid))
)
},
test("pass valid UUID and successfully create value object") {
(for {
uuid <- Base64Uuid.make(supportedUuid)
} yield assertTrue(uuid.value == supportedUuid)).toZIO
}
)

private val roleIriTest = suite("IriSpec - roleIri")(
test("pass an empty value and return an error") {
assertTrue(RoleIri.make("") == Validation.fail(BadRequestException(IriErrorMessages.RoleIriMissing)))
},
Expand All @@ -213,7 +239,7 @@ object IriSpec extends ZIOSpecDefault {
}
)

private val UserIriTest = suite("IriSpec - UserIri")(
private val userIriTest = suite("IriSpec - UserIri")(
test("pass an empty value and return an error") {
assertTrue(UserIri.make("") == Validation.fail(BadRequestException(IriErrorMessages.UserIriMissing)))
},
Expand Down
Expand Up @@ -6,7 +6,7 @@
@prefix knora-admin: <http://www.knora.org/ontology/knora-admin#> .
@prefix salsah-gui: <http://www.knora.org/ontology/salsah-gui#> .

<http://rdfh.ch/projects/0666> a knora-admin:knoraProject ;
<http://rdfh.ch/projects/cXxbOh4xRce3uLUyXHujfg> a knora-admin:knoraProject ;
knora-admin:projectShortname "test"^^xsd:string ;
knora-admin:projectLongname "Test"^^xsd:string ;
knora-admin:projectShortcode "0666"^^xsd:string ;
Expand All @@ -25,5 +25,5 @@
knora-admin:familyName "test"^^xsd:string ;
knora-admin:status "true"^^xsd:boolean ;
knora-admin:preferredLanguage "en"^^xsd:string ;
knora-admin:isInProject <http://rdfh.ch/projects/0666> ;
knora-admin:isInProject <http://rdfh.ch/projects/cXxbOh4xRce3uLUyXHujfg> ;
knora-admin:isInSystemAdminGroup "true"^^xsd:boolean .
14 changes: 7 additions & 7 deletions test_data/e2e.v2.SearchRouteV2R2RSpec/gravsearchtest1-data.ttl
Expand Up @@ -109,19 +109,19 @@

<http://rdfh.ch/0666/tWxW7jM0S2uMYKifwF0mtQ/values/yK5vML4_Sc6QcTPrdfD1kQ> rdf:object <http://rdfh.ch/0666/tWf2vqMqQ_OcUMJSRj6e5w> .

<http://rdfh.ch/0666/tWf2vqMqQ_OcUMJSRj6e5w> :attachedToProject <http://rdfh.ch/projects/0666> .
<http://rdfh.ch/0666/tWf2vqMqQ_OcUMJSRj6e5w> :attachedToProject <http://rdfh.ch/projects/cXxbOh4xRce3uLUyXHujfg> .

<http://rdfh.ch/0666/1rK4ZevpT5eIxj48kgncsQ> :attachedToProject <http://rdfh.ch/projects/0666> .
<http://rdfh.ch/0666/1rK4ZevpT5eIxj48kgncsQ> :attachedToProject <http://rdfh.ch/projects/cXxbOh4xRce3uLUyXHujfg> .

<http://rdfh.ch/0666/NLe33EVtTKGozGJOqKT_2Q> :attachedToProject <http://rdfh.ch/projects/0666> .
<http://rdfh.ch/0666/NLe33EVtTKGozGJOqKT_2Q> :attachedToProject <http://rdfh.ch/projects/cXxbOh4xRce3uLUyXHujfg> .

<http://rdfh.ch/0666/wopH6GHOSpCyASdrsNqg_A> :attachedToProject <http://rdfh.ch/projects/0666> .
<http://rdfh.ch/0666/wopH6GHOSpCyASdrsNqg_A> :attachedToProject <http://rdfh.ch/projects/cXxbOh4xRce3uLUyXHujfg> .

<http://rdfh.ch/0666/xY8O4uSeQb-MDC4VtvQGdw> :attachedToProject <http://rdfh.ch/projects/0666> .
<http://rdfh.ch/0666/xY8O4uSeQb-MDC4VtvQGdw> :attachedToProject <http://rdfh.ch/projects/cXxbOh4xRce3uLUyXHujfg> .

<http://rdfh.ch/0666/yjOFfSKPR_uiw8KoJu5mQg> :attachedToProject <http://rdfh.ch/projects/0666> .
<http://rdfh.ch/0666/yjOFfSKPR_uiw8KoJu5mQg> :attachedToProject <http://rdfh.ch/projects/cXxbOh4xRce3uLUyXHujfg> .

<http://rdfh.ch/0666/tWxW7jM0S2uMYKifwF0mtQ> :attachedToProject <http://rdfh.ch/projects/0666> .
<http://rdfh.ch/0666/tWxW7jM0S2uMYKifwF0mtQ> :attachedToProject <http://rdfh.ch/projects/cXxbOh4xRce3uLUyXHujfg> .

<http://rdfh.ch/0666/tWf2vqMqQ_OcUMJSRj6e5w> :creationDate "2018-06-06T12:08:56.619Z"^^xsd:dateTime .

Expand Down
Expand Up @@ -9,7 +9,7 @@

<http://www.knora.org/ontology/0666/gravsearchtest1> a owl:Ontology ;
rdfs:label "Test ontology" ;
knora-base:attachedToProject <http://rdfh.ch/projects/0666> ;
knora-base:attachedToProject <http://rdfh.ch/projects/cXxbOh4xRce3uLUyXHujfg> ;
knora-base:lastModificationDate "2012-12-12T12:12:12.12Z"^^xsd:dateTime .

gravsearchtest1:isInProjectValue rdf:type owl:ObjectProperty ;
Expand Down

0 comments on commit 4b66682

Please sign in to comment.