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(projectsADM): add possibility to get project and members by UUID (DEV-1408) #2272

Merged
merged 37 commits into from Nov 18, 2022
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
58d2e61
change getProjectByIri methods to work with UUID too
mpro7 Oct 31, 2022
eadef5a
add tests
mpro7 Nov 1, 2022
0dee8eb
fix tests
mpro7 Nov 1, 2022
6c73a88
fix error message
mpro7 Nov 1, 2022
adcaeaf
final fixes
mpro7 Nov 2, 2022
07ba246
update docs
mpro7 Nov 2, 2022
f3a35b9
one method per indentifier + docs
mpro7 Nov 2, 2022
486778f
refactor ProjectIdentifierADM
mpro7 Nov 4, 2022
b1e0ff5
adjust ProjectRouteADM
mpro7 Nov 4, 2022
1c5f567
fix other places where ProjectIdentifierADM is used
mpro7 Nov 4, 2022
80e0d71
Merge branch 'main' into DEV-1408-dsp-api-make-possible-to-get-projec…
mpro7 Nov 7, 2022
295a8df
fix tests
mpro7 Nov 7, 2022
24a41ec
fix formatting
mpro7 Nov 7, 2022
7c3815b
refactor + cleanup
mpro7 Nov 7, 2022
bab628d
Merge branch 'main' into DEV-1408-dsp-api-make-possible-to-get-projec…
mpro7 Nov 8, 2022
e1345c0
fix UpgradePluginPR2255
mpro7 Nov 8, 2022
533bc95
remove duplicated test
mpro7 Nov 9, 2022
76cc1b4
update Lumieres project IRI
mpro7 Nov 9, 2022
adc3844
update gravsearch test project IRI
mpro7 Nov 9, 2022
faa52ef
update v1 test data
mpro7 Nov 9, 2022
df03fdc
add UUID value object
mpro7 Nov 9, 2022
773d1d6
add found only in repo iri map
mpro7 Nov 9, 2022
e7571b4
move value object check to ProjectIdentifierADM
mpro7 Nov 10, 2022
c57ecd9
Merge branch 'main' into DEV-1408-dsp-api-make-possible-to-get-projec…
mpro7 Nov 10, 2022
1cc17ba
fix QueryTraverser
mpro7 Nov 11, 2022
79b0e60
improve uuid validation
mpro7 Nov 11, 2022
508101c
refactor ProjectIdentifierADM 2.0
mpro7 Nov 15, 2022
9562f54
improved naming
mpro7 Nov 15, 2022
2f97aae
fix cache
mpro7 Nov 15, 2022
8d09cd6
fix tests
mpro7 Nov 15, 2022
ca8bbbf
fix formatting
mpro7 Nov 15, 2022
de980cb
Merge branch 'main' into DEV-1408-dsp-api-make-possible-to-get-projec…
mpro7 Nov 16, 2022
12e1abd
move accessors into trait
mpro7 Nov 16, 2022
2967d9f
improve Base64Uuid value obbject + add tests
mpro7 Nov 16, 2022
ee8b604
improve cahce + add tests
mpro7 Nov 16, 2022
d1125ab
add missing tests + cleanup
mpro7 Nov 16, 2022
68c9aba
review changes
mpro7 Nov 17, 2022
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
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."
mpro7 marked this conversation as resolved.
Show resolved Hide resolved
val PropertyIriMissing = "Property IRI cannot be empty."
}
13 changes: 10 additions & 3 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.
* Gets the last segment of IRI, decodes UUID and gets its version.
* @param s the IRI [[String]] to be checked.
* @return UUID version.
*/
def getUUIDVersion(s: String): Int = {
mpro7 marked this conversation as resolved.
Show resolved Hide resolved
val encodedUUID = s.split("/").last
val encodedUUID = getUuidFromIri(s)
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
28 changes: 27 additions & 1 deletion 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)
mpro7 marked this conversation as resolved.
Show resolved Hide resolved

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

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 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