feat(fullstack): Set user roles per orga, scope notification to orga and role, add orga and role to JWT
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
package com.betriebsratkanzlei.legalconsenthub.user
|
||||
|
||||
import com.betriebsratkanzlei.legalconsenthub_api.model.UserRole
|
||||
import com.betriebsratkanzlei.legalconsenthub_api.model.UserStatus
|
||||
import jakarta.persistence.*
|
||||
import org.springframework.data.annotation.CreatedDate
|
||||
@@ -22,10 +21,10 @@ class User(
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(nullable = false)
|
||||
var status: UserStatus = UserStatus.ACTIVE,
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(nullable = true)
|
||||
var role: UserRole? = null,
|
||||
|
||||
@ElementCollection
|
||||
@CollectionTable(name = "user_organization_roles", joinColumns = [JoinColumn(name = "user_id")])
|
||||
var organizationRoles: MutableSet<UserOrganizationRole> = mutableSetOf(),
|
||||
|
||||
@CreatedDate
|
||||
@Column(nullable = false)
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package com.betriebsratkanzlei.legalconsenthub.user
|
||||
|
||||
import com.betriebsratkanzlei.legalconsenthub.security.CustomJwtTokenPrincipal
|
||||
import com.betriebsratkanzlei.legalconsenthub_api.api.UserApi
|
||||
import com.betriebsratkanzlei.legalconsenthub_api.model.CreateUserDto
|
||||
import com.betriebsratkanzlei.legalconsenthub_api.model.UserDto
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
|
||||
@RestController
|
||||
@@ -22,8 +24,24 @@ class UserController(
|
||||
return ResponseEntity.ok(userMapper.toUserDto(user))
|
||||
}
|
||||
|
||||
override fun updateUser(id: String, userDto: UserDto?): ResponseEntity<UserDto> {
|
||||
val user = if (userDto != null) {
|
||||
// Update with provided data
|
||||
userService.updateUser(id, userDto)
|
||||
} else {
|
||||
// Update from JWT data
|
||||
val principal = SecurityContextHolder.getContext().authentication.principal as CustomJwtTokenPrincipal
|
||||
val userId = principal.id ?: throw IllegalArgumentException("User ID missing from JWT")
|
||||
val organizationId = principal.organizationId
|
||||
val roles = principal.roles
|
||||
|
||||
userService.updateUserFromJwt(userId, organizationId, roles)
|
||||
}
|
||||
return ResponseEntity.ok(userMapper.toUserDto(user))
|
||||
}
|
||||
|
||||
override fun deleteUser(id: String): ResponseEntity<Unit> {
|
||||
userService.deleteUser(id)
|
||||
return ResponseEntity.noContent().build()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,22 +4,31 @@ import com.betriebsratkanzlei.legalconsenthub_api.model.UserDto
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
@Component
|
||||
class UserMapper() {
|
||||
class UserMapper(
|
||||
private val roleConverter: UserRoleConverter
|
||||
) {
|
||||
fun toUserDto(user: User): UserDto {
|
||||
val organizationRolesDto = roleConverter.convertToMap(user.organizationRoles)
|
||||
|
||||
return UserDto(
|
||||
id = user.id,
|
||||
name = user.name,
|
||||
status = user.status,
|
||||
role = user.role
|
||||
organizationRoles = organizationRolesDto
|
||||
)
|
||||
}
|
||||
|
||||
fun toUser(userDto: UserDto): User {
|
||||
return User(
|
||||
val user = User(
|
||||
id = userDto.id,
|
||||
name = userDto.name,
|
||||
status = userDto.status,
|
||||
role = userDto.role
|
||||
status = userDto.status
|
||||
)
|
||||
|
||||
userDto.organizationRoles.forEach { (orgId, roles) ->
|
||||
roleConverter.setRolesForOrganization(user.organizationRoles, orgId, roles)
|
||||
}
|
||||
|
||||
return user
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.betriebsratkanzlei.legalconsenthub.user
|
||||
|
||||
import jakarta.persistence.Column
|
||||
import jakarta.persistence.Embeddable
|
||||
|
||||
@Embeddable
|
||||
data class UserOrganizationRole(
|
||||
@Column(name = "organization_id", nullable = false)
|
||||
val organizationId: String,
|
||||
|
||||
@Column(name = "role", nullable = false)
|
||||
val role: String
|
||||
)
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.betriebsratkanzlei.legalconsenthub.user
|
||||
|
||||
import com.betriebsratkanzlei.legalconsenthub_api.model.UserRole
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
@Component
|
||||
object UserRoleConverter {
|
||||
|
||||
fun getRolesForOrganization(organizationRoles: Set<UserOrganizationRole>, organizationId: String): List<UserRole> {
|
||||
return organizationRoles
|
||||
.filter { it.organizationId == organizationId }
|
||||
.mapNotNull { orgRole ->
|
||||
try {
|
||||
UserRole.valueOf(orgRole.role)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setRolesForOrganization(organizationRoles: MutableSet<UserOrganizationRole>, organizationId: String, roles: List<UserRole>) {
|
||||
organizationRoles.removeIf { it.organizationId == organizationId }
|
||||
roles.forEach { role ->
|
||||
organizationRoles.add(UserOrganizationRole(organizationId, role.name))
|
||||
}
|
||||
}
|
||||
|
||||
fun convertToMap(organizationRoles: Set<UserOrganizationRole>): Map<String, List<UserRole>> {
|
||||
return organizationRoles
|
||||
.groupBy { it.organizationId }
|
||||
.mapValues { (_, roles) ->
|
||||
roles.mapNotNull { orgRole ->
|
||||
try {
|
||||
UserRole.valueOf(orgRole.role)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
.filterValues { it.isNotEmpty() }
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,16 @@ import com.betriebsratkanzlei.legalconsenthub.error.UserAlreadyExistsException
|
||||
import com.betriebsratkanzlei.legalconsenthub.error.UserNotFoundException
|
||||
import com.betriebsratkanzlei.legalconsenthub.security.CustomJwtTokenPrincipal
|
||||
import com.betriebsratkanzlei.legalconsenthub_api.model.CreateUserDto
|
||||
import com.betriebsratkanzlei.legalconsenthub_api.model.UserDto
|
||||
import com.betriebsratkanzlei.legalconsenthub_api.model.UserStatus
|
||||
import jakarta.transaction.Transactional
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class UserService(
|
||||
private val userRepository: UserRepository
|
||||
private val userRepository: UserRepository,
|
||||
private val roleConverter: UserRoleConverter
|
||||
) {
|
||||
|
||||
fun getCurrentUser(): User {
|
||||
@@ -29,9 +32,13 @@ class UserService(
|
||||
val user = User(
|
||||
id = createUserDto.id,
|
||||
name = createUserDto.name,
|
||||
status = createUserDto.status ?: UserStatus.ACTIVE,
|
||||
role = createUserDto.role
|
||||
status = createUserDto.status
|
||||
)
|
||||
|
||||
createUserDto.organizationRoles?.forEach { (orgId, roles) ->
|
||||
roleConverter.setRolesForOrganization(user.organizationRoles, orgId, roles)
|
||||
}
|
||||
|
||||
return userRepository.save(user)
|
||||
}
|
||||
|
||||
@@ -40,6 +47,44 @@ class UserService(
|
||||
.orElseThrow { UserNotFoundException(userId) }
|
||||
}
|
||||
|
||||
@Transactional
|
||||
fun updateUser(userId: String, userDto: UserDto): User {
|
||||
val user = userRepository.findById(userId)
|
||||
.orElseThrow { UserNotFoundException(userId) }
|
||||
|
||||
user.name = userDto.name
|
||||
user.status = userDto.status
|
||||
|
||||
user.organizationRoles.clear()
|
||||
userDto.organizationRoles.forEach { (orgId, roles) ->
|
||||
roleConverter.setRolesForOrganization(user.organizationRoles, orgId, roles)
|
||||
}
|
||||
|
||||
return userRepository.save(user)
|
||||
}
|
||||
|
||||
@Transactional
|
||||
fun updateUserFromJwt(userId: String, jwtOrganizationId: String?, jwtRoles: List<String>?): User {
|
||||
val existingUser = userRepository.findById(userId)
|
||||
.orElseThrow { UserNotFoundException(userId) }
|
||||
|
||||
if (jwtOrganizationId != null && !jwtRoles.isNullOrEmpty()) {
|
||||
existingUser.organizationRoles.removeIf { it.organizationId == jwtOrganizationId }
|
||||
|
||||
jwtRoles.forEach { role ->
|
||||
val normalizedRole = role.lowercase().replace("_", "_")
|
||||
existingUser.organizationRoles.add(
|
||||
UserOrganizationRole(
|
||||
organizationId = jwtOrganizationId,
|
||||
role = normalizedRole
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return userRepository.save(existingUser)
|
||||
}
|
||||
|
||||
fun deleteUser(userId: String) {
|
||||
userRepository.deleteById(userId)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user