feat(#1): Add permission and role model
This commit is contained in:
@@ -9,6 +9,7 @@ import org.springframework.core.io.Resource
|
|||||||
import org.springframework.http.HttpHeaders
|
import org.springframework.http.HttpHeaders
|
||||||
import org.springframework.http.MediaType
|
import org.springframework.http.MediaType
|
||||||
import org.springframework.http.ResponseEntity
|
import org.springframework.http.ResponseEntity
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize
|
||||||
import org.springframework.web.bind.annotation.RestController
|
import org.springframework.web.bind.annotation.RestController
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
@@ -20,6 +21,7 @@ class ApplicationFormController(
|
|||||||
val applicationFormFormatService: ApplicationFormFormatService
|
val applicationFormFormatService: ApplicationFormFormatService
|
||||||
) : ApplicationFormApi {
|
) : ApplicationFormApi {
|
||||||
|
|
||||||
|
@PreAuthorize("hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL')")
|
||||||
override fun createApplicationForm(createApplicationFormDto: CreateApplicationFormDto): ResponseEntity<ApplicationFormDto> {
|
override fun createApplicationForm(createApplicationFormDto: CreateApplicationFormDto): ResponseEntity<ApplicationFormDto> {
|
||||||
val updatedCreateApplicationFormDto = createApplicationFormDto.copy(isTemplate = false)
|
val updatedCreateApplicationFormDto = createApplicationFormDto.copy(isTemplate = false)
|
||||||
return ResponseEntity.ok(
|
return ResponseEntity.ok(
|
||||||
@@ -29,6 +31,7 @@ class ApplicationFormController(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL', 'EMPLOYEE')")
|
||||||
override fun getAllApplicationForms(organizationId: String?): ResponseEntity<PagedApplicationFormDto> {
|
override fun getAllApplicationForms(organizationId: String?): ResponseEntity<PagedApplicationFormDto> {
|
||||||
return ResponseEntity.ok(
|
return ResponseEntity.ok(
|
||||||
pagedApplicationFormMapper.toPagedApplicationFormDto(
|
pagedApplicationFormMapper.toPagedApplicationFormDto(
|
||||||
@@ -37,6 +40,7 @@ class ApplicationFormController(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL', 'EMPLOYEE')")
|
||||||
override fun getApplicationFormById(id: UUID): ResponseEntity<ApplicationFormDto> {
|
override fun getApplicationFormById(id: UUID): ResponseEntity<ApplicationFormDto> {
|
||||||
return ResponseEntity.ok(
|
return ResponseEntity.ok(
|
||||||
applicationFormMapper.toApplicationFormDto(
|
applicationFormMapper.toApplicationFormDto(
|
||||||
@@ -45,6 +49,7 @@ class ApplicationFormController(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL', 'EMPLOYEE')")
|
||||||
override fun getApplicationFormHtml(id: UUID): ResponseEntity<String> {
|
override fun getApplicationFormHtml(id: UUID): ResponseEntity<String> {
|
||||||
val applicationForm = applicationFormService.getApplicationFormById(id)
|
val applicationForm = applicationFormService.getApplicationFormById(id)
|
||||||
return ResponseEntity.ok(
|
return ResponseEntity.ok(
|
||||||
@@ -52,6 +57,7 @@ class ApplicationFormController(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL', 'EMPLOYEE')")
|
||||||
override fun getApplicationFormPdf(id: UUID): ResponseEntity<Resource> {
|
override fun getApplicationFormPdf(id: UUID): ResponseEntity<Resource> {
|
||||||
val applicationForm = applicationFormService.getApplicationFormById(id)
|
val applicationForm = applicationFormService.getApplicationFormById(id)
|
||||||
val pdfBytes = applicationFormFormatService.generatePdf(applicationForm)
|
val pdfBytes = applicationFormFormatService.generatePdf(applicationForm)
|
||||||
@@ -62,6 +68,7 @@ class ApplicationFormController(
|
|||||||
.body(resource)
|
.body(resource)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL')")
|
||||||
override fun updateApplicationForm(
|
override fun updateApplicationForm(
|
||||||
id: UUID,
|
id: UUID,
|
||||||
applicationFormDto: ApplicationFormDto
|
applicationFormDto: ApplicationFormDto
|
||||||
@@ -73,11 +80,13 @@ class ApplicationFormController(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL')")
|
||||||
override fun deleteApplicationForm(id: UUID): ResponseEntity<Unit> {
|
override fun deleteApplicationForm(id: UUID): ResponseEntity<Unit> {
|
||||||
applicationFormService.deleteApplicationFormByID(id)
|
applicationFormService.deleteApplicationFormByID(id)
|
||||||
return ResponseEntity.noContent().build()
|
return ResponseEntity.noContent().build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL')")
|
||||||
override fun submitApplicationForm(id: UUID): ResponseEntity<ApplicationFormDto> {
|
override fun submitApplicationForm(id: UUID): ResponseEntity<ApplicationFormDto> {
|
||||||
return ResponseEntity.ok(
|
return ResponseEntity.ok(
|
||||||
applicationFormMapper.toApplicationFormDto(
|
applicationFormMapper.toApplicationFormDto(
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import com.betriebsratkanzlei.legalconsenthub_api.model.ApplicationFormDto
|
|||||||
import com.betriebsratkanzlei.legalconsenthub_api.model.CreateApplicationFormDto
|
import com.betriebsratkanzlei.legalconsenthub_api.model.CreateApplicationFormDto
|
||||||
import com.betriebsratkanzlei.legalconsenthub_api.model.PagedApplicationFormDto
|
import com.betriebsratkanzlei.legalconsenthub_api.model.PagedApplicationFormDto
|
||||||
import org.springframework.http.ResponseEntity
|
import org.springframework.http.ResponseEntity
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize
|
||||||
import org.springframework.web.bind.annotation.RestController
|
import org.springframework.web.bind.annotation.RestController
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
@@ -17,6 +18,7 @@ class ApplicationFormTemplateController(
|
|||||||
val applicationFormMapper: ApplicationFormMapper,
|
val applicationFormMapper: ApplicationFormMapper,
|
||||||
) : ApplicationFormTemplateApi {
|
) : ApplicationFormTemplateApi {
|
||||||
|
|
||||||
|
@PreAuthorize("hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL')")
|
||||||
override fun createApplicationFormTemplate(createApplicationFormDto: CreateApplicationFormDto): ResponseEntity<ApplicationFormDto> {
|
override fun createApplicationFormTemplate(createApplicationFormDto: CreateApplicationFormDto): ResponseEntity<ApplicationFormDto> {
|
||||||
return ResponseEntity.ok(
|
return ResponseEntity.ok(
|
||||||
applicationFormMapper.toApplicationFormDto(
|
applicationFormMapper.toApplicationFormDto(
|
||||||
@@ -25,6 +27,7 @@ class ApplicationFormTemplateController(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL')")
|
||||||
override fun getAllApplicationFormTemplates(): ResponseEntity<PagedApplicationFormDto> {
|
override fun getAllApplicationFormTemplates(): ResponseEntity<PagedApplicationFormDto> {
|
||||||
return ResponseEntity.ok(
|
return ResponseEntity.ok(
|
||||||
pagedApplicationFormMapper.toPagedApplicationFormDto(
|
pagedApplicationFormMapper.toPagedApplicationFormDto(
|
||||||
@@ -33,6 +36,7 @@ class ApplicationFormTemplateController(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL')")
|
||||||
override fun getApplicationFormTemplateById(id: UUID): ResponseEntity<ApplicationFormDto> {
|
override fun getApplicationFormTemplateById(id: UUID): ResponseEntity<ApplicationFormDto> {
|
||||||
return ResponseEntity.ok(
|
return ResponseEntity.ok(
|
||||||
applicationFormMapper.toApplicationFormDto(
|
applicationFormMapper.toApplicationFormDto(
|
||||||
@@ -41,6 +45,7 @@ class ApplicationFormTemplateController(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL')")
|
||||||
override fun updateApplicationFormTemplate(
|
override fun updateApplicationFormTemplate(
|
||||||
id: UUID,
|
id: UUID,
|
||||||
applicationFormDto: ApplicationFormDto
|
applicationFormDto: ApplicationFormDto
|
||||||
@@ -52,6 +57,7 @@ class ApplicationFormTemplateController(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL')")
|
||||||
override fun deleteApplicationFormTemplate(id: UUID): ResponseEntity<Unit> {
|
override fun deleteApplicationFormTemplate(id: UUID): ResponseEntity<Unit> {
|
||||||
applicationFormTemplateService.deleteApplicationFormTemplateByID(id)
|
applicationFormTemplateService.deleteApplicationFormTemplateByID(id)
|
||||||
return ResponseEntity.noContent().build()
|
return ResponseEntity.noContent().build()
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.betriebsratkanzlei.legalconsenthub_api.model.CommentDto
|
|||||||
import com.betriebsratkanzlei.legalconsenthub_api.model.CreateCommentDto
|
import com.betriebsratkanzlei.legalconsenthub_api.model.CreateCommentDto
|
||||||
import com.betriebsratkanzlei.legalconsenthub_api.model.PagedCommentDto
|
import com.betriebsratkanzlei.legalconsenthub_api.model.PagedCommentDto
|
||||||
import org.springframework.http.ResponseEntity
|
import org.springframework.http.ResponseEntity
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize
|
||||||
import org.springframework.web.bind.annotation.RestController
|
import org.springframework.web.bind.annotation.RestController
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
@@ -12,6 +13,7 @@ import java.util.UUID
|
|||||||
class CommentController(
|
class CommentController(
|
||||||
val commentService: CommentService, val commentMapper: CommentMapper, val pagedCommentMapper: PagedCommentMapper
|
val commentService: CommentService, val commentMapper: CommentMapper, val pagedCommentMapper: PagedCommentMapper
|
||||||
) : CommentApi {
|
) : CommentApi {
|
||||||
|
@PreAuthorize("hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL', 'EMPLOYEE')")
|
||||||
override fun createComment(
|
override fun createComment(
|
||||||
applicationFormId: UUID,
|
applicationFormId: UUID,
|
||||||
formElementId: UUID,
|
formElementId: UUID,
|
||||||
@@ -24,6 +26,7 @@ class CommentController(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL', 'EMPLOYEE')")
|
||||||
override fun getCommentsByApplicationFormId(applicationFormId: UUID): ResponseEntity<PagedCommentDto> {
|
override fun getCommentsByApplicationFormId(applicationFormId: UUID): ResponseEntity<PagedCommentDto> {
|
||||||
return ResponseEntity.ok(
|
return ResponseEntity.ok(
|
||||||
pagedCommentMapper.toPagedCommentDto(
|
pagedCommentMapper.toPagedCommentDto(
|
||||||
@@ -32,6 +35,7 @@ class CommentController(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL', 'EMPLOYEE')")
|
||||||
override fun updateComment(id: UUID, commentDto: CommentDto): ResponseEntity<CommentDto> {
|
override fun updateComment(id: UUID, commentDto: CommentDto): ResponseEntity<CommentDto> {
|
||||||
return ResponseEntity.ok(
|
return ResponseEntity.ok(
|
||||||
commentMapper.toCommentDto(
|
commentMapper.toCommentDto(
|
||||||
@@ -40,6 +44,7 @@ class CommentController(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL')")
|
||||||
override fun deleteComment(id: UUID): ResponseEntity<Unit> {
|
override fun deleteComment(id: UUID): ResponseEntity<Unit> {
|
||||||
commentService.deleteCommentByID(id)
|
commentService.deleteCommentByID(id)
|
||||||
return ResponseEntity.noContent().build()
|
return ResponseEntity.noContent().build()
|
||||||
|
|||||||
@@ -3,18 +3,15 @@ package com.betriebsratkanzlei.legalconsenthub.config
|
|||||||
import com.betriebsratkanzlei.legalconsenthub.security.CustomJwtAuthenticationConverter
|
import com.betriebsratkanzlei.legalconsenthub.security.CustomJwtAuthenticationConverter
|
||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
import org.springframework.core.annotation.Order
|
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||||
import org.springframework.security.config.annotation.web.invoke
|
import org.springframework.security.config.annotation.web.invoke
|
||||||
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm
|
|
||||||
import org.springframework.security.oauth2.jwt.JwtDecoder
|
|
||||||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder
|
|
||||||
import org.springframework.security.web.SecurityFilterChain
|
import org.springframework.security.web.SecurityFilterChain
|
||||||
import org.springframework.http.HttpMethod
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
|
@EnableMethodSecurity
|
||||||
class SecurityConfig {
|
class SecurityConfig {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|||||||
@@ -3,18 +3,23 @@ package com.betriebsratkanzlei.legalconsenthub.security
|
|||||||
import org.springframework.core.convert.converter.Converter
|
import org.springframework.core.convert.converter.Converter
|
||||||
import org.springframework.security.authentication.AbstractAuthenticationToken
|
import org.springframework.security.authentication.AbstractAuthenticationToken
|
||||||
import org.springframework.security.core.GrantedAuthority
|
import org.springframework.security.core.GrantedAuthority
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority
|
||||||
import org.springframework.security.oauth2.jwt.Jwt
|
import org.springframework.security.oauth2.jwt.Jwt
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class CustomJwtAuthenticationConverter : Converter<Jwt, AbstractAuthenticationToken> {
|
class CustomJwtAuthenticationConverter : Converter<Jwt, AbstractAuthenticationToken> {
|
||||||
override fun convert(jwt: Jwt): AbstractAuthenticationToken {
|
override fun convert(jwt: Jwt): AbstractAuthenticationToken {
|
||||||
val authorities: Collection<GrantedAuthority> = emptyList()
|
|
||||||
|
|
||||||
val userId = jwt.subject
|
val userId = jwt.subject
|
||||||
val username = jwt.getClaimAsString("name")
|
val username = jwt.getClaimAsString("name")
|
||||||
val realmAccess = jwt.getClaimAsMap("realm_access")
|
|
||||||
val roles = (realmAccess?.get("roles") as? List<*>)?.mapNotNull { it as? String } ?: emptyList()
|
val resourceAccess = jwt.getClaimAsMap("resource_access") as? Map<*, *>
|
||||||
|
val legalconsenthubResource = resourceAccess?.get("legalconsenthub") as? Map<*, *>
|
||||||
|
val roles = (legalconsenthubResource?.get("roles") as? List<*>)?.mapNotNull { it as? String } ?: emptyList()
|
||||||
|
|
||||||
|
val authorities: Collection<GrantedAuthority> = roles.map { role ->
|
||||||
|
SimpleGrantedAuthority("ROLE_$role")
|
||||||
|
}
|
||||||
|
|
||||||
val principal = CustomJwtTokenPrincipal(userId, username, roles)
|
val principal = CustomJwtTokenPrincipal(userId, username, roles)
|
||||||
|
|
||||||
|
|||||||
152
legalconsenthub/composables/usePermissions.ts
Normal file
152
legalconsenthub/composables/usePermissions.ts
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
export type Permission =
|
||||||
|
| 'application-form:read'
|
||||||
|
| 'application-form:write'
|
||||||
|
| 'application-form:sign'
|
||||||
|
| 'application-form-template:add'
|
||||||
|
| 'application-form-template:edit'
|
||||||
|
| 'application-form-template:delete'
|
||||||
|
| 'comment:add'
|
||||||
|
| 'comment:edit'
|
||||||
|
| 'comment:delete'
|
||||||
|
|
||||||
|
export type Role =
|
||||||
|
| 'CHIEF_EXECUTIVE_OFFICER'
|
||||||
|
| 'BUSINESS_DEPARTMENT'
|
||||||
|
| 'IT_DEPARTMENT'
|
||||||
|
| 'HUMAN_RESOURCES'
|
||||||
|
| 'HEAD_OF_WORKS_COUNCIL'
|
||||||
|
| 'WORKS_COUNCIL'
|
||||||
|
| 'EMPLOYEE'
|
||||||
|
|
||||||
|
const ROLE_PERMISSIONS: Record<Role, Permission[]> = {
|
||||||
|
CHIEF_EXECUTIVE_OFFICER: [
|
||||||
|
'application-form:read',
|
||||||
|
'application-form:write',
|
||||||
|
'application-form:sign',
|
||||||
|
'application-form-template:add',
|
||||||
|
'application-form-template:edit',
|
||||||
|
'application-form-template:delete',
|
||||||
|
'comment:add',
|
||||||
|
'comment:edit',
|
||||||
|
'comment:delete'
|
||||||
|
],
|
||||||
|
HEAD_OF_WORKS_COUNCIL: [
|
||||||
|
'application-form:read',
|
||||||
|
'application-form:write',
|
||||||
|
'application-form:sign',
|
||||||
|
'application-form-template:add',
|
||||||
|
'application-form-template:edit',
|
||||||
|
'application-form-template:delete',
|
||||||
|
'comment:add',
|
||||||
|
'comment:edit',
|
||||||
|
'comment:delete'
|
||||||
|
],
|
||||||
|
BUSINESS_DEPARTMENT: [
|
||||||
|
'application-form:read',
|
||||||
|
'application-form:write',
|
||||||
|
'application-form-template:add',
|
||||||
|
'application-form-template:edit',
|
||||||
|
'application-form-template:delete',
|
||||||
|
'comment:add',
|
||||||
|
'comment:edit',
|
||||||
|
'comment:delete'
|
||||||
|
],
|
||||||
|
IT_DEPARTMENT: [
|
||||||
|
'application-form:read',
|
||||||
|
'application-form:write',
|
||||||
|
'application-form-template:add',
|
||||||
|
'application-form-template:edit',
|
||||||
|
'application-form-template:delete',
|
||||||
|
'comment:add',
|
||||||
|
'comment:edit',
|
||||||
|
'comment:delete'
|
||||||
|
],
|
||||||
|
HUMAN_RESOURCES: [
|
||||||
|
'application-form:read',
|
||||||
|
'application-form:write',
|
||||||
|
'application-form-template:add',
|
||||||
|
'application-form-template:edit',
|
||||||
|
'application-form-template:delete',
|
||||||
|
'comment:add',
|
||||||
|
'comment:edit',
|
||||||
|
'comment:delete'
|
||||||
|
],
|
||||||
|
WORKS_COUNCIL: [
|
||||||
|
'application-form:read',
|
||||||
|
'application-form:write',
|
||||||
|
'application-form-template:add',
|
||||||
|
'application-form-template:edit',
|
||||||
|
'application-form-template:delete',
|
||||||
|
'comment:add',
|
||||||
|
'comment:edit',
|
||||||
|
'comment:delete'
|
||||||
|
],
|
||||||
|
EMPLOYEE: ['application-form:read', 'comment:add', 'comment:edit']
|
||||||
|
}
|
||||||
|
|
||||||
|
export const usePermissions = () => {
|
||||||
|
const { user } = useUserSession()
|
||||||
|
|
||||||
|
const userRoles = computed<Role[]>(() => {
|
||||||
|
return (user.value?.roles ?? []) as Role[]
|
||||||
|
})
|
||||||
|
|
||||||
|
const userPermissions = computed<Permission[]>(() => {
|
||||||
|
const permissions = new Set<Permission>()
|
||||||
|
userRoles.value.forEach((role) => {
|
||||||
|
const rolePermissions = ROLE_PERMISSIONS[role] ?? []
|
||||||
|
rolePermissions.forEach((permission) => permissions.add(permission))
|
||||||
|
})
|
||||||
|
return Array.from(permissions)
|
||||||
|
})
|
||||||
|
|
||||||
|
const hasPermission = (permission: Permission): boolean => {
|
||||||
|
return userPermissions.value.includes(permission)
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasAnyPermission = (permissions: Permission[]): boolean => {
|
||||||
|
return permissions.some((permission) => hasPermission(permission))
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasAllPermissions = (permissions: Permission[]): boolean => {
|
||||||
|
return permissions.every((permission) => hasPermission(permission))
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasRole = (role: Role): boolean => {
|
||||||
|
return userRoles.value.includes(role)
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasAnyRole = (roles: Role[]): boolean => {
|
||||||
|
return roles.some((role) => hasRole(role))
|
||||||
|
}
|
||||||
|
|
||||||
|
const canReadApplicationForms = computed(() => hasPermission('application-form:read'))
|
||||||
|
const canWriteApplicationForms = computed(() => hasPermission('application-form:write'))
|
||||||
|
const canSignApplicationForms = computed(() => hasPermission('application-form:sign'))
|
||||||
|
const canAddTemplate = computed(() => hasPermission('application-form-template:add'))
|
||||||
|
const canEditTemplate = computed(() => hasPermission('application-form-template:edit'))
|
||||||
|
const canDeleteTemplate = computed(() => hasPermission('application-form-template:delete'))
|
||||||
|
const canAddComment = computed(() => hasPermission('comment:add'))
|
||||||
|
const canEditComment = computed(() => hasPermission('comment:edit'))
|
||||||
|
const canDeleteComment = computed(() => hasPermission('comment:delete'))
|
||||||
|
|
||||||
|
return {
|
||||||
|
userRoles,
|
||||||
|
userPermissions,
|
||||||
|
hasPermission,
|
||||||
|
hasAnyPermission,
|
||||||
|
hasAllPermissions,
|
||||||
|
hasRole,
|
||||||
|
hasAnyRole,
|
||||||
|
canReadApplicationForms,
|
||||||
|
canWriteApplicationForms,
|
||||||
|
canSignApplicationForms,
|
||||||
|
canAddTemplate,
|
||||||
|
canEditTemplate,
|
||||||
|
canDeleteTemplate,
|
||||||
|
canAddComment,
|
||||||
|
canEditComment,
|
||||||
|
canDeleteComment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
8
legalconsenthub/middleware/permissions.global.ts
Normal file
8
legalconsenthub/middleware/permissions.global.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export default defineNuxtRouteMiddleware((to) => {
|
||||||
|
const { canWriteApplicationForms } = usePermissions()
|
||||||
|
|
||||||
|
if (to.path === '/create' && !canWriteApplicationForms.value) {
|
||||||
|
return navigateTo('/', { replace: true })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
@@ -16,18 +16,11 @@
|
|||||||
|
|
||||||
<template #body>
|
<template #body>
|
||||||
<div class="flex flex-col gap-4 sm:gap-6 lg:gap-12 w-full lg:max-w-4xl mx-auto">
|
<div class="flex flex-col gap-4 sm:gap-6 lg:gap-12 w-full lg:max-w-4xl mx-auto">
|
||||||
<div v-if="!true" class="text-center py-12">
|
<div v-if="!canWriteApplicationForms" class="text-center py-12">
|
||||||
<UIcon name="i-lucide-shield-x" class="w-16 h-16 mx-auto text-red-400 mb-4" />
|
<UIcon name="i-lucide-shield-x" class="w-16 h-16 mx-auto text-red-400 mb-4" />
|
||||||
<h2 class="text-2xl font-semibold text-gray-700 mb-2">Keine Berechtigung</h2>
|
<h2 class="text-2xl font-semibold text-gray-700 mb-2">Keine Berechtigung</h2>
|
||||||
<p class="text-gray-500 mb-4">Sie haben keine Berechtigung zum Erstellen von Anträgen.</p>
|
<p class="text-gray-500 mb-4">Sie haben keine Berechtigung zum Erstellen von Anträgen.</p>
|
||||||
<UAlert
|
<UButton to="/" class="mt-4"> Zurück zur Übersicht </UButton>
|
||||||
v-if="currentRoleInfo"
|
|
||||||
:title="`Ihre aktuelle Rolle: ${currentRoleInfo.name}`"
|
|
||||||
:description="currentRoleInfo.description"
|
|
||||||
:color="currentRoleInfo.color"
|
|
||||||
variant="soft"
|
|
||||||
class="max-w-md mx-auto"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<UPageCard title="Ampelstatus" variant="naked" orientation="horizontal" class="mb-4">
|
<UPageCard title="Ampelstatus" variant="naked" orientation="horizontal" class="mb-4">
|
||||||
@@ -86,17 +79,11 @@ import type { StepperItem } from '@nuxt/ui'
|
|||||||
const { getAllApplicationFormTemplates } = await useApplicationFormTemplate()
|
const { getAllApplicationFormTemplates } = await useApplicationFormTemplate()
|
||||||
const { createApplicationForm, submitApplicationForm } = useApplicationForm()
|
const { createApplicationForm, submitApplicationForm } = useApplicationForm()
|
||||||
const { validateFormElements, getHighestComplianceStatus } = useApplicationFormValidator()
|
const { validateFormElements, getHighestComplianceStatus } = useApplicationFormValidator()
|
||||||
|
const { canWriteApplicationForms } = usePermissions()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const { selectedOrganization } = storeToRefs(userStore)
|
const { selectedOrganization } = storeToRefs(userStore)
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
|
|
||||||
// Get current role information for display
|
|
||||||
const currentRoleInfo = {
|
|
||||||
name: 'Mitarbeiter',
|
|
||||||
description: 'Sie können Anträge erstellen und bearbeiten.',
|
|
||||||
color: 'info'
|
|
||||||
}
|
|
||||||
|
|
||||||
const stepper = useTemplateRef('stepper')
|
const stepper = useTemplateRef('stepper')
|
||||||
const activeStepperItemIndex = ref<number>(0)
|
const activeStepperItemIndex = ref<number>(0)
|
||||||
|
|
||||||
|
|||||||
@@ -123,15 +123,18 @@ const selectedOrganizationId = computed({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const items = [
|
const { canWriteApplicationForms } = usePermissions()
|
||||||
|
|
||||||
|
const items = computed(() => [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
label: 'Neuer Mitbestimmungsantrag',
|
label: 'Neuer Mitbestimmungsantrag',
|
||||||
icon: 'i-lucide-send',
|
icon: 'i-lucide-send',
|
||||||
to: '/create'
|
to: '/create',
|
||||||
|
disabled: !canWriteApplicationForms.value
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
]
|
])
|
||||||
|
|
||||||
const applicationForms = computed({
|
const applicationForms = computed({
|
||||||
get: () => data?.value?.content ?? [],
|
get: () => data?.value?.content ?? [],
|
||||||
@@ -147,12 +150,14 @@ function getLinksForApplicationForm(applicationForm: ApplicationFormDto) {
|
|||||||
{
|
{
|
||||||
label: 'Bearbeiten',
|
label: 'Bearbeiten',
|
||||||
icon: 'i-lucide-file-pen',
|
icon: 'i-lucide-file-pen',
|
||||||
to: `/application-forms/${applicationForm.id}`
|
to: `/application-forms/${applicationForm.id}`,
|
||||||
|
disabled: !canWriteApplicationForms.value
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Löschen',
|
label: 'Löschen',
|
||||||
icon: 'i-lucide-trash',
|
icon: 'i-lucide-trash',
|
||||||
to: `?delete&id=${applicationForm.id}`
|
to: `?delete&id=${applicationForm.id}`,
|
||||||
|
disabled: !canWriteApplicationForms.value
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,14 @@ export default defineOAuthKeycloakEventHandler({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const organizations = decodedJwt ? extractOrganizations(decodedJwt) : []
|
const organizations = decodedJwt ? extractOrganizations(decodedJwt) : []
|
||||||
|
const roles = decodedJwt ? extractRoles(decodedJwt) : []
|
||||||
|
|
||||||
await setUserSession(event, {
|
await setUserSession(event, {
|
||||||
user: {
|
user: {
|
||||||
keycloakId: user.sub,
|
keycloakId: user.sub,
|
||||||
name: user.preferred_username,
|
name: user.preferred_username,
|
||||||
organizations
|
organizations,
|
||||||
|
roles
|
||||||
},
|
},
|
||||||
jwt: {
|
jwt: {
|
||||||
accessToken: tokens.access_token,
|
accessToken: tokens.access_token,
|
||||||
@@ -54,3 +56,7 @@ function extractOrganizations(decoded: KeycloakTokenPayload): Organization[] {
|
|||||||
|
|
||||||
return organizations
|
return organizations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function extractRoles(decoded: KeycloakTokenPayload): string[] {
|
||||||
|
return decoded?.resource_access?.legalconsenthub?.roles ?? []
|
||||||
|
}
|
||||||
|
|||||||
2
legalconsenthub/types/auth.d.ts
vendored
2
legalconsenthub/types/auth.d.ts
vendored
@@ -3,11 +3,13 @@ declare module '#auth-utils' {
|
|||||||
keycloakId: string
|
keycloakId: string
|
||||||
name: string
|
name: string
|
||||||
organizations: Organization[]
|
organizations: Organization[]
|
||||||
|
roles: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
interface UserSession {
|
interface UserSession {
|
||||||
name: string
|
name: string
|
||||||
organizations: Organization[]
|
organizations: Organization[]
|
||||||
|
roles: string[]
|
||||||
loggedInAt: number
|
loggedInAt: number
|
||||||
jwt: {
|
jwt: {
|
||||||
accessToken: string
|
accessToken: string
|
||||||
|
|||||||
@@ -5,6 +5,11 @@ export interface KeycloakTokenPayload {
|
|||||||
family_name?: string
|
family_name?: string
|
||||||
email?: string
|
email?: string
|
||||||
organization?: Record<string, { id?: string }>
|
organization?: Record<string, { id?: string }>
|
||||||
|
resource_access?: {
|
||||||
|
legalconsenthub?: {
|
||||||
|
roles?: string[]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Organization {
|
export interface Organization {
|
||||||
|
|||||||
Reference in New Issue
Block a user