diff --git a/api/app/src/main/kotlin/packit/controllers/RoleController.kt b/api/app/src/main/kotlin/packit/controllers/RoleController.kt index 5a517240..d4a91816 100644 --- a/api/app/src/main/kotlin/packit/controllers/RoleController.kt +++ b/api/app/src/main/kotlin/packit/controllers/RoleController.kt @@ -6,6 +6,9 @@ import org.springframework.stereotype.Controller import org.springframework.validation.annotation.Validated import org.springframework.web.bind.annotation.* import packit.model.dto.CreateRole +import packit.model.dto.RoleDto +import packit.model.dto.UpdateRolePermissions +import packit.model.toDto import packit.service.RoleService @Controller @@ -21,13 +24,44 @@ class RoleController(private val roleService: RoleService) return ResponseEntity.ok(mapOf("message" to "Role created")) } - @DeleteMapping("/{name}") + @DeleteMapping("/{roleName}") fun deleteRole( - @PathVariable name: String + @PathVariable roleName: String + ): ResponseEntity> + { + roleService.deleteRole(roleName) + + return ResponseEntity.noContent().build() + } + + @PutMapping("/update-permissions/{roleName}") + fun updatePermissionsToRole( + @RequestBody @Validated updateRolePermissions: UpdateRolePermissions, + @PathVariable roleName: String ): ResponseEntity { - roleService.deleteRole(name) + roleService.updatePermissionsToRole(roleName, updateRolePermissions) return ResponseEntity.noContent().build() } + + @GetMapping("/names") + fun getRoleNames(): ResponseEntity> + { + return ResponseEntity.ok(roleService.getRoleNames()) + } + + @GetMapping + fun getRolesWithRelationships(@RequestParam isUsername: Boolean?): ResponseEntity> + { + val roles = roleService.getRoles(isUsername) + return ResponseEntity.ok(roles.map { it.toDto() }) + } + + @GetMapping("/{roleName}") + fun getRole(@PathVariable roleName: String): ResponseEntity + { + val role = roleService.getRole(roleName) + return ResponseEntity.ok(role.toDto()) + } } diff --git a/api/app/src/main/kotlin/packit/exceptions/PackitExceptionHandler.kt b/api/app/src/main/kotlin/packit/exceptions/PackitExceptionHandler.kt index 07ebee20..ccb9c0b5 100644 --- a/api/app/src/main/kotlin/packit/exceptions/PackitExceptionHandler.kt +++ b/api/app/src/main/kotlin/packit/exceptions/PackitExceptionHandler.kt @@ -53,6 +53,13 @@ class PackitExceptionHandler .toResponseEntity() } + @ExceptionHandler(IllegalArgumentException::class) + fun handleIllegalArgumentException(e: Exception): ResponseEntity + { + return ErrorDetail(HttpStatus.BAD_REQUEST, e.message ?: "Invalid argument") + .toResponseEntity() + } + @ExceptionHandler(AccessDeniedException::class, AuthenticationException::class) fun handleAccessDenied(e: Exception): ResponseEntity { diff --git a/api/app/src/main/kotlin/packit/model/Packet.kt b/api/app/src/main/kotlin/packit/model/Packet.kt index 4cae07d3..ef9e6ff0 100644 --- a/api/app/src/main/kotlin/packit/model/Packet.kt +++ b/api/app/src/main/kotlin/packit/model/Packet.kt @@ -3,6 +3,7 @@ package packit.model import jakarta.persistence.* import org.hibernate.annotations.JdbcTypeCode import org.hibernate.type.SqlTypes +import packit.model.dto.BasicPacketDto import packit.model.dto.PacketDto @Entity @@ -32,3 +33,5 @@ class Packet( fun Packet.toDto() = PacketDto( id, name, displayName, parameters, published, importTime, startTime, endTime ) + +fun Packet.toBasicDto() = BasicPacketDto(name, id) diff --git a/api/app/src/main/kotlin/packit/model/PacketGroup.kt b/api/app/src/main/kotlin/packit/model/PacketGroup.kt index 81a22edc..f852699e 100644 --- a/api/app/src/main/kotlin/packit/model/PacketGroup.kt +++ b/api/app/src/main/kotlin/packit/model/PacketGroup.kt @@ -1,14 +1,17 @@ package packit.model import jakarta.persistence.* +import packit.model.dto.PacketGroupDto @Entity @Table(name = "packet_group") class PacketGroup( var name: String, - @OneToMany(mappedBy = "packetGroup") + @OneToMany(mappedBy = "packetGroup", cascade = [CascadeType.ALL]) var rolePermissions: MutableList = mutableListOf(), @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Int? = null ) + +fun PacketGroup.toDto() = PacketGroupDto(name, id!!) diff --git a/api/app/src/main/kotlin/packit/model/Role.kt b/api/app/src/main/kotlin/packit/model/Role.kt index 7b76ef77..efa0ffc4 100644 --- a/api/app/src/main/kotlin/packit/model/Role.kt +++ b/api/app/src/main/kotlin/packit/model/Role.kt @@ -1,6 +1,7 @@ package packit.model import jakarta.persistence.* +import packit.model.dto.RoleDto @Entity @Table(name = "`role`") @@ -9,9 +10,14 @@ class Role( var isUsername: Boolean = false, @OneToMany(mappedBy = "role", fetch = FetchType.EAGER, cascade = [CascadeType.ALL]) var rolePermissions: MutableList = mutableListOf(), - @ManyToMany(mappedBy = "roles", fetch = FetchType.LAZY) + @ManyToMany(mappedBy = "roles", fetch = FetchType.EAGER) var users: MutableList = mutableListOf(), @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Int? = null, ) + +fun Role.toDto() = + RoleDto( + name, rolePermissions.map { it.toDto() }, users.map { it.toDto() }, id!! + ) diff --git a/api/app/src/main/kotlin/packit/model/RolePermission.kt b/api/app/src/main/kotlin/packit/model/RolePermission.kt index c7e4b826..4824068f 100644 --- a/api/app/src/main/kotlin/packit/model/RolePermission.kt +++ b/api/app/src/main/kotlin/packit/model/RolePermission.kt @@ -1,6 +1,7 @@ package packit.model import jakarta.persistence.* +import packit.model.dto.RolePermissionDto @Entity @Table(name = "role_permission") @@ -29,3 +30,46 @@ class RolePermission( @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Int? = null, ) +{ + init + { + val nonNullFields = listOf(packet, tag, packetGroup).count { it != null } + require(nonNullFields <= 1) { + "Either all of packet, tag, packetGroup should be null or only one of them should be not null" + } + } + + override fun equals(other: Any?): Boolean + { + return when + { + this === other -> true + other !is RolePermission -> false + role.name != other.role.name -> false + permission.name != other.permission.name -> false + packet?.id != other.packet?.id -> false + packetGroup?.id != other.packetGroup?.id -> false + tag?.id != other.tag?.id -> false + else -> true + } + } + + override fun hashCode(): Int + { + val prime = 31 + var result = role.name.hashCode() + result = prime * result + permission.name.hashCode() + result = prime * result + packet?.id.hashCode() + result = prime * result + packetGroup?.id.hashCode() + result = prime * result + tag?.id.hashCode() + return result + } +} + +fun RolePermission.toDto() = RolePermissionDto( + permission.name, + packet?.toBasicDto(), + tag?.toDto(), + packetGroup?.toDto(), + id!! +) diff --git a/api/app/src/main/kotlin/packit/model/Tag.kt b/api/app/src/main/kotlin/packit/model/Tag.kt index 9b1fd26b..15359dea 100644 --- a/api/app/src/main/kotlin/packit/model/Tag.kt +++ b/api/app/src/main/kotlin/packit/model/Tag.kt @@ -1,6 +1,7 @@ package packit.model import jakarta.persistence.* +import packit.model.dto.TagDto @Entity @Table(name = "tag") @@ -14,3 +15,5 @@ class Tag( @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Int? = null, ) + +fun Tag.toDto() = TagDto(name, id!!) diff --git a/api/app/src/main/kotlin/packit/model/User.kt b/api/app/src/main/kotlin/packit/model/User.kt index e9f0ec27..abc935a3 100644 --- a/api/app/src/main/kotlin/packit/model/User.kt +++ b/api/app/src/main/kotlin/packit/model/User.kt @@ -1,6 +1,7 @@ package packit.model import jakarta.persistence.* +import packit.model.dto.UserDto import java.time.Instant import java.util.* @@ -25,3 +26,5 @@ class User( @GeneratedValue(strategy = GenerationType.UUID) val id: UUID? = null ) + +fun User.toDto() = UserDto(username, id!!) diff --git a/api/app/src/main/kotlin/packit/model/dto/BasicPacketDto.kt b/api/app/src/main/kotlin/packit/model/dto/BasicPacketDto.kt new file mode 100644 index 00000000..a38b0f51 --- /dev/null +++ b/api/app/src/main/kotlin/packit/model/dto/BasicPacketDto.kt @@ -0,0 +1,6 @@ +package packit.model.dto + +data class BasicPacketDto( + val name: String, + val id: String, +) diff --git a/api/app/src/main/kotlin/packit/model/dto/PacketGroupDto.kt b/api/app/src/main/kotlin/packit/model/dto/PacketGroupDto.kt new file mode 100644 index 00000000..a8f6c8c9 --- /dev/null +++ b/api/app/src/main/kotlin/packit/model/dto/PacketGroupDto.kt @@ -0,0 +1,3 @@ +package packit.model.dto + +data class PacketGroupDto(val name: String, val id: Int) diff --git a/api/app/src/main/kotlin/packit/model/dto/RoleDto.kt b/api/app/src/main/kotlin/packit/model/dto/RoleDto.kt new file mode 100644 index 00000000..09843780 --- /dev/null +++ b/api/app/src/main/kotlin/packit/model/dto/RoleDto.kt @@ -0,0 +1,8 @@ +package packit.model.dto + +data class RoleDto( + var name: String, + var rolePermissions: List = listOf(), + var users: List = listOf(), + var id: Int +) diff --git a/api/app/src/main/kotlin/packit/model/dto/RolePermissionDto.kt b/api/app/src/main/kotlin/packit/model/dto/RolePermissionDto.kt new file mode 100644 index 00000000..1895695c --- /dev/null +++ b/api/app/src/main/kotlin/packit/model/dto/RolePermissionDto.kt @@ -0,0 +1,9 @@ +package packit.model.dto + +data class RolePermissionDto( + val permission: String, + val packet: BasicPacketDto? = null, + val tag: TagDto? = null, + val packetGroup: PacketGroupDto? = null, + val id: Int, +) diff --git a/api/app/src/main/kotlin/packit/model/dto/TagDto.kt b/api/app/src/main/kotlin/packit/model/dto/TagDto.kt new file mode 100644 index 00000000..e359f932 --- /dev/null +++ b/api/app/src/main/kotlin/packit/model/dto/TagDto.kt @@ -0,0 +1,3 @@ +package packit.model.dto + +data class TagDto(val name: String, val id: Int) diff --git a/api/app/src/main/kotlin/packit/model/dto/UpdateRolePermission.kt b/api/app/src/main/kotlin/packit/model/dto/UpdateRolePermission.kt new file mode 100644 index 00000000..8fa5b2a3 --- /dev/null +++ b/api/app/src/main/kotlin/packit/model/dto/UpdateRolePermission.kt @@ -0,0 +1,25 @@ +package packit.model.dto + +import org.jetbrains.annotations.NotNull + +data class UpdateRolePermissions( + val addPermissions: List = listOf(), + val removePermissions: List = listOf() +) + +data class UpdateRolePermission( + @field:NotNull + val permission: String, + val packetId: String? = null, + val tagId: Int? = null, + val packetGroupId: Int? = null +) +{ + init + { + val nonNullFields = listOf(packetId, tagId, packetGroupId).count { it != null } + require(nonNullFields <= 1) { + "Either all of packetId, tagId, packetGroupId should be null or only one of them should be not null" + } + } +} diff --git a/api/app/src/main/kotlin/packit/model/dto/UserDto.kt b/api/app/src/main/kotlin/packit/model/dto/UserDto.kt new file mode 100644 index 00000000..ac3d020a --- /dev/null +++ b/api/app/src/main/kotlin/packit/model/dto/UserDto.kt @@ -0,0 +1,5 @@ +package packit.model.dto + +import java.util.* + +data class UserDto(val username: String, val id: UUID) diff --git a/api/app/src/main/kotlin/packit/repository/PermissionRepository.kt b/api/app/src/main/kotlin/packit/repository/PermissionRepository.kt index e3cea30f..2d292a6f 100644 --- a/api/app/src/main/kotlin/packit/repository/PermissionRepository.kt +++ b/api/app/src/main/kotlin/packit/repository/PermissionRepository.kt @@ -8,4 +8,5 @@ import packit.model.Permission interface PermissionRepository : JpaRepository { fun findByNameIn(names: List): List + fun findByName(name: String): Permission? } diff --git a/api/app/src/main/kotlin/packit/repository/RolePermissionRepository.kt b/api/app/src/main/kotlin/packit/repository/RolePermissionRepository.kt new file mode 100644 index 00000000..921e251a --- /dev/null +++ b/api/app/src/main/kotlin/packit/repository/RolePermissionRepository.kt @@ -0,0 +1,17 @@ +package packit.repository + +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Modifying +import org.springframework.data.jpa.repository.Query +import org.springframework.stereotype.Repository +import org.springframework.transaction.annotation.Transactional +import packit.model.RolePermission + +@Repository +interface RolePermissionRepository : JpaRepository +{ + @Modifying + @Transactional + @Query("DELETE FROM RolePermission rp WHERE rp.id IN :ids") + fun deleteAllByIdIn(ids: List) +} diff --git a/api/app/src/main/kotlin/packit/repository/RoleRepository.kt b/api/app/src/main/kotlin/packit/repository/RoleRepository.kt index 5a1b7d64..ac14e290 100644 --- a/api/app/src/main/kotlin/packit/repository/RoleRepository.kt +++ b/api/app/src/main/kotlin/packit/repository/RoleRepository.kt @@ -2,6 +2,7 @@ package packit.repository import org.springframework.data.jpa.repository.JpaRepository import org.springframework.stereotype.Repository +import org.springframework.transaction.annotation.Transactional import packit.model.Role @Repository @@ -10,5 +11,8 @@ interface RoleRepository : JpaRepository fun findByName(name: String): Role? fun existsByName(name: String): Boolean fun findByNameIn(names: List): List + fun findAllByIsUsername(isUsername: Boolean): List + + @Transactional fun deleteByName(name: String) } diff --git a/api/app/src/main/kotlin/packit/service/RolePermissionService.kt b/api/app/src/main/kotlin/packit/service/RolePermissionService.kt new file mode 100644 index 00000000..d1e08651 --- /dev/null +++ b/api/app/src/main/kotlin/packit/service/RolePermissionService.kt @@ -0,0 +1,80 @@ +package packit.service + +import org.springframework.http.HttpStatus +import org.springframework.stereotype.Service +import packit.exceptions.PackitException +import packit.model.Role +import packit.model.RolePermission +import packit.model.dto.UpdateRolePermission +import packit.repository.* + +interface RolePermissionService +{ + fun removeRolePermissionsFromRole(role: Role, removeRolePermissions: List) + fun getRolePermissionsToAdd(role: Role, addRolePermissions: List): List +} + +@Service +class BaseRolePermissionService( + private val permissionRepository: PermissionRepository, + private val packetRepository: PacketRepository, + private val packetGroupRepository: PacketGroupRepository, + private val tagRepository: TagRepository, + private val rolePermissionRepository: RolePermissionRepository +) : RolePermissionService +{ + internal fun getRolePermissionsToUpdate( + role: Role, + updateRolePermissions: List + ): List + { + return updateRolePermissions.map { addRolePermission -> + val permission = permissionRepository.findByName(addRolePermission.permission) + ?: throw PackitException("invalidPermissionsProvided", HttpStatus.BAD_REQUEST) + + RolePermission( + role = role, + permission = permission, + packet = addRolePermission.packetId?.let { + packetRepository.findById(it) + .orElseThrow { PackitException("packetNotFound", HttpStatus.BAD_REQUEST) } + }, + packetGroup = addRolePermission.packetGroupId?.let { + packetGroupRepository.findById(it) + .orElseThrow { PackitException("packetGroupNotFound", HttpStatus.BAD_REQUEST) } + }, + tag = addRolePermission.tagId?.let { + tagRepository.findById(it).orElseThrow { PackitException("tagNotFound", HttpStatus.BAD_REQUEST) } + } + ) + } + } + + override fun removeRolePermissionsFromRole(role: Role, removeRolePermissions: List) + { + val rolePermissionsToRemove = getRolePermissionsToUpdate(role, removeRolePermissions) + + val matchedRolePermissionsToRemove = rolePermissionsToRemove.map { rolePermissionToRemove -> + val matchedPermission = role.rolePermissions.find { rolePermissionToRemove == it } + ?: throw PackitException("rolePermissionDoesNotExist", HttpStatus.BAD_REQUEST) + + matchedPermission + } + + rolePermissionRepository.deleteAllByIdIn(matchedRolePermissionsToRemove.map { it.id!! }) + } + + override fun getRolePermissionsToAdd( + role: Role, + addRolePermissions: List + ): List + { + val rolePermissionsToAdd = getRolePermissionsToUpdate(role, addRolePermissions) + if (rolePermissionsToAdd.any { role.rolePermissions.contains(it) }) + { + throw PackitException("rolePermissionAlreadyExists", HttpStatus.BAD_REQUEST) + } + + return rolePermissionsToAdd + } +} diff --git a/api/app/src/main/kotlin/packit/service/RoleService.kt b/api/app/src/main/kotlin/packit/service/RoleService.kt index e48382b2..99109f1d 100644 --- a/api/app/src/main/kotlin/packit/service/RoleService.kt +++ b/api/app/src/main/kotlin/packit/service/RoleService.kt @@ -4,12 +4,13 @@ import org.springframework.http.HttpStatus import org.springframework.security.core.GrantedAuthority import org.springframework.security.core.authority.SimpleGrantedAuthority import org.springframework.stereotype.Service -import org.springframework.transaction.annotation.Transactional import packit.exceptions.PackitException import packit.model.Permission import packit.model.Role import packit.model.RolePermission import packit.model.dto.CreateRole +import packit.model.dto.UpdateRolePermission +import packit.model.dto.UpdateRolePermissions import packit.repository.RoleRepository interface RoleService @@ -20,12 +21,17 @@ interface RoleService fun getGrantedAuthorities(roles: List): MutableList fun createRole(createRole: CreateRole) fun deleteRole(roleName: String) + fun getRoleNames(): List + fun getRoles(isUsernames: Boolean?): List + fun getRole(roleName: String): Role + fun updatePermissionsToRole(roleName: String, updateRolePermissions: UpdateRolePermissions) } @Service class BaseRoleService( private val roleRepository: RoleRepository, - private val permissionService: PermissionService + private val permissionService: PermissionService, + private val rolePermissionService: RolePermissionService ) : RoleService { override fun getUsernameRole(username: String): Role @@ -52,10 +58,8 @@ class BaseRoleService( saveRole(createRole.name, permissions) } - @Transactional override fun deleteRole(roleName: String) { - if (!roleRepository.existsByName(roleName)) { throw PackitException("roleNotFound", HttpStatus.BAD_REQUEST) @@ -63,6 +67,48 @@ class BaseRoleService( roleRepository.deleteByName(roleName) } + override fun updatePermissionsToRole(roleName: String, updateRolePermissions: UpdateRolePermissions) + { + val role = roleRepository.findByName(roleName) + ?: throw PackitException("roleNotFound", HttpStatus.BAD_REQUEST) + + val roleAfterPermissionAdd = addRolePermissionsToRole(role, updateRolePermissions.addPermissions) + + rolePermissionService.removeRolePermissionsFromRole( + roleAfterPermissionAdd, + updateRolePermissions.removePermissions + ) + } + + internal fun addRolePermissionsToRole(role: Role, addRolePermissions: List): Role + { + val rolePermissionsToAdd = + rolePermissionService.getRolePermissionsToAdd(role, addRolePermissions) + role.rolePermissions.addAll(rolePermissionsToAdd) + return roleRepository.save(role) + } + + override fun getRoleNames(): List + { + return roleRepository.findAll().map { it.name } + } + + override fun getRoles(isUsernames: Boolean?): List + { + if (isUsernames == null) + { + return roleRepository.findAll() + } + + return roleRepository.findAllByIsUsername(isUsernames) + } + + override fun getRole(roleName: String): Role + { + return roleRepository.findByName(roleName) + ?: throw PackitException("roleNotFound", HttpStatus.BAD_REQUEST) + } + internal fun saveRole(roleName: String, permissions: List = listOf()) { if (roleRepository.existsByName(roleName)) diff --git a/api/app/src/main/resources/errorBundle.properties b/api/app/src/main/resources/errorBundle.properties index eb8e8f2f..a4ef8524 100644 --- a/api/app/src/main/resources/errorBundle.properties +++ b/api/app/src/main/resources/errorBundle.properties @@ -15,4 +15,9 @@ userAlreadyExists=User already exists userNotFound=User not found roleAlreadyExists=Role already exists roleNotFound=Role not found +rolePermissionAlreadyExists=Role permission already exists +packetNotFound=Packet not found +packetGroupNotFound=Packet group not found +tagNotFound=Tag not found +rolePermissionDoesNotExist=Permission does not exist on Role adminRoleNotFound=Admin role not found, contact your administrator diff --git a/api/app/src/test/kotlin/packit/integration/controllers/RoleControllerTest.kt b/api/app/src/test/kotlin/packit/integration/controllers/RoleControllerTest.kt index 009f8ec3..ea7d9372 100644 --- a/api/app/src/test/kotlin/packit/integration/controllers/RoleControllerTest.kt +++ b/api/app/src/test/kotlin/packit/integration/controllers/RoleControllerTest.kt @@ -9,7 +9,12 @@ import org.springframework.test.context.jdbc.Sql import packit.integration.IntegrationTest import packit.integration.WithAuthenticatedUser import packit.model.Role +import packit.model.RolePermission import packit.model.dto.CreateRole +import packit.model.dto.UpdateRolePermission +import packit.model.dto.UpdateRolePermissions +import packit.model.toDto +import packit.repository.PermissionRepository import packit.repository.RoleRepository import kotlin.test.assertEquals import kotlin.test.assertNotNull @@ -20,22 +25,41 @@ class RoleControllerTest : IntegrationTest() { @Autowired private lateinit var roleRepository: RoleRepository + + @Autowired + private lateinit var permissionsRepository: PermissionRepository + private val createTestRoleBody = ObjectMapper().writeValueAsString( CreateRole( name = "testRole", permissionNames = listOf("packet.run", "packet.read") ) ) + private val updateRolePermissions = ObjectMapper().writeValueAsString( + UpdateRolePermissions( + addPermissions = listOf( + UpdateRolePermission( + permission = "packet.read" + ) + ), + removePermissions = listOf( + UpdateRolePermission( + permission = "packet.run" + ) + ) + ) + ) @Test @WithAuthenticatedUser(authorities = ["user.manage"]) fun `users with manage authority can create roles`() { - val result = restTemplate.postForEntity( - "/role", - getTokenizedHttpEntity(data = createTestRoleBody), - String::class.java - ) + val result = + restTemplate.postForEntity( + "/role", + getTokenizedHttpEntity(data = createTestRoleBody), + String::class.java + ) assertSuccess(result) assertNotNull(roleRepository.findByName("testRole")) @@ -45,11 +69,12 @@ class RoleControllerTest : IntegrationTest() @WithAuthenticatedUser(authorities = ["none"]) fun `user without user manage permission cannot create roles`() { - val result = restTemplate.postForEntity( - "/role", - getTokenizedHttpEntity(data = createTestRoleBody), - String::class.java - ) + val result = + restTemplate.postForEntity( + "/role", + getTokenizedHttpEntity(data = createTestRoleBody), + String::class.java + ) assertEquals(result.statusCode, HttpStatus.UNAUTHORIZED) } @@ -58,11 +83,12 @@ class RoleControllerTest : IntegrationTest() @WithAuthenticatedUser(authorities = ["user.manage"]) fun `reject request if createRole body is invalid`() { - val result = restTemplate.postForEntity( - "/role", - getTokenizedHttpEntity(data = "{}"), - String::class.java - ) + val result = + restTemplate.postForEntity( + "/role", + getTokenizedHttpEntity(data = "{}"), + String::class.java + ) assertEquals(result.statusCode, HttpStatus.BAD_REQUEST) } @@ -73,29 +99,163 @@ class RoleControllerTest : IntegrationTest() { roleRepository.save(Role(name = "testRole")) + val result = + restTemplate.exchange( + "/role/testRole", + HttpMethod.DELETE, + getTokenizedHttpEntity(), + String::class.java + ) + + assertEquals(result.statusCode, HttpStatus.NO_CONTENT) + assertNull(roleRepository.findByName("testRole")) + } + + @Test + @WithAuthenticatedUser(authorities = ["none"]) + fun `user without user manage permission cannot delete roles`() + { + roleRepository.save(Role(name = "testRole")) + + val result = + restTemplate.postForEntity( + "/role/testRole", + getTokenizedHttpEntity(data = createTestRoleBody), + String::class.java + ) + + assertEquals(result.statusCode, HttpStatus.UNAUTHORIZED) + } + + @Test + @WithAuthenticatedUser(authorities = ["user.manage"]) + fun `users with manage authority can update role permissions`() + { + val roleName = "testRole" + val baseRole = roleRepository.save(Role(name = roleName)) + val permission = permissionsRepository.findByName("packet.run")!! + baseRole.rolePermissions = mutableListOf(RolePermission(baseRole, permission)) + roleRepository.save(baseRole) + val result = restTemplate.exchange( - "/role/testRole", - HttpMethod.DELETE, - getTokenizedHttpEntity(), + "/role/update-permissions/testRole", + HttpMethod.PUT, + getTokenizedHttpEntity(data = updateRolePermissions), String::class.java ) assertEquals(result.statusCode, HttpStatus.NO_CONTENT) - assertNull(roleRepository.findByName("testRole")) + val role = roleRepository.findByName("testRole")!! + assertEquals(1, role.rolePermissions.size) + assertEquals("packet.read", role.rolePermissions.first().permission.name) } @Test @WithAuthenticatedUser(authorities = ["none"]) - fun `user without user manage permission cannot delete roles`() + fun `user without user manage permission cannot update role permissions`() { roleRepository.save(Role(name = "testRole")) - val result = restTemplate.postForEntity( - "/role/testRole", - getTokenizedHttpEntity(data = createTestRoleBody), + val result = restTemplate.exchange( + "/role/update-permissions/testRole", + HttpMethod.PUT, + getTokenizedHttpEntity(data = updateRolePermissions), String::class.java ) assertEquals(result.statusCode, HttpStatus.UNAUTHORIZED) } + + @Test + @WithAuthenticatedUser(authorities = ["user.manage"]) + fun `user with manage authority can read role names`() + { + roleRepository.save(Role(name = "testRole")) + + val result = + restTemplate.exchange( + "/role/names", + HttpMethod.GET, + getTokenizedHttpEntity(), + String::class.java + ) + + assertSuccess(result) + + assertEquals(ObjectMapper().writeValueAsString(listOf("ADMIN", "testRole")), result.body) + } + + @Test + @WithAuthenticatedUser(authorities = ["user.manage"]) + fun `users can get roles with relationships`() + { + val roleDto = roleRepository.findByName("ADMIN")!!.toDto() + val result = + restTemplate.exchange( + "/role", + HttpMethod.GET, + getTokenizedHttpEntity(), + String::class.java + ) + + assertSuccess(result) + + assertEquals(ObjectMapper().writeValueAsString(listOf(roleDto)), result.body) + } + + @Test + @WithAuthenticatedUser(authorities = ["user.manage"]) + fun `users can get username roles with relationships `() + { + roleRepository.save(Role("username", isUsername = true)) + val allUsernameRoles = roleRepository.findAllByIsUsername(true).map { it.toDto() } + val result = + restTemplate.exchange( + "/role?isUsername=true", + HttpMethod.GET, + getTokenizedHttpEntity(), + String::class.java + ) + + assertSuccess(result) + + assertEquals(ObjectMapper().writeValueAsString(allUsernameRoles), result.body) + } + + @Test + @WithAuthenticatedUser(authorities = ["user.manage"]) + fun `users can get non username roles with relationships`() + { + roleRepository.save(Role("randomUser", isUsername = true)).toDto() + val adminRole = roleRepository.findByName("ADMIN")!!.toDto() + val result = + restTemplate.exchange( + "/role?isUsername=false", + HttpMethod.GET, + getTokenizedHttpEntity(), + String::class.java + ) + + assertSuccess(result) + + assertEquals(ObjectMapper().writeValueAsString(listOf(adminRole)), result.body) + } + + @Test + @WithAuthenticatedUser(authorities = ["user.manage"]) + fun `users can get specific with relationships`() + { + val roleDto = roleRepository.findByName("ADMIN")!!.toDto() + val result = + restTemplate.exchange( + "/role/ADMIN", + HttpMethod.GET, + getTokenizedHttpEntity(), + String::class.java + ) + + assertSuccess(result) + + assertEquals(ObjectMapper().writeValueAsString(roleDto), result.body) + } } diff --git a/api/app/src/test/kotlin/packit/unit/model/PacketGroupTest.kt b/api/app/src/test/kotlin/packit/unit/model/PacketGroupTest.kt new file mode 100644 index 00000000..7ad05d10 --- /dev/null +++ b/api/app/src/test/kotlin/packit/unit/model/PacketGroupTest.kt @@ -0,0 +1,19 @@ +package packit.unit.model + +import packit.model.PacketGroup +import packit.model.toDto +import kotlin.test.Test +import kotlin.test.assertEquals + +class PacketGroupTest +{ + @Test + fun `toDto returns correct PacketGroupDto for given PacketGroup`() + { + val packetGroup = PacketGroup("group1") + packetGroup.id = 1 + val packetGroupDto = packetGroup.toDto() + assertEquals("group1", packetGroupDto.name) + assertEquals(1, packetGroupDto.id) + } +} diff --git a/api/app/src/test/kotlin/packit/unit/model/PacketTest.kt b/api/app/src/test/kotlin/packit/unit/model/PacketTest.kt new file mode 100644 index 00000000..af8e97b4 --- /dev/null +++ b/api/app/src/test/kotlin/packit/unit/model/PacketTest.kt @@ -0,0 +1,44 @@ +package packit.unit.model + +import packit.model.Packet +import packit.model.toBasicDto +import packit.model.toDto +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class PacketTest +{ + @Test + fun `toDto returns correct PacketDto for given Packet`() + { + val packet = Packet("id1", "name1", "displayName1", emptyMap(), true, 1.0, 2.0, 3.0) + val packetDto = packet.toDto() + assertEquals("id1", packetDto.id) + assertEquals("name1", packetDto.name) + assertEquals("displayName1", packetDto.displayName) + assertTrue(packetDto.parameters.isEmpty()) + assertTrue(packetDto.published) + assertEquals(1.0, packetDto.importTime) + assertEquals(2.0, packetDto.startTime) + assertEquals(3.0, packetDto.endTime) + } + + @Test + fun `toDto returns correct PacketDto for Packet with non-empty parameters`() + { + val parameters = mapOf("param1" to "value1") + val packet = Packet("id1", "name1", "displayName1", parameters, true, 1.0, 2.0, 3.0) + val packetDto = packet.toDto() + assertEquals(parameters, packetDto.parameters) + } + + @Test + fun `toBasicDto returns correct BasicPacketDto for given Packet`() + { + val packet = Packet("id1", "name1", "displayName1", emptyMap(), true, 1.0, 2.0, 3.0) + val basicPacketDto = packet.toBasicDto() + assertEquals("id1", basicPacketDto.id) + assertEquals("name1", basicPacketDto.name) + } +} diff --git a/api/app/src/test/kotlin/packit/unit/model/RolePermissionTest.kt b/api/app/src/test/kotlin/packit/unit/model/RolePermissionTest.kt new file mode 100644 index 00000000..bb8c156a --- /dev/null +++ b/api/app/src/test/kotlin/packit/unit/model/RolePermissionTest.kt @@ -0,0 +1,185 @@ +package packit.unit.model + +import org.junit.jupiter.api.Assertions.assertDoesNotThrow +import org.junit.jupiter.api.assertThrows +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import packit.model.* +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertNotEquals + +class RolePermissionTest +{ + private val mockRoles = listOf( + Role("role1"), + Role("role2"), + ) + private val mockPermissions = listOf( + Permission("permission1", description = "d1"), + Permission("permission2", description = "d2"), + ) + + @Test + fun `equals returns true when comparing same instance`() + { + val rolePermission = RolePermission(mockRoles.first(), mockPermissions.first()) + assertEquals(rolePermission, rolePermission) + } + + @Test + fun `equals returns false when comparing with non RolePermission instance`() + { + val rolePermission = RolePermission(mockRoles.first(), mockPermissions.first()) + assertFalse(rolePermission.equals("not a RolePermission")) + } + + @Test + fun `equals returns false when role names are different`() + { + val rolePermission1 = RolePermission(mockRoles.first(), mockPermissions.first()) + val rolePermission2 = RolePermission(mockRoles.last(), mockPermissions.first()) + assertNotEquals(rolePermission1, rolePermission2) + } + + @Test + fun `equals returns false when permission names are different`() + { + val rolePermission1 = RolePermission(mockRoles.first(), mockPermissions.first()) + val rolePermission2 = RolePermission(mockRoles.first(), mockPermissions.last()) + assertNotEquals(rolePermission1, rolePermission2) + } + + @Test + fun `equals returns true when all properties are equal`() + { + val rolePermission1 = RolePermission(mockRoles.first(), mockPermissions.first()) + val rolePermission2 = RolePermission(mockRoles.first(), mockPermissions.first()) + assertEquals(rolePermission1, rolePermission2) + } + + @Test + fun `equals returns false when packet ids are different`() + { + + val rolePermission1 = + RolePermission(mockRoles.first(), mockPermissions.first(), mock { on { id } doReturn "2024111" }) + val rolePermission2 = + RolePermission(mockRoles.first(), mockPermissions.first(), mock { on { id } doReturn "2023344" }) + assertNotEquals(rolePermission1, rolePermission2) + } + + @Test + fun `equals returns false when packetGroup ids are different`() + { + val rolePermission1 = + RolePermission(mockRoles.first(), mockPermissions.first(), null, mock { on { id } doReturn 1 }) + val rolePermission2 = + RolePermission(mockRoles.first(), mockPermissions.first(), null, mock { on { id } doReturn 2 }) + assertNotEquals(rolePermission1, rolePermission2) + } + + @Test + fun `equals returns false when tag ids are different`() + { + val rolePermission1 = + RolePermission(mockRoles.first(), mockPermissions.first(), null, null, mock { on { id } doReturn 1 }) + val rolePermission2 = + RolePermission(mockRoles.first(), mockPermissions.first(), null, null, mock { on { id } doReturn 2 }) + assertNotEquals(rolePermission1, rolePermission2) + } + + @Test + fun `hashCode returns same hashcode for identical RolePermission instances`() + { + val rolePermission1 = RolePermission(mockRoles.first(), mockPermissions.first()) + val rolePermission2 = RolePermission(mockRoles.first(), mockPermissions.first()) + assertEquals(rolePermission1.hashCode(), rolePermission2.hashCode()) + } + + @Test + fun `hashCode returns different hash codes for RolePermission instances with different roles`() + { + val rolePermission1 = RolePermission(mockRoles.first(), mockPermissions.first()) + val rolePermission2 = RolePermission(mockRoles.last(), mockPermissions.first()) + assertNotEquals(rolePermission1.hashCode(), rolePermission2.hashCode()) + } + + @Test + fun `hashCode returns different hash codes for RolePermission instances with different permissions`() + { + val rolePermission1 = RolePermission(mockRoles.first(), mockPermissions.first()) + val rolePermission2 = RolePermission(mockRoles.first(), mockPermissions.last()) + assertNotEquals(rolePermission1.hashCode(), rolePermission2.hashCode()) + } + + @Test + fun `hashCode returns different hash codes for RolePermission instances with different packets`() + { + val rolePermission1 = + RolePermission(mockRoles.first(), mockPermissions.first(), mock { on { id } doReturn "2024111" }) + val rolePermission2 = + RolePermission(mockRoles.first(), mockPermissions.first(), mock { on { id } doReturn "2023344" }) + assertNotEquals(rolePermission1.hashCode(), rolePermission2.hashCode()) + } + + @Test + fun `hashCode returns different hash codes for RolePermission instances with different packetGroups`() + { + val rolePermission1 = + RolePermission(mockRoles.first(), mockPermissions.first(), null, mock { on { id } doReturn 1 }) + val rolePermission2 = + RolePermission(mockRoles.first(), mockPermissions.first(), null, mock { on { id } doReturn 2 }) + assertNotEquals(rolePermission1.hashCode(), rolePermission2.hashCode()) + } + + @Test + fun `hashCode returns different hash codes for RolePermission instances with different tags`() + { + val rolePermission1 = + RolePermission(mockRoles.first(), mockPermissions.first(), null, null, mock { on { id } doReturn 1 }) + val rolePermission2 = + RolePermission(mockRoles.first(), mockPermissions.first(), null, null, mock { on { id } doReturn 2 }) + assertNotEquals(rolePermission1.hashCode(), rolePermission2.hashCode()) + } + + @Test + fun `constructor throws when more than one scope field is non-null`() + { + assertThrows { + RolePermission(Role("r1"), Permission("p1", "d1"), mock(), mock()) + } + } + + @Test + fun `constructor does not throw when all scope fields are null`() + { + assertDoesNotThrow { + RolePermission(Role("r1"), Permission("p1", "d1")) + } + } + + @Test + fun `constructor does not throw when only single scope field is non-null`() + { + assertDoesNotThrow { + RolePermission(Role("r1"), Permission("p1", "d1"), mock()) + } + } + + @Test + fun `toDto returns correct RolePermissionDto for given RolePermission`() + { + val permission = Permission("permission1", "d1") + val tag = Tag("tag1", id = 1) + val rolePermission = RolePermission(Role("roleName"), permission, tag = tag, id = 1) + + val rolePermissionDto = rolePermission.toDto() + + assertEquals("permission1", rolePermissionDto.permission) + assertEquals("tag1", rolePermissionDto.tag!!.name) + assertEquals(1, rolePermissionDto.tag!!.id) + assertEquals(1, rolePermissionDto.id) + } +} diff --git a/api/app/src/test/kotlin/packit/unit/model/RoleTest.kt b/api/app/src/test/kotlin/packit/unit/model/RoleTest.kt new file mode 100644 index 00000000..504f813b --- /dev/null +++ b/api/app/src/test/kotlin/packit/unit/model/RoleTest.kt @@ -0,0 +1,29 @@ +package packit.unit.model + +import packit.model.* +import java.util.* +import kotlin.test.Test +import kotlin.test.assertEquals + +class RoleTest +{ + @Test + fun `toDto returns correct RoleDto for given Role`() + { + val user = User("user1", mutableListOf(), false, "source1", "displayName", id = UUID.randomUUID()) + val role = Role("role1", users = mutableListOf(user), id = 1) + val permission = Permission("permission1", "d1") + val tag = Tag("tag1", id = 1) + val rolePermission = RolePermission(role, permission, tag = tag, id = 1) + role.rolePermissions = mutableListOf(rolePermission) + + val roleDto = role.toDto() + + assertEquals("role1", roleDto.name) + assertEquals(1, roleDto.id) + assertEquals("permission1", roleDto.rolePermissions.first().permission) + assertEquals("user1", roleDto.users.first().username) + assertEquals("tag1", roleDto.rolePermissions.first().tag!!.name) + assertEquals(1, roleDto.rolePermissions.first().tag!!.id) + } +} diff --git a/api/app/src/test/kotlin/packit/unit/model/TagTest.kt b/api/app/src/test/kotlin/packit/unit/model/TagTest.kt new file mode 100644 index 00000000..434300bc --- /dev/null +++ b/api/app/src/test/kotlin/packit/unit/model/TagTest.kt @@ -0,0 +1,26 @@ +package packit.unit.model + +import org.junit.jupiter.api.assertThrows +import packit.model.Tag +import packit.model.toDto +import kotlin.test.Test +import kotlin.test.assertEquals + +class TagTest +{ + @Test + fun `toDto returns correct TagDto for given Tag`() + { + val tag = Tag("tag1", id = 1) + val tagDto = tag.toDto() + assertEquals("tag1", tagDto.name) + assertEquals(1, tagDto.id) + } + + @Test + fun `toDto throws NullPointerException for Tag with null id`() + { + val tag = Tag("tag1") + assertThrows { tag.toDto() } + } +} diff --git a/api/app/src/test/kotlin/packit/unit/model/UpdateRolePermissionTest.kt b/api/app/src/test/kotlin/packit/unit/model/UpdateRolePermissionTest.kt new file mode 100644 index 00000000..479798f0 --- /dev/null +++ b/api/app/src/test/kotlin/packit/unit/model/UpdateRolePermissionTest.kt @@ -0,0 +1,49 @@ +package packit.unit.model + +import org.junit.jupiter.api.assertDoesNotThrow +import org.junit.jupiter.api.assertThrows +import packit.model.dto.UpdateRolePermission +import kotlin.test.Test + +class UpdateRolePermissionTest +{ + @Test + fun `constructor throws when more than one field is non-null`() + { + assertThrows { + UpdateRolePermission("permission", "packetId", 1, 1) + } + } + + @Test + fun `constructor does not throw when all fields are null`() + { + assertDoesNotThrow { + UpdateRolePermission("permission", null, null, null) + } + } + + @Test + fun `constructor does not throw when only packetId is non-null`() + { + assertDoesNotThrow { + UpdateRolePermission("permission", "packetId", null, null) + } + } + + @Test + fun `constructor does not throw when only tagId is non-null`() + { + assertDoesNotThrow { + UpdateRolePermission("permission", null, 1, null) + } + } + + @Test + fun `constructor does not throw when only packetGroupId is non-null`() + { + assertDoesNotThrow { + UpdateRolePermission("permission", null, null, 1) + } + } +} diff --git a/api/app/src/test/kotlin/packit/unit/model/UserTest.kt b/api/app/src/test/kotlin/packit/unit/model/UserTest.kt new file mode 100644 index 00000000..a5cd03d2 --- /dev/null +++ b/api/app/src/test/kotlin/packit/unit/model/UserTest.kt @@ -0,0 +1,21 @@ +package packit.unit.model + +import packit.model.Role +import packit.model.User +import packit.model.toDto +import java.util.* +import kotlin.test.Test +import kotlin.test.assertEquals + +class UserTest +{ + @Test + fun `toDto returns correct UserDto for given User`() + { + val role = Role("role1") + val user = User("user1", mutableListOf(role), false, "source1", "displayName1", id = UUID.randomUUID()) + val userDto = user.toDto() + assertEquals("user1", userDto.username) + assertEquals(user.id, userDto.id) + } +} diff --git a/api/app/src/test/kotlin/packit/unit/service/RolePermissionServiceTest.kt b/api/app/src/test/kotlin/packit/unit/service/RolePermissionServiceTest.kt new file mode 100644 index 00000000..e24fe454 --- /dev/null +++ b/api/app/src/test/kotlin/packit/unit/service/RolePermissionServiceTest.kt @@ -0,0 +1,214 @@ +package packit.unit.service + +import org.junit.jupiter.api.assertThrows +import org.mockito.kotlin.any +import org.mockito.kotlin.mock +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever +import org.springframework.http.HttpStatus +import packit.exceptions.PackitException +import packit.model.* +import packit.model.dto.UpdateRolePermission +import packit.repository.* +import packit.service.BaseRolePermissionService +import java.util.* +import kotlin.test.Test +import kotlin.test.assertEquals + +class RolePermissionServiceTest +{ + + private val permissionRepository: PermissionRepository = mock() + private val packetRepository: PacketRepository = mock() + private val packetGroupRepository: PacketGroupRepository = mock() + private val tagRepository: TagRepository = mock() + private val rolePermissionRepository: RolePermissionRepository = mock() + + private val service = BaseRolePermissionService( + permissionRepository, + packetRepository, + packetGroupRepository, + tagRepository, + rolePermissionRepository + ) + + @Test + fun `getRolePermissionsToUpdate returns RolePermission list when all entities are found`() + { + val role = Role("role1") + val mockPacket = mock() + val updateRolePermission = UpdateRolePermission("permission1", "id-1") + whenever(permissionRepository.findByName(any())).thenReturn(mock()) + whenever(packetRepository.findById(any())).thenReturn(Optional.of(mockPacket)) + + val result = service.getRolePermissionsToUpdate(role, listOf(updateRolePermission)) + + assertEquals(1, result.size) + assertEquals(role, result[0].role) + assertEquals(mockPacket, result[0].packet) + } + + @Test + fun `getRolePermissionsToUpdate returns RolePermission list when packetGroup is found`() + { + val role = Role("role1") + val mockPacketGroup = mock() + val updateRolePermission = UpdateRolePermission("permission1", packetGroupId = 1) + whenever(permissionRepository.findByName(any())).thenReturn(mock()) + whenever(packetGroupRepository.findById(any())).thenReturn(Optional.of(mockPacketGroup)) + + val result = service.getRolePermissionsToUpdate(role, listOf(updateRolePermission)) + + assertEquals(1, result.size) + assertEquals(role, result[0].role) + assertEquals(mockPacketGroup, result[0].packetGroup) + } + + @Test + fun `getRolePermissionsToUpdate returns RolePermission list when tag is found`() + { + val role = Role("role1") + val mockTag = mock() + val updateRolePermission = UpdateRolePermission("permission1", tagId = 1) + whenever(permissionRepository.findByName(any())).thenReturn(mock()) + whenever(tagRepository.findById(any())).thenReturn(Optional.of(mockTag)) + + val result = service.getRolePermissionsToUpdate(role, listOf(updateRolePermission)) + + assertEquals(1, result.size) + assertEquals(role, result[0].role) + assertEquals(mockTag, result[0].tag) + } + + @Test + fun `getRolePermissionsToUpdate throws PackitException when permission is not found`() + { + val role = Role("role1") + val updateRolePermission = UpdateRolePermission("permission1") + whenever(permissionRepository.findByName(any())).thenReturn(null) + + assertThrows { + service.getRolePermissionsToUpdate(role, listOf(updateRolePermission)) + }.apply { + assertEquals("invalidPermissionsProvided", key) + assertEquals(HttpStatus.BAD_REQUEST, httpStatus) + } + } + + @Test + fun `getRolePermissionsToUpdate throws PackitException when packet is not found`() + { + val role = Role("role1") + val updateRolePermission = UpdateRolePermission("permission1", "packet1") + whenever(permissionRepository.findByName(any())).thenReturn(mock()) + whenever(packetRepository.findById(any())).thenReturn(Optional.empty()) + + assertThrows { + service.getRolePermissionsToUpdate(role, listOf(updateRolePermission)) + }.apply { + assertEquals("packetNotFound", key) + assertEquals(HttpStatus.BAD_REQUEST, httpStatus) + } + } + + @Test + fun `getRolePermissionsToUpdate throws PackitException when packetGroup is not found`() + { + val role = Role("role1") + val updateRolePermission = UpdateRolePermission("permission1", packetGroupId = 1) + whenever(permissionRepository.findByName(any())).thenReturn(mock()) + whenever(packetGroupRepository.findById(any())).thenReturn(Optional.empty()) + + assertThrows { + service.getRolePermissionsToUpdate(role, listOf(updateRolePermission)) + }.apply { + assertEquals("packetGroupNotFound", key) + assertEquals(HttpStatus.BAD_REQUEST, httpStatus) + } + } + + @Test + fun `getRolePermissionsToUpdate throws PackitException when tag is not found`() + { + val role = Role("role1") + val updateRolePermission = UpdateRolePermission("permission1", tagId = 1) + whenever(permissionRepository.findByName(any())).thenReturn(mock()) + whenever(tagRepository.findById(any())).thenReturn(Optional.empty()) + + assertThrows { + service.getRolePermissionsToUpdate(role, listOf(updateRolePermission)) + }.apply { + assertEquals("tagNotFound", key) + assertEquals(HttpStatus.BAD_REQUEST, httpStatus) + } + } + + @Test + fun `removeRolePermissionsFromRole removes role permissions when they exist`() + { + val role = Role("role1") + val permission1 = Permission("permission1", "d1") + val updateRolePermissions = listOf(UpdateRolePermission(permission1.name)) + role.rolePermissions = mutableListOf( + RolePermission(role, permission1, id = 1), + RolePermission(role, Permission("permission2", "d2"), id = 2) + ) + whenever(permissionRepository.findByName(any())).thenReturn(permission1) + + service.removeRolePermissionsFromRole(role, updateRolePermissions) + + verify(rolePermissionRepository).deleteAllByIdIn(listOf(role.rolePermissions.first().id!!)) + } + + @Test + fun `removeRolePermissionsFromRole throws PackitException when role permission does not exist`() + { + val role = Role("role1") + val permission1 = Permission("permission1", "d1") + val updateRolePermissions = + listOf(UpdateRolePermission(permission1.name)) + role.rolePermissions = mutableListOf( + RolePermission(role, Permission("permission2", "d2"), id = 2) + ) + whenever(permissionRepository.findByName(any())).thenReturn(permission1) + + assertThrows { + service.removeRolePermissionsFromRole(role, updateRolePermissions) + }.apply { + assertEquals("rolePermissionDoesNotExist", key) + assertEquals(HttpStatus.BAD_REQUEST, httpStatus) + } + } + + @Test + fun `getAddRolePermissionsFromRole returns role permissions to add when they do not exist in role`() + { + val role = Role("role1") + val permission1 = Permission("permission1", "d1") + val addRolePermissions = listOf(UpdateRolePermission(permission1.name)) + whenever(permissionRepository.findByName(any())).thenReturn(permission1) + + val result = service.getRolePermissionsToAdd(role, addRolePermissions) + + assertEquals(1, result.size) + assertEquals(role, result[0].role) + assertEquals(permission1, result[0].permission) + } + + @Test + fun `getAddRolePermissionsFromRole throws exception when role permission already exists in role`() + { + val role = Role("role1") + val permission1 = Permission("permission1", "d1") + val addRolePermissions = listOf(UpdateRolePermission(permission1.name)) + role.rolePermissions = mutableListOf(RolePermission(role, permission1, id = 1)) + whenever(permissionRepository.findByName(any())).thenReturn(permission1) + + assertThrows { + service.getRolePermissionsToAdd(role, addRolePermissions) + }.apply { + assertEquals("rolePermissionAlreadyExists", key) + assertEquals(HttpStatus.BAD_REQUEST, httpStatus) + } + } +} diff --git a/api/app/src/test/kotlin/packit/unit/service/RoleServiceTest.kt b/api/app/src/test/kotlin/packit/unit/service/RoleServiceTest.kt index 978b7600..ac5baae0 100644 --- a/api/app/src/test/kotlin/packit/unit/service/RoleServiceTest.kt +++ b/api/app/src/test/kotlin/packit/unit/service/RoleServiceTest.kt @@ -14,9 +14,11 @@ import packit.model.Permission import packit.model.Role import packit.model.RolePermission import packit.model.dto.CreateRole +import packit.model.dto.UpdateRolePermissions import packit.repository.RoleRepository import packit.service.BaseRoleService import packit.service.PermissionService +import packit.service.RolePermissionService import kotlin.test.assertTrue class RoleServiceTest @@ -24,13 +26,15 @@ class RoleServiceTest private lateinit var roleRepository: RoleRepository private lateinit var roleService: BaseRoleService private lateinit var permissionService: PermissionService + private lateinit var rolePermissionService: RolePermissionService @BeforeEach fun setup() { roleRepository = mock() permissionService = mock() - roleService = BaseRoleService(roleRepository, permissionService) + rolePermissionService = mock() + roleService = BaseRoleService(roleRepository, permissionService, rolePermissionService) } @Test @@ -233,11 +237,99 @@ class RoleServiceTest val roleName = "nonExistingRole" whenever(roleRepository.existsByName(roleName)).thenReturn(false) - assertThrows(PackitException::class.java) { + assertThrows { roleService.deleteRole(roleName) } } + @Test + fun `updatePermissionsToRole calls correct methods and saves role`() + { + val roleName = "roleName" + val permissionName = "permission1" + val role = createRoleWithPermission(roleName, permissionName) + whenever(roleRepository.findByName(roleName)).thenReturn(role) + whenever(roleRepository.save(any())).thenAnswer { it.getArgument(0) } + whenever(rolePermissionService.getRolePermissionsToAdd(role, listOf())).thenReturn( + listOf( + createRoleWithPermission(roleName, "differentPermission").rolePermissions.first() + ) + ) + + roleService.updatePermissionsToRole(roleName, UpdateRolePermissions()) + + verify(roleRepository).save( + argThat { + this == role + this.rolePermissions.size == 2 + } + ) + verify(rolePermissionService).removeRolePermissionsFromRole(role, listOf()) + verify(rolePermissionService).getRolePermissionsToAdd(role, listOf()) + } + + @Test + fun `updatePermissionsToRole throws exception when role does not exist`() + { + val roleName = "nonExistingRole" + whenever(roleRepository.findByName(roleName)).thenReturn(null) + + assertThrows { + roleService.updatePermissionsToRole(roleName, UpdateRolePermissions()) + }.apply { + assertEquals("roleNotFound", key) + assertEquals(HttpStatus.BAD_REQUEST, httpStatus) + } + } + + @Test + fun `getRoleNames returns role names`() + { + val roles = listOf(Role(name = "role1"), Role(name = "role2")) + whenever(roleRepository.findAll()).thenReturn(roles) + + val result = roleService.getRoleNames() + + assertEquals(2, result.size) + assertTrue(result.containsAll(listOf("role1", "role2"))) + } + + @Test + fun `getRolesWithRelationships returns all roles when no isUsernamesflag set`() + { + val roles = listOf(Role(name = "role1"), Role(name = "role2")) + whenever(roleRepository.findAll()).thenReturn(roles) + + val result = roleService.getRoles(null) + + assertEquals(2, result.size) + assertTrue(result.containsAll(roles)) + } + + @Test + fun `getRolesWithRelationships returns roles with isUsername flag`() + { + val roles = listOf(Role(name = "username1", isUsername = true), Role(name = "username2", isUsername = true)) + whenever(roleRepository.findAllByIsUsername(true)).thenReturn(roles) + + val result = roleService.getRoles(true) + + assertEquals(roles, result) + verify(roleRepository).findAllByIsUsername(true) + } + + @Test + fun `getRole returns role by name`() + { + val roleName = "roleName" + val role = Role(name = roleName) + whenever(roleRepository.findByName(roleName)).thenReturn(role) + + val result = roleService.getRole(roleName) + + assertEquals(role, result) + } + private fun createRoleWithPermission( roleName: String, permissionName: String,