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

refactor: Use value types in Project #3430

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
300b83c
add properties to knora base and admin ontologies
seakayone Nov 15, 2024
102cac0
sort lines
seakayone Nov 15, 2024
fbd579e
add to knora-api v2
seakayone Nov 15, 2024
d7e1ec1
feat: Add copyright attribution and license to Project
seakayone Nov 15, 2024
2f93730
feat: Add copyright attribution and license to update Project
seakayone Nov 15, 2024
f1389a8
feat: Add copyright attribution and license to test data
seakayone Nov 15, 2024
ab0a6e2
Merge branch 'feat/add-license-and-copyright-attribution-model' into …
seakayone Nov 15, 2024
3efe015
Merge branch 'main' into feat/add-license-and-copyright-attribution-t…
seakayone Nov 15, 2024
97b0377
feat: Introduce StringValues for copyright attribution and license
seakayone Nov 15, 2024
40f825c
Merge branch 'main' into feat/add-license-and-copyright-attribution-t…
seakayone Nov 15, 2024
aec743f
fmt
seakayone Nov 15, 2024
7947c2d
simplify
seakayone Nov 15, 2024
64ce806
refactor: Make Project.shortname typed
seakayone Nov 15, 2024
0ddf7aa
refactor: Make Project.shortcode typed
seakayone Nov 15, 2024
209af47
refactor: Make Project.longname typed
seakayone Nov 15, 2024
3fb6603
refactor: Make Project.logo typed
seakayone Nov 15, 2024
48f6180
refactor: Make Project.selfjoin typed
seakayone Nov 15, 2024
c564346
refactor: Make Project.status typed
seakayone Nov 15, 2024
d418c7b
refactor: Make Project.id typed
seakayone Nov 15, 2024
804e35a
refactor: Make Project.keywords typed
seakayone Nov 15, 2024
02f828c
refactor: Make Project.description typed
seakayone Nov 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ object ProjectEraseIT extends E2EZSpec {
None,
KnoraProject.Status.Active,
KnoraProject.SelfJoin.CanJoin,
None,
None,
),
),
).orDie
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import org.knora.webapi.messages.util.rdf.RdfModel
import org.knora.webapi.sharedtestdata.SharedTestDataADM
import org.knora.webapi.slice.admin.api.model.*
import org.knora.webapi.slice.admin.api.model.ProjectMembersGetResponseADM
import org.knora.webapi.slice.admin.domain.model.KnoraProject.SelfJoin
import org.knora.webapi.slice.admin.domain.model.KnoraProject.Status
import org.knora.webapi.slice.admin.domain.model.User
import org.knora.webapi.util.AkkaHttpUtils
import org.knora.webapi.util.MutableTestIri
Expand All @@ -41,7 +43,7 @@ class ProjectsADME2ESpec extends E2ESpec with SprayJsonSupport {
private val rootEmail = SharedTestDataADM.rootUser.email
private val testPass = SharedTestDataADM.testPass
private val projectIri = SharedTestDataADM.imagesProject.id
private val projectIriEnc = URLEncoder.encode(projectIri, "utf-8")
private val projectIriEnc = URLEncoder.encode(projectIri.value, "utf-8")
private val projectShortname = SharedTestDataADM.imagesProject.shortname
private val projectShortcode = SharedTestDataADM.imagesProject.shortcode

Expand Down Expand Up @@ -235,10 +237,10 @@ class ProjectsADME2ESpec extends E2ESpec with SprayJsonSupport {
result.description should be(Seq(StringLiteralV2.from(value = "project description", language = Some("en"))))
result.keywords should be(Seq("keywords"))
result.logo should be(Some("/fu/bar/baz.jpg"))
result.status should be(true)
result.selfjoin should be(false)
result.status should be(Status.Active)
result.selfjoin should be(SelfJoin.CannotJoin)

newProjectIri.set(result.id)
newProjectIri.set(result.id.value)
}

"return a 'BadRequest' if the supplied project shortname during creation is not unique" in {
Expand Down Expand Up @@ -360,10 +362,10 @@ class ProjectsADME2ESpec extends E2ESpec with SprayJsonSupport {
result.description should be(
Seq(StringLiteralV2.from(value = "updated project description", language = Some("en"))),
)
result.keywords.sorted should be(Seq("updated", "keywords").sorted)
result.keywords.map(_.value).sorted should be(Seq("updated", "keywords").sorted)
result.logo should be(Some("/fu/bar/baz-updated.jpg"))
result.status should be(true)
result.selfjoin should be(true)
result.status should be(Status.Active)
result.selfjoin should be(SelfJoin.CanJoin)
}

"UPDATE a project with multi-language description" in {
Expand Down Expand Up @@ -398,7 +400,7 @@ class ProjectsADME2ESpec extends E2ESpec with SprayJsonSupport {
response.status should be(StatusCodes.OK)

val result: Project = AkkaHttpUtils.httpResponseToJson(response).fields("project").convertTo[Project]
result.status should be(false)
result.status should be(Status.Inactive)
}
}

Expand All @@ -411,8 +413,7 @@ class ProjectsADME2ESpec extends E2ESpec with SprayJsonSupport {
assert(response.status === StatusCodes.OK)
val jsObject = AkkaHttpUtils.httpResponseToJson(response)
val prjMembersResp = jsonReader[ProjectMembersGetResponseADM].read(jsObject)
// val prjMembersResp = jsObject.convertTo[ProjectMembersGetResponseADM]
val members = prjMembersResp.members
val members = prjMembersResp.members
members.size should be(4)
}

Expand Down Expand Up @@ -539,7 +540,7 @@ class ProjectsADME2ESpec extends E2ESpec with SprayJsonSupport {
}

"return all keywords for a single project" in {
val incunabulaIriEnc = URLEncoder.encode(SharedTestDataADM.incunabulaProject.id, "utf-8")
val incunabulaIriEnc = URLEncoder.encode(SharedTestDataADM.incunabulaProject.id.value, "utf-8")
val request = Get(baseApiUrl + s"/admin/projects/iri/$incunabulaIriEnc/Keywords") ~> addCredentials(
BasicHttpCredentials(rootEmail, testPass),
)
Expand All @@ -551,7 +552,7 @@ class ProjectsADME2ESpec extends E2ESpec with SprayJsonSupport {
}

"return empty list for a project without keywords" in {
val dokubibIriEnc = URLEncoder.encode(SharedTestDataADM.dokubibProject.id, "utf-8")
val dokubibIriEnc = URLEncoder.encode(SharedTestDataADM.dokubibProject.id.value, "utf-8")
val request = Get(baseApiUrl + s"/admin/projects/iri/$dokubibIriEnc/Keywords") ~> addCredentials(
BasicHttpCredentials(rootEmail, testPass),
)
Expand All @@ -574,7 +575,7 @@ class ProjectsADME2ESpec extends E2ESpec with SprayJsonSupport {

"used to dump project data" should {
"return a TriG file containing all data from a project" in {
val anythingProjectIriEnc = URLEncoder.encode(SharedTestDataADM.anythingProject.id, "utf-8")
val anythingProjectIriEnc = URLEncoder.encode(SharedTestDataADM.anythingProject.id.value, "utf-8")
val request = Get(baseApiUrl + s"/admin/projects/iri/$anythingProjectIriEnc/AllData") ~> addCredentials(
BasicHttpCredentials(SharedTestDataADM.anythingAdminUser.email, testPass),
)
Expand All @@ -599,7 +600,7 @@ class ProjectsADME2ESpec extends E2ESpec with SprayJsonSupport {

"used to set RestrictedViewSize by project IRI" should {
"return requested value to be set with 200 Response Status" in {
val encodedIri = URLEncoder.encode(SharedTestDataADM.imagesProject.id, "utf-8")
val encodedIri = URLEncoder.encode(SharedTestDataADM.imagesProject.id.value, "utf-8")
val payload = """{"size":"pct:1"}"""
val request =
Post(
Expand All @@ -614,7 +615,7 @@ class ProjectsADME2ESpec extends E2ESpec with SprayJsonSupport {
}

"return the `BadRequest` if the size value is invalid" in {
val encodedIri = URLEncoder.encode(SharedTestDataADM.imagesProject.id, "utf-8")
val encodedIri = URLEncoder.encode(SharedTestDataADM.imagesProject.id.value, "utf-8")
val payload = """{"size":"pct:0"}"""
val request =
Post(
Expand All @@ -630,7 +631,7 @@ class ProjectsADME2ESpec extends E2ESpec with SprayJsonSupport {
}

"return `Forbidden` for the user who is not a system nor project admin" in {
val encodedIri = URLEncoder.encode(SharedTestDataADM.imagesProject.id, "utf-8")
val encodedIri = URLEncoder.encode(SharedTestDataADM.imagesProject.id.value, "utf-8")
val payload = """{"size":"pct:1"}"""
val request =
Post(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class UsersADME2ESpec extends E2ESpec with SprayJsonSupport {
private val multiUserIriEnc = java.net.URLEncoder.encode(multiUserIri, "utf-8")

private val imagesProjectIri = SharedTestDataADM.imagesProject.id
private val imagesProjectIriEnc = java.net.URLEncoder.encode(imagesProjectIri, "utf-8")
private val imagesProjectIriEnc = java.net.URLEncoder.encode(imagesProjectIri.value, "utf-8")

private val imagesReviewerGroupIri = SharedTestDataADM.imagesReviewerGroup.id
private val imagesReviewerGroupIriEnc = java.net.URLEncoder.encode(imagesReviewerGroupIri, "utf-8")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import org.knora.webapi.messages.util.rdf.RdfFormatUtil
import org.knora.webapi.messages.util.rdf.Turtle
import org.knora.webapi.sharedtestdata.SharedOntologyTestDataADM
import org.knora.webapi.sharedtestdata.SharedTestDataADM
import org.knora.webapi.slice.common.Value.StringValue
import org.knora.webapi.util.*

class OntologyFormatsE2ESpec extends E2ESpec {
Expand Down Expand Up @@ -73,8 +74,8 @@ class OntologyFormatsE2ESpec extends E2ESpec {
}
}

private def urlEncodeIri(iri: IRI): String =
URLEncoder.encode(iri, "UTF-8")
private def urlEncodeIri(iri: StringValue): String = URLEncoder.encode(iri.value, "UTF-8")
private def urlEncodeIri(iri: IRI): String = URLEncoder.encode(iri, "UTF-8")

private def checkTestCase(httpGetTest: HttpGetTest) = {
val responseJsonLd = getResponse(httpGetTest.urlPath, RdfMediaTypes.`application/ld+json`)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ class ResourcesRouteV2E2ESpec extends E2ESpec {
val orderByProperty = URLEncoder.encode("http://0.0.0.0:3333/ontology/0803/incunabula/v2#title", "UTF-8")
val request =
Get(s"$baseApiUrl/v2/resources?resourceClass=$resourceClass&orderByProperty=$orderByProperty&page=0")
.addHeader(new ProjectHeader(SharedTestDataADM.incunabulaProject.id)) ~> addCredentials(
.addHeader(new ProjectHeader(SharedTestDataADM.incunabulaProject.id.value)) ~> addCredentials(
BasicHttpCredentials(SharedTestDataADM.incunabulaProjectAdminUser.email, password),
)
val response: HttpResponse = singleAwaitingRequest(request)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,27 @@ import org.knora.webapi.messages.admin.responder.usersmessages.UserProjectAdminM
import org.knora.webapi.messages.admin.responder.usersmessages.UserProjectMembershipsGetResponseADM
import org.knora.webapi.messages.admin.responder.usersmessages.UserResponseADM
import org.knora.webapi.messages.admin.responder.usersmessages.UsersGetResponseADM
import org.knora.webapi.messages.store.triplestoremessages.StringLiteralV2
import org.knora.webapi.messages.store.triplestoremessages.TriplestoreJsonProtocol
import org.knora.webapi.slice.admin.api.model.Project
import org.knora.webapi.slice.admin.api.model.ProjectAdminMembersGetResponseADM
import org.knora.webapi.slice.admin.api.model.ProjectMembersGetResponseADM
import org.knora.webapi.slice.admin.api.model.ProjectOperationResponseADM
import org.knora.webapi.slice.admin.domain.model.Group
import org.knora.webapi.slice.admin.domain.model.KnoraProject.CopyrightAttribution
import org.knora.webapi.slice.admin.domain.model.KnoraProject.Description
import org.knora.webapi.slice.admin.domain.model.KnoraProject.Keyword
import org.knora.webapi.slice.admin.domain.model.KnoraProject.License
import org.knora.webapi.slice.admin.domain.model.KnoraProject.Logo
import org.knora.webapi.slice.admin.domain.model.KnoraProject.Longname
import org.knora.webapi.slice.admin.domain.model.KnoraProject.ProjectIri
import org.knora.webapi.slice.admin.domain.model.KnoraProject.SelfJoin
import org.knora.webapi.slice.admin.domain.model.KnoraProject.Shortcode
import org.knora.webapi.slice.admin.domain.model.KnoraProject.Shortname
import org.knora.webapi.slice.admin.domain.model.KnoraProject.Status
import org.knora.webapi.slice.admin.domain.model.User
import org.knora.webapi.slice.common.Value.BooleanValue
import org.knora.webapi.slice.common.Value.StringValue

/**
* A spray-json protocol for generating Knora API JSON providing data about projects.
Expand Down Expand Up @@ -189,9 +203,74 @@ object IntegrationTestAdminJsonProtocol extends TriplestoreJsonProtocol {
"ontologies",
"status",
"selfjoin",
"copyrightAttribution",
"license",
),
)

implicit object DescriptionFormat extends JsonFormat[Description] with TriplestoreJsonProtocol {
val lit = implicitly[JsonFormat[StringLiteralV2]]
override def write(obj: Description): JsValue = lit.write(obj.value)
override def read(json: JsValue): Description = Description
.from(lit.read(json))
.fold(err => throw DeserializationException(err), identity)
}
trait StringValueFormat[T <: StringValue] extends JsonFormat[T] { self =>
def from: String => Either[String, T]
override def write(v: T): JsValue = JsString(v.value)
override def read(json: JsValue): T = json match
case JsString(str) => self.from(str).fold(err => throw DeserializationException(err), identity)
case _ => throw DeserializationException("Must be a json String")
}

implicit object ProjectIriFormat extends StringValueFormat[ProjectIri] {
override val from: String => Either[String, ProjectIri] = ProjectIri.from
}

implicit object CopyrightAttributionFormat extends StringValueFormat[CopyrightAttribution] {
override val from: String => Either[String, CopyrightAttribution] = CopyrightAttribution.from
}

implicit object LicenseFormat extends StringValueFormat[License] {
override val from: String => Either[String, License] = License.from
}

implicit object ShortnameFormat extends StringValueFormat[Shortname] {
override val from: String => Either[String, Shortname] = Shortname.from
}

implicit object ShortcodeFormat extends StringValueFormat[Shortcode] {
override val from: String => Either[String, Shortcode] = Shortcode.from
}

implicit object LongnameFormat extends StringValueFormat[Longname] {
override val from: String => Either[String, Longname] = Longname.from
}

implicit object LogoFormat extends StringValueFormat[Logo] {
override val from: String => Either[String, Logo] = Logo.from
}

implicit object KeywordFormat extends StringValueFormat[Keyword] {
override val from: String => Either[String, Keyword] = Keyword.from
}

trait BooleanValueFormat[T <: BooleanValue] extends JsonFormat[T] { self =>
def from: Boolean => T
override def write(v: T): JsValue = JsString(v.value.toString)
override def read(json: JsValue): T = json match
case JsBoolean(bool) => self.from(bool)
case _ => throw DeserializationException("Must be a json Boolean")
}

implicit object SelfJoinValueFormat extends BooleanValueFormat[SelfJoin] {
override val from: Boolean => SelfJoin = SelfJoin.from
}

implicit object StatusFormat extends BooleanValueFormat[Status] {
override val from: Boolean => Status = Status.from
}

implicit val groupFormat: JsonFormat[Group] = jsonFormat6(Group.apply)

implicit val projectAdminMembersGetResponseADMFormat: RootJsonFormat[ProjectAdminMembersGetResponseADM] = rootFormat(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class PermissionsMessagesADMSpec extends CoreSpec {
val exit = UnsafeZioRun.run(
PermissionRestService.createAdministrativePermission(
CreateAdministrativePermissionAPIRequestADM(
forProject = SharedTestDataADM.imagesProjectIri,
forProject = SharedTestDataADM.imagesProjectIri.value,
forGroup = groupIri,
hasPermissions = Set(PermissionADM.from(Permission.Administrative.ProjectAdminAll)),
),
Expand All @@ -61,7 +61,7 @@ class PermissionsMessagesADMSpec extends CoreSpec {
PermissionRestService.createAdministrativePermission(
CreateAdministrativePermissionAPIRequestADM(
id = Some(permissionIri),
forProject = SharedTestDataADM.imagesProjectIri,
forProject = SharedTestDataADM.imagesProjectIri.value,
forGroup = KnoraGroupRepo.builtIn.ProjectMember.id.value,
hasPermissions = Set(PermissionADM.from(Permission.Administrative.ProjectAdminAll)),
),
Expand All @@ -83,7 +83,7 @@ class PermissionsMessagesADMSpec extends CoreSpec {
val exit = UnsafeZioRun.run(
PermissionRestService.createAdministrativePermission(
CreateAdministrativePermissionAPIRequestADM(
forProject = SharedTestDataADM.imagesProjectIri,
forProject = SharedTestDataADM.imagesProjectIri.value,
forGroup = KnoraGroupRepo.builtIn.ProjectMember.id.value,
hasPermissions = hasPermissions,
),
Expand All @@ -101,7 +101,7 @@ class PermissionsMessagesADMSpec extends CoreSpec {
val exit = UnsafeZioRun.run(
PermissionRestService.createAdministrativePermission(
CreateAdministrativePermissionAPIRequestADM(
forProject = SharedTestDataADM.imagesProjectIri,
forProject = SharedTestDataADM.imagesProjectIri.value,
forGroup = KnoraGroupRepo.builtIn.ProjectMember.id.value,
hasPermissions = Set.empty[PermissionADM],
),
Expand All @@ -115,7 +115,7 @@ class PermissionsMessagesADMSpec extends CoreSpec {
val exit = UnsafeZioRun.run(
PermissionRestService.createAdministrativePermission(
CreateAdministrativePermissionAPIRequestADM(
forProject = SharedTestDataADM.imagesProjectIri,
forProject = SharedTestDataADM.imagesProjectIri.value,
forGroup = KnoraGroupRepo.builtIn.ProjectMember.id.value,
hasPermissions = Set(PermissionADM.from(Permission.Administrative.ProjectAdminAll)),
),
Expand Down Expand Up @@ -153,7 +153,7 @@ class PermissionsMessagesADMSpec extends CoreSpec {
val exit = UnsafeZioRun.run(
PermissionRestService.createDefaultObjectAccessPermission(
CreateDefaultObjectAccessPermissionAPIRequestADM(
forProject = SharedTestDataADM.imagesProjectIri,
forProject = SharedTestDataADM.imagesProjectIri.value,
forGroup = Some(groupIri),
hasPermissions = Set(
PermissionADM.from(Permission.ObjectAccess.ChangeRights, KnoraGroupRepo.builtIn.ProjectMember.id.value),
Expand All @@ -171,7 +171,7 @@ class PermissionsMessagesADMSpec extends CoreSpec {
PermissionRestService.createDefaultObjectAccessPermission(
CreateDefaultObjectAccessPermissionAPIRequestADM(
id = Some(permissionIri),
forProject = SharedTestDataADM.imagesProjectIri,
forProject = SharedTestDataADM.imagesProjectIri.value,
forGroup = Some(KnoraGroupRepo.builtIn.ProjectMember.id.value),
hasPermissions = Set(
PermissionADM.from(Permission.ObjectAccess.ChangeRights, KnoraGroupRepo.builtIn.ProjectMember.id.value),
Expand All @@ -187,7 +187,7 @@ class PermissionsMessagesADMSpec extends CoreSpec {
val exit = UnsafeZioRun.run(
PermissionRestService.createDefaultObjectAccessPermission(
CreateDefaultObjectAccessPermissionAPIRequestADM(
forProject = SharedTestDataADM.imagesProjectIri,
forProject = SharedTestDataADM.imagesProjectIri.value,
forGroup = Some(SharedTestDataADM.thingSearcherGroup.id),
hasPermissions = Set.empty[PermissionADM],
),
Expand Down Expand Up @@ -289,7 +289,7 @@ class PermissionsMessagesADMSpec extends CoreSpec {
val exit = UnsafeZioRun.run(
PermissionRestService.createDefaultObjectAccessPermission(
CreateDefaultObjectAccessPermissionAPIRequestADM(
forProject = SharedTestDataADM.anythingProjectIri,
forProject = SharedTestDataADM.anythingProjectIri.value,
forGroup = Some(SharedTestDataADM.thingSearcherGroup.id),
hasPermissions =
Set(PermissionADM.from(Permission.ObjectAccess.RestrictedView, SharedTestDataADM.thingSearcherGroup.id)),
Expand Down
Loading
Loading