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(v3): add role slice (DEV-1010) #2099

Merged
merged 24 commits into from Jul 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
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
72 changes: 72 additions & 0 deletions build.sbt
Expand Up @@ -242,6 +242,76 @@ lazy val valueObjects = project
testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework"))
)

// Role projects

lazy val roleInterface = project
.in(file("dsp-role/interface"))
.settings(
scalacOptions ++= Seq(
"-feature",
"-unchecked",
"-deprecation",
"-Yresolve-term-conflict:package",
"-Ymacro-annotations"
),
name := "roleInterface",
libraryDependencies ++= Dependencies.roleInterfaceLibraryDependencies,
testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework"))
)
.dependsOn(shared, roleHandler)

lazy val roleHandler = project
.in(file("dsp-role/handler"))
.settings(
scalacOptions ++= Seq(
"-feature",
"-unchecked",
"-deprecation",
"-Yresolve-term-conflict:package",
"-Ymacro-annotations"
),
name := "roleHandler",
libraryDependencies ++= Dependencies.roleHandlerLibraryDependencies,
testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework"))
)
.dependsOn(
shared,
roleCore % "compile->compile;test->test",
roleRepo % "test->test"
)

lazy val roleRepo = project
.in(file("dsp-role/repo"))
.settings(
scalacOptions ++= Seq(
"-feature",
"-unchecked",
"-deprecation",
"-Yresolve-term-conflict:package",
"-Ymacro-annotations"
),
name := "roleRepo",
libraryDependencies ++= Dependencies.roleRepoLibraryDependencies,
testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework"))
)
.dependsOn(shared, roleCore % "compile->compile;test->test")

lazy val roleCore = project
.in(file("dsp-role/core"))
.settings(
scalacOptions ++= Seq(
"-feature",
"-unchecked",
"-deprecation",
"-Yresolve-term-conflict:package",
"-Ymacro-annotations"
),
name := "roleCore",
libraryDependencies ++= Dependencies.roleCoreLibraryDependencies,
testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework"))
)
.dependsOn(shared)

// User projects

lazy val userInterface = project
Expand Down Expand Up @@ -312,6 +382,8 @@ lazy val userCore = project
)
.dependsOn(shared)

// Shared project

lazy val shared = project
.in(file("dsp-shared"))
.settings(
Expand Down
53 changes: 53 additions & 0 deletions dsp-role/core/src/main/scala/dsp/role/api/RoleRepo.scala
@@ -0,0 +1,53 @@
/*
* Copyright © 2021 - 2022 Data and Service Center for the Humanities and/or DaSCH Service Platform contributors.
* SPDX-License-Identifier: Apache-2.0
*/

package dsp.role.api

import dsp.role.domain.Role
import dsp.valueobjects.Id.RoleId
import zio._
import zio.macros.accessible

/**
* The trait (interface) for the role repository.
* The role repository is responsible for storing and retrieving roles.
* Needs to be used by the role repository implementations.
*/
@accessible
trait RoleRepo {

/**
* Writes a role into the repository, while both creating or updating a role.
*
* @param r the [[Role]] to write
* @return the [[RoleId]]
*/
def storeRole(role: Role): UIO[RoleId]

/**
* Gets all roles from the repository.
*
* @return a list of [[Role]]
*/
def getRoles(): UIO[List[Role]]

/**
* Retrieves a role from the repository.
*
* @param id the role's ID
* @return the [[Role]] if found
*/
def getRoleById(id: RoleId): IO[Option[Nothing], Role]

// should the role name be unique like username???

/**
* Deletes the [[Role]] from the repository by its [[RoleId]]
*
* @param id the role ID
* @return the [[RoleId]] of the deleted role, if found
*/
def deleteRole(id: RoleId): IO[Option[Nothing], RoleId]
}
122 changes: 122 additions & 0 deletions dsp-role/core/src/main/scala/dsp/role/domain/RoleDomain.scala
@@ -0,0 +1,122 @@
/*
* Copyright © 2021 - 2022 Data and Service Center for the Humanities and/or DaSCH Service Platform contributors.
* SPDX-License-Identifier: Apache-2.0
*/

package dsp.role.domain

import dsp.errors.BadRequestException
import dsp.valueobjects.Id.RoleId
import dsp.valueobjects.Id.UserId
import dsp.valueobjects.Permission
import dsp.valueobjects.Role._
import zio.prelude.Validation

case class RoleUser(
id: UserId
)

/**
* Role's domain entity.
*
* @param id the role's ID
* @param name the role's name
* @param description the role's description
* @param users the role's users
* @param permission the role's permission
*/
sealed abstract case class Role private (
id: RoleId,
name: LangString,
description: LangString,
users: List[RoleUser], // how to reperesnt the user here?
permission: Permission
) extends Ordered[Role] { self =>

/**
* Allows to compare the [[Role]] instances.
*
* @param that [[Role]] to compare
* @return [[Boolean]] value
*/
def compare(that: Role): Int = self.id.iri.toString().compareTo(that.id.iri.toString())

/**
* Updates the role's name with new value.
*
* @param newValue new role's name to update
* @return updated [[Role]]
*/
def updateName(newValue: LangString): Validation[BadRequestException, Role] =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def updateName(newValue: LangString): Validation[BadRequestException, Role] =
def updateName(name: LangString): Validation[BadRequestException, Role] =

would be more expressive, maybe even newName?

Copy link
Collaborator Author

@mpro7 mpro7 Jul 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In opposite to that r: Role here maybe the param name could be name/newName, because type doesn't say what it is, but:

  • def updateName(newValue: LangString) is very clear the method will update the Name and requires its new value in LangString type to be passed
  • we have the docString which clarify it even more
  • followed the convention we have in user slice

Role.make(
self.id,
newValue,
self.description,
self.users,
self.permission
)

/**
* Updates the role's description with new value.
*
* @param newValue new role's description to update
* @return updated [[Role]]
*/
def updateDescription(newValue: LangString): Validation[BadRequestException, Role] =
mpro7 marked this conversation as resolved.
Show resolved Hide resolved
Role.make(
self.id,
self.name,
newValue,
self.users,
self.permission
)

/**
* Updates the role's users with new value.
*
* @param newValue new role's users to update
* @return updated [[Role]]
*/
def updateUsers(newValue: List[RoleUser]): Validation[BadRequestException, Role] =
mpro7 marked this conversation as resolved.
Show resolved Hide resolved
Role.make(
self.id,
self.name,
self.description,
newValue,
self.permission
)

/**
* Updates the role's permission with new value.
*
* @param newValue new role's permission to update
* @return updated [[Role]]
*/
def updatePermission(newValue: Permission): Validation[BadRequestException, Role] =
mpro7 marked this conversation as resolved.
Show resolved Hide resolved
Role.make(
self.id,
self.name,
self.description,
self.users,
newValue
)
}

object Role {
def make(
id: RoleId,
name: LangString,
description: LangString,
users: List[RoleUser],
permission: Permission
): Validation[BadRequestException, Role] =
Validation.succeed(
new Role(
id,
name,
description,
users,
permission
) {}
)
}
11 changes: 11 additions & 0 deletions dsp-role/core/src/test/scala/dsp/role/api/RoleApiSpec.scala
@@ -0,0 +1,11 @@
/*
* Copyright © 2021 - 2022 Data and Service Center for the Humanities and/or DaSCH Service Platform contributors.
* SPDX-License-Identifier: Apache-2.0
*/

package dsp.role.api

/**
* To be implemented...
*/
object placeholder {}
111 changes: 111 additions & 0 deletions dsp-role/core/src/test/scala/dsp/role/domain/RoleDomainSpec.scala
@@ -0,0 +1,111 @@
/*
* Copyright © 2021 - 2022 Data and Service Center for the Humanities and/or DaSCH Service Platform contributors.
* SPDX-License-Identifier: Apache-2.0
*/

package dsp.role.domain

import dsp.role.sharedtestdata.RoleTestData
import dsp.valueobjects.Id
import dsp.valueobjects.Permission
import dsp.valueobjects.Role._
import zio.test._

/**
* This spec is used to test [[RoleDomain]].
*/
object RoleDomainSpec extends ZIOSpecDefault {
def spec = (compareRolesTest + createRoleTest + updateRoleTest)

private val compareRolesTest = suite("compareRoles")(
test("compare two roles") {
val role = RoleTestData.role1
val equalRole = RoleTestData.role1
val nonEqualRole = RoleTestData.role2

assertTrue(role == equalRole) &&
assertTrue(role != nonEqualRole)
}
)

private val createRoleTest = suite("createRole")(
test("create a role") {
(
for {
id <- RoleTestData.id1
name <- RoleTestData.name1
description <- RoleTestData.description1
users = RoleTestData.users1
permission <- RoleTestData.permission1
mpro7 marked this conversation as resolved.
Show resolved Hide resolved

role <- Role.make(
id,
name,
description,
users = users,
permission
)
} yield assertTrue(role.id == id) &&
assertTrue(role.name == name) &&
assertTrue(role.description == description) &&
assertTrue(role.users == users) &&
assertTrue(role.permission == permission)
).toZIO
}
)

private val updateRoleTest = suite("updateRole")(
test("update the name") {
(
for {
role <- RoleTestData.role1
newValue <- LangString.make("newRoleName", "en")
updatedRole <- role.updateName(newValue)
} yield assertTrue(updatedRole.name == newValue) &&
assertTrue(updatedRole.name != role.name) &&
assertTrue(updatedRole.description == role.description) &&
assertTrue(updatedRole.users == role.users) &&
assertTrue(updatedRole.permission == role.permission)
).toZIO
},
test("update the description") {
(
for {
role <- RoleTestData.role1
newValue <- LangString.make("New Role Description", "en")
updatedRole <- role.updateDescription(newValue)
} yield assertTrue(updatedRole.name == role.name) &&
assertTrue(updatedRole.description == newValue) &&
assertTrue(updatedRole.description != role.description) &&
assertTrue(updatedRole.users == role.users) &&
assertTrue(updatedRole.permission == role.permission)
).toZIO
},
test("update the users") {
(
for {
role <- RoleTestData.role1
newValue = List(RoleUser(Id.UserId.make().fold(e => throw e.head, v => v)))
updatedRole <- role.updateUsers(newValue)
} yield assertTrue(updatedRole.name == role.name) &&
assertTrue(updatedRole.description == role.description) &&
assertTrue(updatedRole.users == newValue) &&
assertTrue(updatedRole.users != role.users) &&
assertTrue(updatedRole.permission == role.permission)
).toZIO
},
test("update the permission") {
(
for {
role <- RoleTestData.role1
newValue <- Permission.make(Permission.Create)
updatedRole <- role.updatePermission(newValue)
} yield assertTrue(updatedRole.name == role.name) &&
assertTrue(updatedRole.description == role.description) &&
assertTrue(updatedRole.users == role.users) &&
assertTrue(updatedRole.permission == newValue) &&
assertTrue(updatedRole.permission != role.permission)
).toZIO
}
)
}