diff --git a/api/app/src/main/kotlin/packit/controllers/LoginController.kt b/api/app/src/main/kotlin/packit/controllers/LoginController.kt index 1c6e01a2..783f9a92 100644 --- a/api/app/src/main/kotlin/packit/controllers/LoginController.kt +++ b/api/app/src/main/kotlin/packit/controllers/LoginController.kt @@ -6,8 +6,8 @@ import org.springframework.validation.annotation.Validated import org.springframework.web.bind.annotation.* import packit.AppConfig import packit.exceptions.PackitException -import packit.model.LoginWithPassword -import packit.model.LoginWithToken +import packit.model.dto.LoginWithPassword +import packit.model.dto.LoginWithToken import packit.service.BasicLoginService import packit.service.GithubAPILoginService diff --git a/api/app/src/main/kotlin/packit/controllers/PacketController.kt b/api/app/src/main/kotlin/packit/controllers/PacketController.kt index 46f7e630..198f2e10 100644 --- a/api/app/src/main/kotlin/packit/controllers/PacketController.kt +++ b/api/app/src/main/kotlin/packit/controllers/PacketController.kt @@ -4,10 +4,10 @@ import org.springframework.core.io.ByteArrayResource import org.springframework.data.domain.Page import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.* -import packit.model.PacketGroupSummary import packit.model.PacketMetadata import packit.model.PageablePayload import packit.model.dto.PacketDto +import packit.model.dto.PacketGroupSummary import packit.model.toDto import packit.service.PacketService diff --git a/api/app/src/main/kotlin/packit/controllers/RoleController.kt b/api/app/src/main/kotlin/packit/controllers/RoleController.kt new file mode 100644 index 00000000..765fe01e --- /dev/null +++ b/api/app/src/main/kotlin/packit/controllers/RoleController.kt @@ -0,0 +1,25 @@ +package packit.controllers + +import org.springframework.http.ResponseEntity +import org.springframework.security.access.prepost.PreAuthorize +import org.springframework.stereotype.Controller +import org.springframework.validation.annotation.Validated +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import packit.model.dto.CreateRole +import packit.service.RoleService + +@Controller +@PreAuthorize("hasAuthority('user.manage')") +@RequestMapping("/role") +class RoleController(private val roleService: RoleService) +{ + @PostMapping() + fun createRole(@RequestBody @Validated createRole: CreateRole): ResponseEntity> + { + roleService.createRole(createRole) + + return ResponseEntity.ok(mapOf("message" to "Role created")) + } +} diff --git a/api/app/src/main/kotlin/packit/controllers/UserController.kt b/api/app/src/main/kotlin/packit/controllers/UserController.kt index 7f7fcf3d..8e8f2a2b 100644 --- a/api/app/src/main/kotlin/packit/controllers/UserController.kt +++ b/api/app/src/main/kotlin/packit/controllers/UserController.kt @@ -10,7 +10,7 @@ import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping import packit.AppConfig import packit.exceptions.PackitException -import packit.model.CreateBasicUser +import packit.model.dto.CreateBasicUser import packit.service.UserService @Controller diff --git a/api/app/src/main/kotlin/packit/model/Packet.kt b/api/app/src/main/kotlin/packit/model/Packet.kt index 92aefaf8..4cae07d3 100644 --- a/api/app/src/main/kotlin/packit/model/Packet.kt +++ b/api/app/src/main/kotlin/packit/model/Packet.kt @@ -25,8 +25,7 @@ class Packet( inverseJoinColumns = [JoinColumn(name = "tag_id")] ) var tags: MutableList = mutableListOf(), - - @OneToMany(mappedBy = "packet") + @OneToMany(mappedBy = "packet", cascade = [CascadeType.ALL]) var rolePermissions: MutableList = mutableListOf() ) diff --git a/api/app/src/main/kotlin/packit/model/Permission.kt b/api/app/src/main/kotlin/packit/model/Permission.kt index b079ba7a..fc3346ef 100644 --- a/api/app/src/main/kotlin/packit/model/Permission.kt +++ b/api/app/src/main/kotlin/packit/model/Permission.kt @@ -7,7 +7,7 @@ import jakarta.persistence.* class Permission( var name: String, var description: String, - @OneToMany(mappedBy = "permission") + @OneToMany(mappedBy = "permission", cascade = [CascadeType.ALL]) var rolePermissions: MutableList = mutableListOf(), @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/api/app/src/main/kotlin/packit/model/Role.kt b/api/app/src/main/kotlin/packit/model/Role.kt index 8f3cddd9..7b76ef77 100644 --- a/api/app/src/main/kotlin/packit/model/Role.kt +++ b/api/app/src/main/kotlin/packit/model/Role.kt @@ -7,7 +7,7 @@ import jakarta.persistence.* class Role( var name: String, var isUsername: Boolean = false, - @OneToMany(mappedBy = "role", fetch = FetchType.EAGER) + @OneToMany(mappedBy = "role", fetch = FetchType.EAGER, cascade = [CascadeType.ALL]) var rolePermissions: MutableList = mutableListOf(), @ManyToMany(mappedBy = "roles", fetch = FetchType.LAZY) var users: MutableList = mutableListOf(), diff --git a/api/app/src/main/kotlin/packit/model/Tag.kt b/api/app/src/main/kotlin/packit/model/Tag.kt index 9146c99f..9b1fd26b 100644 --- a/api/app/src/main/kotlin/packit/model/Tag.kt +++ b/api/app/src/main/kotlin/packit/model/Tag.kt @@ -8,7 +8,7 @@ class Tag( val name: String, @ManyToMany(mappedBy = "tags") var packets: MutableList = mutableListOf(), - @OneToMany(mappedBy = "tag") + @OneToMany(mappedBy = "tag", cascade = [CascadeType.ALL]) var rolePermissions: MutableList = mutableListOf(), @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/api/app/src/main/kotlin/packit/model/CreateBasicUser.kt b/api/app/src/main/kotlin/packit/model/dto/CreateBasicUser.kt similarity index 94% rename from api/app/src/main/kotlin/packit/model/CreateBasicUser.kt rename to api/app/src/main/kotlin/packit/model/dto/CreateBasicUser.kt index 95389802..b166c50c 100644 --- a/api/app/src/main/kotlin/packit/model/CreateBasicUser.kt +++ b/api/app/src/main/kotlin/packit/model/dto/CreateBasicUser.kt @@ -1,4 +1,4 @@ -package packit.model +package packit.model.dto import jakarta.validation.constraints.Email import jakarta.validation.constraints.Size diff --git a/api/app/src/main/kotlin/packit/model/dto/CreateRole.kt b/api/app/src/main/kotlin/packit/model/dto/CreateRole.kt new file mode 100644 index 00000000..ab10ff85 --- /dev/null +++ b/api/app/src/main/kotlin/packit/model/dto/CreateRole.kt @@ -0,0 +1,9 @@ +package packit.model.dto + +import org.jetbrains.annotations.NotNull + +data class CreateRole( + @field:NotNull + val name: String, + val permissionNames: List = listOf() +) diff --git a/api/app/src/main/kotlin/packit/model/LoginWithPassword.kt b/api/app/src/main/kotlin/packit/model/dto/LoginWithPassword.kt similarity index 83% rename from api/app/src/main/kotlin/packit/model/LoginWithPassword.kt rename to api/app/src/main/kotlin/packit/model/dto/LoginWithPassword.kt index ed493c43..324dfb94 100644 --- a/api/app/src/main/kotlin/packit/model/LoginWithPassword.kt +++ b/api/app/src/main/kotlin/packit/model/dto/LoginWithPassword.kt @@ -1,4 +1,4 @@ -package packit.model +package packit.model.dto import org.jetbrains.annotations.NotNull diff --git a/api/app/src/main/kotlin/packit/model/LoginWithToken.kt b/api/app/src/main/kotlin/packit/model/dto/LoginWithToken.kt similarity index 79% rename from api/app/src/main/kotlin/packit/model/LoginWithToken.kt rename to api/app/src/main/kotlin/packit/model/dto/LoginWithToken.kt index 951a1cd1..ce96bc5f 100644 --- a/api/app/src/main/kotlin/packit/model/LoginWithToken.kt +++ b/api/app/src/main/kotlin/packit/model/dto/LoginWithToken.kt @@ -1,4 +1,4 @@ -package packit.model +package packit.model.dto import org.jetbrains.annotations.NotNull diff --git a/api/app/src/main/kotlin/packit/model/OutpackMetadata.kt b/api/app/src/main/kotlin/packit/model/dto/OutpackMetadata.kt similarity index 70% rename from api/app/src/main/kotlin/packit/model/OutpackMetadata.kt rename to api/app/src/main/kotlin/packit/model/dto/OutpackMetadata.kt index 4ca565f9..92afc19c 100644 --- a/api/app/src/main/kotlin/packit/model/OutpackMetadata.kt +++ b/api/app/src/main/kotlin/packit/model/dto/OutpackMetadata.kt @@ -1,4 +1,6 @@ -package packit.model +package packit.model.dto + +import packit.model.TimeMetadata data class OutpackMetadata( val id: String, diff --git a/api/app/src/main/kotlin/packit/model/PacketGroupSummary.kt b/api/app/src/main/kotlin/packit/model/dto/PacketGroupSummary.kt similarity index 89% rename from api/app/src/main/kotlin/packit/model/PacketGroupSummary.kt rename to api/app/src/main/kotlin/packit/model/dto/PacketGroupSummary.kt index 1ef14aaa..413ba793 100644 --- a/api/app/src/main/kotlin/packit/model/PacketGroupSummary.kt +++ b/api/app/src/main/kotlin/packit/model/dto/PacketGroupSummary.kt @@ -1,4 +1,4 @@ -package packit.model +package packit.model.dto // Projection class for PacketRepository.findPacketGroupSummaryByName interface PacketGroupSummary diff --git a/api/app/src/main/kotlin/packit/repository/PacketRepository.kt b/api/app/src/main/kotlin/packit/repository/PacketRepository.kt index 24859e47..06b22233 100644 --- a/api/app/src/main/kotlin/packit/repository/PacketRepository.kt +++ b/api/app/src/main/kotlin/packit/repository/PacketRepository.kt @@ -6,7 +6,7 @@ import org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.Query import org.springframework.stereotype.Repository import packit.model.Packet -import packit.model.PacketGroupSummary +import packit.model.dto.PacketGroupSummary @Repository interface PacketRepository : JpaRepository diff --git a/api/app/src/main/kotlin/packit/repository/PermissionRepository.kt b/api/app/src/main/kotlin/packit/repository/PermissionRepository.kt index 060525e2..e3cea30f 100644 --- a/api/app/src/main/kotlin/packit/repository/PermissionRepository.kt +++ b/api/app/src/main/kotlin/packit/repository/PermissionRepository.kt @@ -6,3 +6,6 @@ import packit.model.Permission @Repository interface PermissionRepository : JpaRepository +{ + fun findByNameIn(names: List): List +} diff --git a/api/app/src/main/kotlin/packit/repository/RoleRepository.kt b/api/app/src/main/kotlin/packit/repository/RoleRepository.kt index b6f890c0..d6f8a339 100644 --- a/api/app/src/main/kotlin/packit/repository/RoleRepository.kt +++ b/api/app/src/main/kotlin/packit/repository/RoleRepository.kt @@ -8,6 +8,6 @@ import packit.model.Role interface RoleRepository : JpaRepository { fun findByName(name: String): Role? - fun existsByName(name: String): Boolean + fun findByNameIn(names: List): List } diff --git a/api/app/src/main/kotlin/packit/service/BasicLoginService.kt b/api/app/src/main/kotlin/packit/service/BasicLoginService.kt index e993e392..d87cc77b 100644 --- a/api/app/src/main/kotlin/packit/service/BasicLoginService.kt +++ b/api/app/src/main/kotlin/packit/service/BasicLoginService.kt @@ -5,7 +5,7 @@ import org.springframework.security.authentication.AuthenticationManager import org.springframework.security.authentication.UsernamePasswordAuthenticationToken import org.springframework.stereotype.Component import packit.exceptions.PackitException -import packit.model.LoginWithPassword +import packit.model.dto.LoginWithPassword import packit.security.profile.BasicUserDetails import packit.security.provider.JwtIssuer diff --git a/api/app/src/main/kotlin/packit/service/GithubAPILoginService.kt b/api/app/src/main/kotlin/packit/service/GithubAPILoginService.kt index 1dd740b7..8acf6ebc 100644 --- a/api/app/src/main/kotlin/packit/service/GithubAPILoginService.kt +++ b/api/app/src/main/kotlin/packit/service/GithubAPILoginService.kt @@ -5,7 +5,7 @@ import org.springframework.stereotype.Component import packit.AppConfig import packit.clients.GithubUserClient import packit.exceptions.PackitException -import packit.model.LoginWithToken +import packit.model.dto.LoginWithToken import packit.security.profile.UserPrincipal import packit.security.provider.JwtIssuer diff --git a/api/app/src/main/kotlin/packit/service/OutpackServerClient.kt b/api/app/src/main/kotlin/packit/service/OutpackServerClient.kt index c3debcbb..c4c8629f 100644 --- a/api/app/src/main/kotlin/packit/service/OutpackServerClient.kt +++ b/api/app/src/main/kotlin/packit/service/OutpackServerClient.kt @@ -12,9 +12,9 @@ import org.springframework.web.client.HttpStatusCodeException import org.springframework.web.client.RestTemplate import packit.AppConfig import packit.exceptions.PackitException -import packit.model.OutpackMetadata import packit.model.OutpackResponse import packit.model.PacketMetadata +import packit.model.dto.OutpackMetadata import java.net.URI interface OutpackServer diff --git a/api/app/src/main/kotlin/packit/service/BasePacketService.kt b/api/app/src/main/kotlin/packit/service/PacketService.kt similarity index 96% rename from api/app/src/main/kotlin/packit/service/BasePacketService.kt rename to api/app/src/main/kotlin/packit/service/PacketService.kt index b1e234b7..1a046569 100644 --- a/api/app/src/main/kotlin/packit/service/BasePacketService.kt +++ b/api/app/src/main/kotlin/packit/service/PacketService.kt @@ -11,7 +11,11 @@ import org.springframework.http.MediaType import org.springframework.stereotype.Service import packit.contentTypes import packit.exceptions.PackitException -import packit.model.* +import packit.model.Packet +import packit.model.PacketGroup +import packit.model.PacketMetadata +import packit.model.PageablePayload +import packit.model.dto.PacketGroupSummary import packit.repository.PacketGroupRepository import packit.repository.PacketRepository import java.security.MessageDigest diff --git a/api/app/src/main/kotlin/packit/service/PermissionService.kt b/api/app/src/main/kotlin/packit/service/PermissionService.kt new file mode 100644 index 00000000..0197a3a0 --- /dev/null +++ b/api/app/src/main/kotlin/packit/service/PermissionService.kt @@ -0,0 +1,29 @@ +package packit.service + +import org.springframework.http.HttpStatus +import org.springframework.stereotype.Service +import packit.exceptions.PackitException +import packit.model.Permission +import packit.repository.PermissionRepository + +interface PermissionService +{ + fun checkMatchingPermissions(permissionsToCheck: List): List +} + +@Service +class BasePermissionService( + private val permissionRepository: PermissionRepository +) : PermissionService +{ + override fun checkMatchingPermissions(permissionsToCheck: List): List + { + val matchedPermissions = permissionRepository.findByNameIn(permissionsToCheck) + + if (matchedPermissions.size != permissionsToCheck.size) + { + throw PackitException("invalidPermissionsProvided", HttpStatus.BAD_REQUEST) + } + return matchedPermissions + } +} diff --git a/api/app/src/main/kotlin/packit/service/RoleService.kt b/api/app/src/main/kotlin/packit/service/RoleService.kt index 5c6d918a..c6fd0c96 100644 --- a/api/app/src/main/kotlin/packit/service/RoleService.kt +++ b/api/app/src/main/kotlin/packit/service/RoleService.kt @@ -5,22 +5,25 @@ import org.springframework.security.core.GrantedAuthority import org.springframework.security.core.authority.SimpleGrantedAuthority import org.springframework.stereotype.Service import packit.exceptions.PackitException +import packit.model.Permission import packit.model.Role import packit.model.RolePermission +import packit.model.dto.CreateRole import packit.repository.RoleRepository interface RoleService { fun getUsernameRole(username: String): Role fun getAdminRole(): Role - fun saveRole(roleName: String) fun checkMatchingRoles(rolesToCheck: List): List fun getGrantedAuthorities(roles: List): MutableList + fun createRole(createRole: CreateRole) } @Service class BaseRoleService( - private val roleRepository: RoleRepository + private val roleRepository: RoleRepository, + private val permissionService: PermissionService ) : RoleService { override fun getUsernameRole(username: String): Role @@ -40,26 +43,34 @@ class BaseRoleService( ?: throw PackitException("adminRoleNotFound", HttpStatus.INTERNAL_SERVER_ERROR) } - override fun saveRole(roleName: String) + override fun createRole(createRole: CreateRole) + { + val permissions = permissionService.checkMatchingPermissions(createRole.permissionNames) + + saveRole(createRole.name, permissions) + } + + internal fun saveRole(roleName: String, permissions: List = listOf()) { if (roleRepository.existsByName(roleName)) { throw PackitException("roleAlreadyExists") } val role = Role(name = roleName) + role.rolePermissions = permissions.map { RolePermission(permission = it, role = role) } + .toMutableList() roleRepository.save(role) } override fun checkMatchingRoles(rolesToCheck: List): List { - val allRoles = roleRepository.findAll() - val foundRoles = rolesToCheck.mapNotNull { name -> allRoles.find { it.name == name } } + val matchedRoles = roleRepository.findByNameIn(rolesToCheck) - if (foundRoles.size != rolesToCheck.size) + if (matchedRoles.size != rolesToCheck.size) { throw PackitException("invalidRolesProvided", HttpStatus.BAD_REQUEST) } - return foundRoles + return matchedRoles } /** diff --git a/api/app/src/main/kotlin/packit/service/UserService.kt b/api/app/src/main/kotlin/packit/service/UserService.kt index 8eee8498..046c562a 100644 --- a/api/app/src/main/kotlin/packit/service/UserService.kt +++ b/api/app/src/main/kotlin/packit/service/UserService.kt @@ -4,8 +4,8 @@ import org.springframework.http.HttpStatus import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.stereotype.Service import packit.exceptions.PackitException -import packit.model.CreateBasicUser import packit.model.User +import packit.model.dto.CreateBasicUser import packit.repository.UserRepository import java.time.Instant diff --git a/api/app/src/main/resources/errorBundle.properties b/api/app/src/main/resources/errorBundle.properties index 4f3e5fd6..78bc84aa 100644 --- a/api/app/src/main/resources/errorBundle.properties +++ b/api/app/src/main/resources/errorBundle.properties @@ -10,6 +10,7 @@ githubLoginDisabled=GitHub login is disabled basicLoginDisabled=Basic login is disabled insufficientPrivileges=You do not have sufficient privileges for attempted action invalidRolesProvided=Invalid roles provided +invalidPermissionsProvided=Invalid permissions provided userAlreadyExists=User already exists userNotFound=User not found roleAlreadyExists=Role already exists diff --git a/api/app/src/test/kotlin/packit/integration/controllers/LoginControllerTest.kt b/api/app/src/test/kotlin/packit/integration/controllers/LoginControllerTest.kt index ee4edf4c..c4d57ed2 100644 --- a/api/app/src/test/kotlin/packit/integration/controllers/LoginControllerTest.kt +++ b/api/app/src/test/kotlin/packit/integration/controllers/LoginControllerTest.kt @@ -12,9 +12,9 @@ import org.springframework.http.* import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.test.context.TestPropertySource import packit.integration.IntegrationTest -import packit.model.LoginWithPassword -import packit.model.LoginWithToken import packit.model.User +import packit.model.dto.LoginWithPassword +import packit.model.dto.LoginWithToken import packit.repository.UserRepository import kotlin.test.assertEquals diff --git a/api/app/src/test/kotlin/packit/integration/controllers/RoleControllerTest.kt b/api/app/src/test/kotlin/packit/integration/controllers/RoleControllerTest.kt new file mode 100644 index 00000000..c942f240 --- /dev/null +++ b/api/app/src/test/kotlin/packit/integration/controllers/RoleControllerTest.kt @@ -0,0 +1,66 @@ +package packit.integration.controllers + +import com.fasterxml.jackson.databind.ObjectMapper +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.HttpStatus +import org.springframework.test.context.jdbc.Sql +import packit.integration.IntegrationTest +import packit.integration.WithAuthenticatedUser +import packit.model.dto.CreateRole +import packit.repository.RoleRepository +import kotlin.test.assertEquals +import kotlin.test.assertNotNull + +@Sql("/delete-test-users.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) +class RoleControllerTest : IntegrationTest() +{ + @Autowired + private lateinit var roleRepository: RoleRepository + private val createTestRoleBody = ObjectMapper().writeValueAsString( + CreateRole( + name = "testRole", + permissionNames = listOf("packet.run", "packet.read") + ) + ) + + @Test + @WithAuthenticatedUser(authorities = ["user.manage"]) + fun `users with manage authority can create roles`() + { + val result = restTemplate.postForEntity( + "/role", + getTokenizedHttpEntity(data = createTestRoleBody), + String::class.java + ) + + assertSuccess(result) + assertNotNull(roleRepository.findByName("testRole")) + } + + @Test + @WithAuthenticatedUser(authorities = ["none"]) + fun `user without user manage permission cannot create roles`() + { + val result = restTemplate.postForEntity( + "/role", + getTokenizedHttpEntity(data = createTestRoleBody), + String::class.java + ) + + assertEquals(result.statusCode, HttpStatus.UNAUTHORIZED) + } + + @Test + @WithAuthenticatedUser(authorities = ["user.manage"]) + fun `reject request if createRole body is invalid`() + { + val result = restTemplate.postForEntity( + "/role", + getTokenizedHttpEntity(data = "{}"), + String::class.java + ) + + assertEquals(result.statusCode, HttpStatus.BAD_REQUEST) + } +} diff --git a/api/app/src/test/kotlin/packit/integration/controllers/UserControllerTest.kt b/api/app/src/test/kotlin/packit/integration/controllers/UserControllerTest.kt index 934dbab5..d974a664 100644 --- a/api/app/src/test/kotlin/packit/integration/controllers/UserControllerTest.kt +++ b/api/app/src/test/kotlin/packit/integration/controllers/UserControllerTest.kt @@ -7,7 +7,7 @@ import org.springframework.test.context.TestPropertySource import org.springframework.test.context.jdbc.Sql import packit.integration.IntegrationTest import packit.integration.WithAuthenticatedUser -import packit.model.CreateBasicUser +import packit.model.dto.CreateBasicUser import packit.repository.UserRepository import kotlin.test.Test import kotlin.test.assertEquals @@ -44,7 +44,7 @@ class UserControllerTest : IntegrationTest() @Test @WithAuthenticatedUser(authorities = ["none"]) - fun `non-admin user cannot create basic users`() + fun `user without user manage permission cannot create basic users`() { val result = restTemplate.postForEntity( "/user/basic", diff --git a/api/app/src/test/kotlin/packit/unit/controllers/LoginControllerTest.kt b/api/app/src/test/kotlin/packit/unit/controllers/LoginControllerTest.kt index fde59b9e..0ece44e0 100644 --- a/api/app/src/test/kotlin/packit/unit/controllers/LoginControllerTest.kt +++ b/api/app/src/test/kotlin/packit/unit/controllers/LoginControllerTest.kt @@ -7,8 +7,8 @@ import org.springframework.http.HttpStatus import packit.AppConfig import packit.controllers.LoginController import packit.exceptions.PackitException -import packit.model.LoginWithPassword -import packit.model.LoginWithToken +import packit.model.dto.LoginWithPassword +import packit.model.dto.LoginWithToken import packit.service.BasicLoginService import packit.service.GithubAPILoginService import kotlin.test.Test diff --git a/api/app/src/test/kotlin/packit/unit/controllers/PacketControllerTest.kt b/api/app/src/test/kotlin/packit/unit/controllers/PacketControllerTest.kt index 7fe5465b..0408e675 100644 --- a/api/app/src/test/kotlin/packit/unit/controllers/PacketControllerTest.kt +++ b/api/app/src/test/kotlin/packit/unit/controllers/PacketControllerTest.kt @@ -13,6 +13,7 @@ import org.springframework.http.HttpHeaders import org.springframework.http.HttpStatus import packit.controllers.PacketController import packit.model.* +import packit.model.dto.PacketGroupSummary import packit.service.PacketService import java.time.Instant import kotlin.test.assertEquals diff --git a/api/app/src/test/kotlin/packit/unit/controllers/UserControllerTest.kt b/api/app/src/test/kotlin/packit/unit/controllers/UserControllerTest.kt index bcac8aa5..87a079d7 100644 --- a/api/app/src/test/kotlin/packit/unit/controllers/UserControllerTest.kt +++ b/api/app/src/test/kotlin/packit/unit/controllers/UserControllerTest.kt @@ -8,7 +8,7 @@ import org.springframework.http.HttpStatus import packit.AppConfig import packit.controllers.UserController import packit.exceptions.PackitException -import packit.model.CreateBasicUser +import packit.model.dto.CreateBasicUser import packit.service.UserService import kotlin.test.Test import kotlin.test.assertEquals diff --git a/api/app/src/test/kotlin/packit/unit/service/BasicLoginServiceTest.kt b/api/app/src/test/kotlin/packit/unit/service/BasicLoginServiceTest.kt index 5b94a802..20747011 100644 --- a/api/app/src/test/kotlin/packit/unit/service/BasicLoginServiceTest.kt +++ b/api/app/src/test/kotlin/packit/unit/service/BasicLoginServiceTest.kt @@ -7,7 +7,7 @@ import org.springframework.security.authentication.AuthenticationManager import org.springframework.security.authentication.UsernamePasswordAuthenticationToken import org.springframework.security.core.Authentication import packit.exceptions.PackitException -import packit.model.LoginWithPassword +import packit.model.dto.LoginWithPassword import packit.security.profile.BasicUserDetails import packit.security.profile.UserPrincipal import packit.security.provider.JwtIssuer diff --git a/api/app/src/test/kotlin/packit/unit/service/GithubAPILoginServiceTest.kt b/api/app/src/test/kotlin/packit/unit/service/GithubAPILoginServiceTest.kt index 2c0bffbf..7cad74b6 100644 --- a/api/app/src/test/kotlin/packit/unit/service/GithubAPILoginServiceTest.kt +++ b/api/app/src/test/kotlin/packit/unit/service/GithubAPILoginServiceTest.kt @@ -12,9 +12,9 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority import packit.AppConfig import packit.clients.GithubUserClient import packit.exceptions.PackitException -import packit.model.LoginWithToken import packit.model.Role import packit.model.User +import packit.model.dto.LoginWithToken import packit.security.profile.UserPrincipal import packit.security.provider.JwtIssuer import packit.service.GithubAPILoginService diff --git a/api/app/src/test/kotlin/packit/unit/service/PacketServiceTest.kt b/api/app/src/test/kotlin/packit/unit/service/PacketServiceTest.kt index 2c1a84a3..7ea2dd54 100644 --- a/api/app/src/test/kotlin/packit/unit/service/PacketServiceTest.kt +++ b/api/app/src/test/kotlin/packit/unit/service/PacketServiceTest.kt @@ -11,6 +11,8 @@ import org.springframework.data.domain.Sort import org.springframework.http.HttpHeaders import packit.exceptions.PackitException import packit.model.* +import packit.model.dto.OutpackMetadata +import packit.model.dto.PacketGroupSummary import packit.repository.PacketGroupRepository import packit.repository.PacketRepository import packit.service.BasePacketService diff --git a/api/app/src/test/kotlin/packit/unit/service/PermissionServiceTest.kt b/api/app/src/test/kotlin/packit/unit/service/PermissionServiceTest.kt new file mode 100644 index 00000000..a4ec5f0b --- /dev/null +++ b/api/app/src/test/kotlin/packit/unit/service/PermissionServiceTest.kt @@ -0,0 +1,49 @@ +package packit.unit.service + +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.assertThrows +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever +import packit.exceptions.PackitException +import packit.model.Permission +import packit.repository.PermissionRepository +import packit.service.BasePermissionService +import kotlin.test.Test +import kotlin.test.assertEquals + +class PermissionServiceTest +{ + private lateinit var permissionRepository: PermissionRepository + private lateinit var basePermissionService: BasePermissionService + + @BeforeEach + fun setup() + { + permissionRepository = mock() + basePermissionService = BasePermissionService(permissionRepository) + } + + @Test + fun `checkMatchingPermissions returns matched permissions when all permissions exist`() + { + val permissionsToCheck = listOf("p1", "p2") + val matchedPermissions = listOf(Permission("p1", "d1"), Permission("p2", "d2")) + whenever(permissionRepository.findByNameIn(permissionsToCheck)).thenReturn(matchedPermissions) + + val result = basePermissionService.checkMatchingPermissions(permissionsToCheck) + + assertEquals(matchedPermissions, result) + } + + @Test + fun `checkMatchingPermissions throws PackitException when not all permissions exist`() + { + val permissionsToCheck = listOf("p1", "p2") + val matchedPermissions = listOf(Permission("p1", "d2")) + whenever(permissionRepository.findByNameIn(permissionsToCheck)).thenReturn(matchedPermissions) + + assertThrows { + basePermissionService.checkMatchingPermissions(permissionsToCheck) + } + } +} 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 d8e438b8..5e3127f9 100644 --- a/api/app/src/test/kotlin/packit/unit/service/RoleServiceTest.kt +++ b/api/app/src/test/kotlin/packit/unit/service/RoleServiceTest.kt @@ -13,20 +13,24 @@ import packit.model.Packet import packit.model.Permission import packit.model.Role import packit.model.RolePermission +import packit.model.dto.CreateRole import packit.repository.RoleRepository import packit.service.BaseRoleService +import packit.service.PermissionService import kotlin.test.assertTrue class RoleServiceTest { private lateinit var roleRepository: RoleRepository private lateinit var roleService: BaseRoleService + private lateinit var permissionService: PermissionService @BeforeEach fun setup() { roleRepository = mock() - roleService = BaseRoleService(roleRepository) + permissionService = mock() + roleService = BaseRoleService(roleRepository, permissionService) } @Test @@ -77,26 +81,49 @@ class RoleServiceTest } } + @Test + fun `createRole creates role with matching permissions`() + { + val createRole = CreateRole(name = "newRole", permissionNames = listOf("p1", "p2")) + val permissions = + listOf(Permission(name = "p1", description = "d1"), Permission(name = "p2", description = "d2")) + whenever(permissionService.checkMatchingPermissions(createRole.permissionNames)).thenReturn(permissions) + whenever(roleRepository.existsByName(createRole.name)).thenReturn(false) + + roleService.createRole(createRole) + + verify(roleRepository).save( + argThat { + this.name == createRole.name + this.rolePermissions.size == 2 + } + ) + } + @Test fun `saveRole throws exception if role already exists`() { whenever(roleRepository.existsByName("roleName")).thenReturn(true) assertThrows(PackitException::class.java) { - roleService.saveRole("roleName") + roleService.saveRole("roleName", listOf()) } } @Test - fun `saveRole saves role when does not exist`() + fun `saveRole saves role with permissions when does not exist`() { + val roleName = "roleName" + val permissions = + listOf(Permission(name = "p1", description = "d1"), Permission(name = "p2", description = "d2")) whenever(roleRepository.existsByName("roleName")).thenReturn(false) - roleService.saveRole("roleName") + roleService.saveRole(roleName, permissions) verify(roleRepository).save( argThat { - this.name == "roleName" + this.name == roleName + this.rolePermissions.size == 2 } ) } @@ -106,7 +133,7 @@ class RoleServiceTest { val rolesToCheck = listOf("role1", "role2") val allRoles = listOf(Role(name = "role1")) - whenever(roleRepository.findAll()).thenReturn(allRoles) + whenever(roleRepository.findByNameIn(rolesToCheck)).thenReturn(allRoles) assertThrows(PackitException::class.java) { roleService.checkMatchingRoles(rolesToCheck) @@ -118,7 +145,7 @@ class RoleServiceTest { val rolesToCheck = listOf("role1", "role2") val allRoles = listOf(Role(name = "role1"), Role(name = "role2")) - whenever(roleRepository.findAll()).thenReturn(allRoles) + whenever(roleRepository.findByNameIn(rolesToCheck)).thenReturn(allRoles) val result = roleService.checkMatchingRoles(rolesToCheck) diff --git a/api/app/src/test/kotlin/packit/unit/service/UserServiceTest.kt b/api/app/src/test/kotlin/packit/unit/service/UserServiceTest.kt index 2cf2006c..d2aa919b 100644 --- a/api/app/src/test/kotlin/packit/unit/service/UserServiceTest.kt +++ b/api/app/src/test/kotlin/packit/unit/service/UserServiceTest.kt @@ -7,9 +7,9 @@ import org.mockito.kotlin.* import org.springframework.http.HttpStatus import org.springframework.security.crypto.password.PasswordEncoder import packit.exceptions.PackitException -import packit.model.CreateBasicUser import packit.model.Role import packit.model.User +import packit.model.dto.CreateBasicUser import packit.repository.UserRepository import packit.service.BaseUserService import packit.service.RoleService diff --git a/api/app/src/test/resources/delete-test-users.sql b/api/app/src/test/resources/delete-test-users.sql index 1b1706df..03c0bdd2 100644 --- a/api/app/src/test/resources/delete-test-users.sql +++ b/api/app/src/test/resources/delete-test-users.sql @@ -1,4 +1,8 @@ --- delete all users except super admin +-- delete all users and roles except super admin DELETE FROM "user" -WHERE display_name NOT IN ('Super Admin'); \ No newline at end of file +WHERE display_name != 'Super Admin'; + +DELETE +FROM "role" +WHERE name != 'ADMIN' \ No newline at end of file