-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #145 from NIAEFEUP/feature/roles
Role management endpoints
- Loading branch information
Showing
17 changed files
with
1,234 additions
and
37 deletions.
There are no files selected for viewing
92 changes: 92 additions & 0 deletions
92
src/main/kotlin/pt/up/fe/ni/website/backend/controller/RoleController.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package pt.up.fe.ni.website.backend.controller | ||
|
||
import org.springframework.web.bind.annotation.DeleteMapping | ||
import org.springframework.web.bind.annotation.GetMapping | ||
import org.springframework.web.bind.annotation.PathVariable | ||
import org.springframework.web.bind.annotation.PostMapping | ||
import org.springframework.web.bind.annotation.PutMapping | ||
import org.springframework.web.bind.annotation.RequestBody | ||
import org.springframework.web.bind.annotation.RequestMapping | ||
import org.springframework.web.bind.annotation.RestController | ||
import pt.up.fe.ni.website.backend.dto.auth.UserIdDto | ||
import pt.up.fe.ni.website.backend.dto.entity.role.CreateRoleDto | ||
import pt.up.fe.ni.website.backend.dto.entity.role.UpdateRoleDto | ||
import pt.up.fe.ni.website.backend.dto.roles.PermissionsDto | ||
import pt.up.fe.ni.website.backend.service.RoleService | ||
|
||
@RestController | ||
@RequestMapping("/roles") | ||
class RoleController(private val roleService: RoleService) { | ||
@GetMapping | ||
fun getAllRoles() = roleService.getAllRoles() | ||
|
||
@GetMapping("/{id}") | ||
fun getRole(@PathVariable id: Long) = roleService.getRoleById(id) | ||
|
||
@PostMapping | ||
fun createNewRole(@RequestBody dto: CreateRoleDto) = roleService.createNewRole(dto) | ||
|
||
@DeleteMapping("/{id}") | ||
fun deleteRole(@PathVariable id: Long) = roleService.deleteRole(id) | ||
|
||
@PutMapping("/{id}") | ||
fun updateRole(@PathVariable id: Long, @RequestBody dto: UpdateRoleDto) = roleService.updateRole(id, dto) | ||
|
||
@PostMapping("/{id}/permissions") | ||
fun grantPermissionToRole( | ||
@PathVariable id: Long, | ||
@RequestBody permissionsDto: PermissionsDto | ||
): Map<String, String> { | ||
roleService.grantPermissionToRole(id, permissionsDto.permissions) | ||
return emptyMap() | ||
} | ||
|
||
@DeleteMapping("/{id}/permissions") | ||
fun revokePermissionFromRole( | ||
@PathVariable id: Long, | ||
@RequestBody permissionsDto: PermissionsDto | ||
): Map<String, String> { | ||
roleService.revokePermissionFromRole(id, permissionsDto.permissions) | ||
return emptyMap() | ||
} | ||
|
||
@PostMapping("/{id}/users") | ||
fun addUserToRole(@PathVariable id: Long, @RequestBody userIdDto: UserIdDto): Map<String, String> { | ||
roleService.addUserToRole(id, userIdDto.userId) | ||
return emptyMap() | ||
} | ||
|
||
@DeleteMapping("/{id}/users") | ||
fun removeUserFromRole(@PathVariable id: Long, @RequestBody userIdDto: UserIdDto): Map<String, String> { | ||
roleService.removeUserFromRole(id, userIdDto.userId) | ||
return emptyMap() | ||
} | ||
|
||
@PostMapping("/{id}/activities/{activityId}/permissions") | ||
fun addPermissionToPerActivityRole( | ||
@PathVariable id: Long, | ||
@PathVariable activityId: Long, | ||
@RequestBody permissionsDto: PermissionsDto | ||
): Map<String, String> { | ||
roleService.grantPermissionToRoleOnActivity( | ||
id, | ||
activityId, | ||
permissionsDto.permissions | ||
) | ||
return emptyMap() | ||
} | ||
|
||
@DeleteMapping("/{id}/activities/{activityId}/permissions") | ||
fun revokePermissionFromPerActivityRole( | ||
@PathVariable id: Long, | ||
@PathVariable activityId: Long, | ||
@RequestBody permissionsDto: PermissionsDto | ||
): Map<String, String> { | ||
roleService.revokePermissionFromRoleOnActivity( | ||
id, | ||
activityId, | ||
permissionsDto.permissions | ||
) | ||
return emptyMap() | ||
} | ||
} |
5 changes: 5 additions & 0 deletions
5
src/main/kotlin/pt/up/fe/ni/website/backend/dto/auth/UserIdDto.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package pt.up.fe.ni.website.backend.dto.auth | ||
|
||
data class UserIdDto( | ||
val userId: Long | ||
) |
3 changes: 2 additions & 1 deletion
3
src/main/kotlin/pt/up/fe/ni/website/backend/dto/entity/GenerationDto.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,9 @@ | ||
package pt.up.fe.ni.website.backend.dto.entity | ||
|
||
import pt.up.fe.ni.website.backend.dto.entity.role.CreateRoleDto | ||
import pt.up.fe.ni.website.backend.model.Generation | ||
|
||
class GenerationDto( | ||
var schoolYear: String?, | ||
val roles: List<RoleDto> | ||
val roles: List<CreateRoleDto> | ||
) : EntityDto<Generation>() |
10 changes: 7 additions & 3 deletions
10
.../ni/website/backend/dto/entity/RoleDto.kt → .../backend/dto/entity/role/CreateRoleDto.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,19 @@ | ||
package pt.up.fe.ni.website.backend.dto.entity | ||
package pt.up.fe.ni.website.backend.dto.entity.role | ||
|
||
import com.fasterxml.jackson.annotation.JsonProperty | ||
import pt.up.fe.ni.website.backend.dto.entity.EntityDto | ||
import pt.up.fe.ni.website.backend.dto.entity.PerActivityRoleDto | ||
import pt.up.fe.ni.website.backend.model.Role | ||
|
||
class RoleDto( | ||
class CreateRoleDto( | ||
val name: String, | ||
val permissions: List<Int>, | ||
|
||
@JsonProperty(required = true) | ||
val isSection: Boolean?, | ||
|
||
val accountIds: List<Long> = emptyList(), | ||
val associatedActivities: List<PerActivityRoleDto> | ||
val associatedActivities: List<PerActivityRoleDto>, | ||
|
||
val generationId: Long? = null | ||
) : EntityDto<Role>() |
9 changes: 9 additions & 0 deletions
9
src/main/kotlin/pt/up/fe/ni/website/backend/dto/entity/role/UpdateRoleDto.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package pt.up.fe.ni.website.backend.dto.entity.role | ||
|
||
import pt.up.fe.ni.website.backend.dto.entity.EntityDto | ||
import pt.up.fe.ni.website.backend.model.Role | ||
|
||
class UpdateRoleDto( | ||
val name: String, | ||
val isSection: Boolean? | ||
) : EntityDto<Role>() |
7 changes: 7 additions & 0 deletions
7
src/main/kotlin/pt/up/fe/ni/website/backend/dto/roles/PermissionsDto.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package pt.up.fe.ni.website.backend.dto.roles | ||
|
||
import pt.up.fe.ni.website.backend.model.permissions.Permissions | ||
|
||
data class PermissionsDto( | ||
val permissions: Permissions | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
101 changes: 84 additions & 17 deletions
101
src/main/kotlin/pt/up/fe/ni/website/backend/service/RoleService.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,46 +1,113 @@ | ||
package pt.up.fe.ni.website.backend.service | ||
|
||
import jakarta.transaction.Transactional | ||
import jakarta.validation.Validator | ||
import org.springframework.stereotype.Service | ||
import pt.up.fe.ni.website.backend.model.Activity | ||
import pt.up.fe.ni.website.backend.dto.entity.role.CreateRoleDto | ||
import pt.up.fe.ni.website.backend.dto.entity.role.UpdateRoleDto | ||
import pt.up.fe.ni.website.backend.model.PerActivityRole | ||
import pt.up.fe.ni.website.backend.model.Role | ||
import pt.up.fe.ni.website.backend.model.permissions.Permission | ||
import pt.up.fe.ni.website.backend.model.permissions.Permissions | ||
import pt.up.fe.ni.website.backend.repository.GenerationRepository | ||
import pt.up.fe.ni.website.backend.repository.PerActivityRoleRepository | ||
import pt.up.fe.ni.website.backend.repository.RoleRepository | ||
import pt.up.fe.ni.website.backend.service.activity.ActivityService | ||
|
||
@Service | ||
@Transactional | ||
class RoleService( | ||
private val roleRepository: RoleRepository, | ||
private val perActivityRoleRepository: PerActivityRoleRepository | ||
private val perActivityRoleRepository: PerActivityRoleRepository, | ||
private val generationService: GenerationService, | ||
private val accountService: AccountService, | ||
private val activityService: ActivityService, | ||
private val generationRepository: GenerationRepository, | ||
private val validator: Validator | ||
) { | ||
|
||
fun grantPermissionToRole(role: Role, permission: Permission) { | ||
role.permissions.add(permission) | ||
fun getRoleById(roleId: Long): Role { | ||
val role = roleRepository.findById(roleId).orElseThrow { | ||
throw NoSuchElementException(ErrorMessages.roleNotFound(roleId)) | ||
} | ||
return role | ||
} | ||
fun getAllRoles(): List<Role> = roleRepository.findAll().toList() | ||
fun grantPermissionToRole(roleId: Long, permissions: Permissions) { | ||
val role = getRoleById(roleId) | ||
role.permissions.addAll(permissions) | ||
roleRepository.save(role) | ||
} | ||
|
||
fun revokePermissionFromRole(role: Role, permission: Permission) { | ||
role.permissions.remove(permission) | ||
fun revokePermissionFromRole(roleId: Long, permissions: Permissions) { | ||
val role = getRoleById(roleId) | ||
role.permissions.removeAll(permissions) | ||
roleRepository.save(role) | ||
} | ||
|
||
fun grantPermissionToRoleOnActivity(role: Role, activity: Activity, permission: Permission) { | ||
val foundActivity = activity.associatedRoles | ||
fun grantPermissionToRoleOnActivity(roleId: Long, activityId: Long, permissions: Permissions) { | ||
val activity = activityService.getActivityById(activityId) | ||
val role = getRoleById(roleId) | ||
val perActivityRole = activity.associatedRoles | ||
.find { it.activity == activity } ?: PerActivityRole(Permissions()) | ||
foundActivity.role = role | ||
foundActivity.activity = activity | ||
perActivityRole.role = role | ||
perActivityRole.activity = activity | ||
|
||
foundActivity.role = role | ||
foundActivity.permissions.add(permission) | ||
perActivityRoleRepository.save(foundActivity) | ||
perActivityRole.permissions.addAll(permissions) | ||
perActivityRoleRepository.save(perActivityRole) | ||
} | ||
|
||
fun revokePermissionFromRoleOnActivity(role: Role, activity: Activity, permission: Permission) { | ||
fun revokePermissionFromRoleOnActivity(roleId: Long, activityId: Long, permissions: Permissions) { | ||
val activity = activityService.getActivityById(activityId) | ||
val role = getRoleById(roleId) | ||
val foundActivity = activity.associatedRoles | ||
.find { it.role == role } ?: return | ||
|
||
foundActivity.permissions.remove(permission) | ||
foundActivity.permissions.removeAll(permissions) | ||
perActivityRoleRepository.save(foundActivity) | ||
} | ||
|
||
fun createNewRole(dto: CreateRoleDto): Role { | ||
val role = dto.create() | ||
val generation = generationService.getGenerationByIdOrInferLatest(dto.generationId) | ||
|
||
generation.roles.add(role) // just for validation and will not be persisted | ||
if (validator.validateProperty(generation, "roles").isNotEmpty()) { | ||
throw IllegalArgumentException(ErrorMessages.roleAlreadyExists(role.name, generation.schoolYear)) | ||
} | ||
role.generation = generation | ||
roleRepository.save(role) | ||
return role | ||
} | ||
|
||
fun deleteRole(roleId: Long) { | ||
val role = getRoleById(roleId) | ||
role.generation.roles.remove(role) | ||
generationRepository.save(role.generation) | ||
roleRepository.delete(role) | ||
} | ||
|
||
fun addUserToRole(roleId: Long, userId: Long) { | ||
val role = getRoleById(roleId) | ||
val account = accountService.getAccountById(userId) | ||
if (role.accounts.any { it.id == account.id }) return | ||
account.roles.add(role) | ||
roleRepository.save(role) | ||
} | ||
|
||
fun removeUserFromRole(roleId: Long, userId: Long) { | ||
val role = getRoleById(roleId) | ||
val account = accountService.getAccountById(userId) | ||
role.accounts.remove(account) | ||
roleRepository.save(role) | ||
} | ||
|
||
fun updateRole(roleId: Long, dto: UpdateRoleDto): Role { | ||
val role = getRoleById(roleId) | ||
|
||
dto.update(role) | ||
if (validator.validateProperty(role.generation, "roles").isNotEmpty()) { | ||
throw IllegalArgumentException(ErrorMessages.roleAlreadyExists(role.name, role.generation.schoolYear)) | ||
} | ||
|
||
return roleRepository.save(role) | ||
} | ||
} |
Oops, something went wrong.