feature/#30-group-authentication #31

Merged
william merged 10 commits from feature/#30-group-authentication into develop 2022-08-03 08:04:11 -04:00
29 changed files with 397 additions and 143 deletions
Showing only changes of commit a3b49804a5 - Show all commits

View File

@ -3,15 +3,16 @@ package dev.fyloz.colorrecipesexplorer
object Constants {
object ControllerPaths {
const val COMPANY = "/api/company"
const val GROUP_TOKEN = "/api/account/group/token"
const val FILE = "/api/file"
const val GROUP = "/api/user/group"
const val GROUP = "/api/account/group"
const val INVENTORY = "/api/inventory"
const val MATERIAL = "/api/material"
const val MATERIAL_TYPE = "/api/materialtype"
const val MIX = "/api/recipe/mix"
const val RECIPE = "/api/recipe"
const val TOUCH_UP_KIT = "/api/touchupkit"
const val USER = "/api/user"
const val USER = "/api/account/user"
}
object FilePaths {
@ -25,6 +26,7 @@ object Constants {
object ModelNames {
const val COMPANY = "Company"
const val GROUP_TOKEN = "GroupToken"
const val GROUP = "Group"
const val MATERIAL = "Material"
const val MATERIAL_TYPE = "MaterialType"
@ -47,4 +49,4 @@ object Constants {
object ValidationRegexes {
const val VALIDATION_COLOR_PATTERN = "^#([0-9a-f]{6})$"
}
}
}

View File

@ -2,6 +2,12 @@ package dev.fyloz.colorrecipesexplorer.config.annotations
import org.springframework.security.access.prepost.PreAuthorize
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
@PreAuthorize("hasAuthority('ADMIN')")
annotation class PreAuthorizeAdmin
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented

View File

@ -2,12 +2,12 @@ package dev.fyloz.colorrecipesexplorer.config.security
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import dev.fyloz.colorrecipesexplorer.config.properties.CreSecurityProperties
import dev.fyloz.colorrecipesexplorer.dtos.UserDetails
import dev.fyloz.colorrecipesexplorer.dtos.UserDto
import dev.fyloz.colorrecipesexplorer.dtos.UserLoginRequestDto
import dev.fyloz.colorrecipesexplorer.dtos.account.UserDetails
import dev.fyloz.colorrecipesexplorer.dtos.account.UserDto
import dev.fyloz.colorrecipesexplorer.dtos.account.UserLoginRequestDto
import dev.fyloz.colorrecipesexplorer.exception.NotFoundException
import dev.fyloz.colorrecipesexplorer.logic.users.JwtLogic
import dev.fyloz.colorrecipesexplorer.logic.users.UserDetailsLogic
import dev.fyloz.colorrecipesexplorer.logic.account.JwtLogic
import dev.fyloz.colorrecipesexplorer.logic.account.UserDetailsLogic
import dev.fyloz.colorrecipesexplorer.utils.addCookie
import io.jsonwebtoken.ExpiredJwtException
import org.springframework.security.authentication.AuthenticationManager

View File

@ -1,11 +1,11 @@
package dev.fyloz.colorrecipesexplorer.config.security
import dev.fyloz.colorrecipesexplorer.config.properties.CreSecurityProperties
import dev.fyloz.colorrecipesexplorer.dtos.UserDto
import dev.fyloz.colorrecipesexplorer.dtos.account.UserDto
import dev.fyloz.colorrecipesexplorer.emergencyMode
import dev.fyloz.colorrecipesexplorer.logic.users.JwtLogic
import dev.fyloz.colorrecipesexplorer.logic.users.UserDetailsLogic
import dev.fyloz.colorrecipesexplorer.logic.users.UserLogic
import dev.fyloz.colorrecipesexplorer.logic.account.JwtLogic
import dev.fyloz.colorrecipesexplorer.logic.account.UserDetailsLogic
import dev.fyloz.colorrecipesexplorer.logic.account.UserLogic
import dev.fyloz.colorrecipesexplorer.model.account.Permission
import mu.KotlinLogging
import org.slf4j.Logger

View File

@ -2,6 +2,7 @@ package dev.fyloz.colorrecipesexplorer.dtos
import com.fasterxml.jackson.annotation.JsonIgnore
import dev.fyloz.colorrecipesexplorer.Constants
import dev.fyloz.colorrecipesexplorer.dtos.account.GroupDto
import java.time.LocalDate
import javax.validation.constraints.Max
import javax.validation.constraints.Min
@ -118,4 +119,4 @@ data class RecipePublicDataDto(
val notes: List<RecipeGroupNoteDto>,
val mixesLocation: List<MixLocationDto>
)
)

View File

@ -1,6 +1,7 @@
package dev.fyloz.colorrecipesexplorer.dtos
package dev.fyloz.colorrecipesexplorer.dtos.account
import com.fasterxml.jackson.annotation.JsonIgnore
import dev.fyloz.colorrecipesexplorer.dtos.EntityDto
import dev.fyloz.colorrecipesexplorer.model.account.Permission
import javax.validation.constraints.NotBlank
import javax.validation.constraints.NotEmpty

View File

@ -0,0 +1,21 @@
package dev.fyloz.colorrecipesexplorer.dtos.account
import java.util.UUID
import javax.validation.constraints.NotBlank
data class GroupTokenDto(
val id: UUID,
val name: String,
val isValid: Boolean,
val group: GroupDto
)
data class GroupTokenSaveDto(
@field:NotBlank
val name: String,
val groupId: Long
)

View File

@ -1,8 +1,9 @@
package dev.fyloz.colorrecipesexplorer.dtos
package dev.fyloz.colorrecipesexplorer.dtos.account
import com.fasterxml.jackson.annotation.JsonIgnore
import dev.fyloz.colorrecipesexplorer.Constants
import dev.fyloz.colorrecipesexplorer.SpringUserDetails
import dev.fyloz.colorrecipesexplorer.dtos.EntityDto
import dev.fyloz.colorrecipesexplorer.model.account.Permission
import dev.fyloz.colorrecipesexplorer.model.account.toAuthority
import java.time.LocalDateTime
@ -57,8 +58,6 @@ data class UserSaveDto(
val permissions: List<Permission>,
// TODO WN: Test if working
// @JsonProperty(access = JsonProperty.Access.READ_ONLY)
@field:JsonIgnore
val isSystemUser: Boolean = false,
@ -91,4 +90,4 @@ class UserDetails(val user: UserDto) : SpringUserDetails {
override fun isAccountNonLocked() = true
override fun isCredentialsNonExpired() = true
override fun isEnabled() = true
}
}

View File

@ -5,7 +5,7 @@ import dev.fyloz.colorrecipesexplorer.config.annotations.LogicComponent
import dev.fyloz.colorrecipesexplorer.dtos.*
import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException
import dev.fyloz.colorrecipesexplorer.logic.files.WriteableFileLogic
import dev.fyloz.colorrecipesexplorer.logic.users.GroupLogic
import dev.fyloz.colorrecipesexplorer.logic.account.GroupLogic
import dev.fyloz.colorrecipesexplorer.service.RecipeService
import dev.fyloz.colorrecipesexplorer.utils.collections.LazyMapList
import dev.fyloz.colorrecipesexplorer.utils.merge

View File

@ -2,13 +2,12 @@ package dev.fyloz.colorrecipesexplorer.logic
import dev.fyloz.colorrecipesexplorer.Constants
import dev.fyloz.colorrecipesexplorer.config.annotations.LogicComponent
import dev.fyloz.colorrecipesexplorer.dtos.GroupDto
import dev.fyloz.colorrecipesexplorer.dtos.account.GroupDto
import dev.fyloz.colorrecipesexplorer.dtos.RecipeGroupInformationDto
import dev.fyloz.colorrecipesexplorer.dtos.RecipeStepDto
import dev.fyloz.colorrecipesexplorer.exception.InvalidPositionError
import dev.fyloz.colorrecipesexplorer.exception.InvalidPositionsException
import dev.fyloz.colorrecipesexplorer.exception.RestException
import dev.fyloz.colorrecipesexplorer.model.account.Group
import dev.fyloz.colorrecipesexplorer.service.RecipeStepService
import dev.fyloz.colorrecipesexplorer.utils.PositionUtils
import org.springframework.http.HttpStatus
@ -46,4 +45,4 @@ class InvalidGroupStepsPositionsException(
) {
val errors: Set<InvalidPositionError>
get() = exception.errors
}
}

View File

@ -1,14 +1,14 @@
package dev.fyloz.colorrecipesexplorer.logic.users
package dev.fyloz.colorrecipesexplorer.logic.account
import dev.fyloz.colorrecipesexplorer.Constants
import dev.fyloz.colorrecipesexplorer.config.annotations.LogicComponent
import dev.fyloz.colorrecipesexplorer.config.security.defaultGroupCookieName
import dev.fyloz.colorrecipesexplorer.dtos.GroupDto
import dev.fyloz.colorrecipesexplorer.dtos.UserDto
import dev.fyloz.colorrecipesexplorer.dtos.account.GroupDto
import dev.fyloz.colorrecipesexplorer.dtos.account.UserDto
import dev.fyloz.colorrecipesexplorer.exception.NoDefaultGroupException
import dev.fyloz.colorrecipesexplorer.logic.BaseLogic
import dev.fyloz.colorrecipesexplorer.logic.Logic
import dev.fyloz.colorrecipesexplorer.service.GroupService
import dev.fyloz.colorrecipesexplorer.service.account.GroupService
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.util.WebUtils
import javax.servlet.http.HttpServletRequest
@ -77,4 +77,4 @@ class DefaultGroupLogic(service: GroupService, private val userLogic: UserLogic)
throw alreadyExistsException(value = name)
}
}
}
}

View File

@ -0,0 +1,85 @@
package dev.fyloz.colorrecipesexplorer.logic.account
import dev.fyloz.colorrecipesexplorer.Constants
import dev.fyloz.colorrecipesexplorer.config.annotations.LogicComponent
import dev.fyloz.colorrecipesexplorer.dtos.account.GroupTokenDto
import dev.fyloz.colorrecipesexplorer.dtos.account.GroupTokenSaveDto
import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException
import dev.fyloz.colorrecipesexplorer.exception.NotFoundException
import dev.fyloz.colorrecipesexplorer.logic.BaseLogic
import dev.fyloz.colorrecipesexplorer.service.account.GroupTokenService
import java.util.UUID
interface GroupTokenLogic {
fun getAll(): Collection<GroupTokenDto>
fun getById(id: String): GroupTokenDto
fun save(dto: GroupTokenSaveDto): GroupTokenDto
fun deleteById(id: String)
}
@LogicComponent
class DefaultGroupTokenLogic(private val service: GroupTokenService, private val groupLogic: GroupLogic) :
GroupTokenLogic {
private val typeName = Constants.ModelNames.GROUP_TOKEN
private val typeNameLowerCase = typeName.lowercase()
override fun getAll() = service.getAll()
override fun getById(id: String) =
service.getById(UUID.fromString(id)) ?: throw notFoundException(value = id)
override fun save(dto: GroupTokenSaveDto): GroupTokenDto {
throwIfNameAlreadyExists(dto.name)
val token = GroupTokenDto(
generateUniqueUUIDForName(dto.name),
dto.name,
true,
groupLogic.getById(dto.groupId)
)
return service.save(token)
}
override fun deleteById(id: String) {
service.deleteById(UUID.fromString(id))
}
private fun generateUniqueUUIDForName(name: String): UUID {
var id = generateUUIDForName(name)
// UUIDs do not guarantee that collisions can't happen
while (service.existsById(id)) {
id = generateUUIDForName(name)
}
return id
}
private fun generateUUIDForName(name: String) =
UUID.nameUUIDFromBytes(name.toByteArray())
private fun throwIfNameAlreadyExists(name: String) {
if (service.existsByName(name)) {
throw alreadyExistsException(value = name)
}
}
private fun notFoundException(identifierName: String = BaseLogic.ID_IDENTIFIER_NAME, value: Any) =
NotFoundException(
typeNameLowerCase,
"$typeName not found",
"A $typeNameLowerCase with the $identifierName '$value' could not be found",
value,
identifierName
)
private fun alreadyExistsException(identifierName: String = BaseLogic.NAME_IDENTIFIER_NAME, value: Any) =
AlreadyExistsException(
typeNameLowerCase,
"$typeName already exists",
"A $typeNameLowerCase with the $identifierName '$value' already exists",
value,
identifierName
)
}

View File

@ -1,10 +1,10 @@
package dev.fyloz.colorrecipesexplorer.logic.users
package dev.fyloz.colorrecipesexplorer.logic.account
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import dev.fyloz.colorrecipesexplorer.config.properties.CreSecurityProperties
import dev.fyloz.colorrecipesexplorer.dtos.UserDetails
import dev.fyloz.colorrecipesexplorer.dtos.UserDto
import dev.fyloz.colorrecipesexplorer.dtos.account.UserDetails
import dev.fyloz.colorrecipesexplorer.dtos.account.UserDto
import dev.fyloz.colorrecipesexplorer.utils.base64encode
import dev.fyloz.colorrecipesexplorer.utils.toDate
import io.jsonwebtoken.Jwts

View File

@ -1,11 +1,11 @@
package dev.fyloz.colorrecipesexplorer.logic.users
package dev.fyloz.colorrecipesexplorer.logic.account
import dev.fyloz.colorrecipesexplorer.SpringUserDetails
import dev.fyloz.colorrecipesexplorer.SpringUserDetailsService
import dev.fyloz.colorrecipesexplorer.config.annotations.RequireDatabase
import dev.fyloz.colorrecipesexplorer.config.properties.CreSecurityProperties
import dev.fyloz.colorrecipesexplorer.dtos.UserDetails
import dev.fyloz.colorrecipesexplorer.dtos.UserDto
import dev.fyloz.colorrecipesexplorer.dtos.account.UserDetails
import dev.fyloz.colorrecipesexplorer.dtos.account.UserDto
import dev.fyloz.colorrecipesexplorer.exception.NotFoundException
import dev.fyloz.colorrecipesexplorer.model.account.Permission
import dev.fyloz.colorrecipesexplorer.model.account.User

View File

@ -1,20 +1,19 @@
package dev.fyloz.colorrecipesexplorer.logic.users
package dev.fyloz.colorrecipesexplorer.logic.account
import dev.fyloz.colorrecipesexplorer.Constants
import dev.fyloz.colorrecipesexplorer.config.annotations.LogicComponent
import dev.fyloz.colorrecipesexplorer.config.security.authorizationCookieName
import dev.fyloz.colorrecipesexplorer.config.security.blacklistedJwtTokens
import dev.fyloz.colorrecipesexplorer.dtos.GroupDto
import dev.fyloz.colorrecipesexplorer.dtos.UserDto
import dev.fyloz.colorrecipesexplorer.dtos.UserSaveDto
import dev.fyloz.colorrecipesexplorer.dtos.UserUpdateDto
import dev.fyloz.colorrecipesexplorer.dtos.account.GroupDto
import dev.fyloz.colorrecipesexplorer.dtos.account.UserDto
import dev.fyloz.colorrecipesexplorer.dtos.account.UserSaveDto
import dev.fyloz.colorrecipesexplorer.dtos.account.UserUpdateDto
import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException
import dev.fyloz.colorrecipesexplorer.logic.BaseLogic
import dev.fyloz.colorrecipesexplorer.logic.Logic
import dev.fyloz.colorrecipesexplorer.model.account.Permission
import dev.fyloz.colorrecipesexplorer.service.UserService
import dev.fyloz.colorrecipesexplorer.service.account.UserService
import org.springframework.context.annotation.Lazy
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.web.util.WebUtils
import java.time.LocalDateTime
@ -166,4 +165,4 @@ class DefaultUserLogic(
)
}
}
}
}

View File

@ -0,0 +1,26 @@
package dev.fyloz.colorrecipesexplorer.model.account
import java.util.UUID
import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.Id
import javax.persistence.JoinColumn
import javax.persistence.ManyToOne
import javax.persistence.Table
@Entity
@Table(name = "group_token")
data class GroupToken(
@Id
val id: UUID,
@Column(unique = true)
val name: String,
@Column(name = "is_valid")
val isValid: Boolean,
@ManyToOne
@JoinColumn(name = "group_id")
val group: Group
)

View File

@ -1,10 +1,12 @@
package dev.fyloz.colorrecipesexplorer.repository
import dev.fyloz.colorrecipesexplorer.model.account.GroupToken
import dev.fyloz.colorrecipesexplorer.model.account.Group
import dev.fyloz.colorrecipesexplorer.model.account.User
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query
import org.springframework.stereotype.Repository
import java.util.UUID
@Repository
interface UserRepository : JpaRepository<User, Long> {
@ -28,3 +30,9 @@ interface GroupRepository : JpaRepository<Group, Long> {
/** Checks if a group with the given [name] and a different [id] exists. */
fun existsByNameAndIdNot(name: String, id: Long): Boolean
}
@Repository
interface GroupTokenRepository : JpaRepository<GroupToken, UUID> {
/** Checks if a token with the given [name] exists. */
fun existsByName(name: String): Boolean
}

View File

@ -0,0 +1,82 @@
package dev.fyloz.colorrecipesexplorer.rest.account
import dev.fyloz.colorrecipesexplorer.Constants
import dev.fyloz.colorrecipesexplorer.config.annotations.PreAuthorizeEditUsers
import dev.fyloz.colorrecipesexplorer.config.annotations.PreAuthorizeViewUsers
import dev.fyloz.colorrecipesexplorer.dtos.account.GroupDto
import dev.fyloz.colorrecipesexplorer.logic.account.GroupLogic
import dev.fyloz.colorrecipesexplorer.logic.account.UserLogic
import dev.fyloz.colorrecipesexplorer.rest.created
import dev.fyloz.colorrecipesexplorer.rest.noContent
import dev.fyloz.colorrecipesexplorer.rest.ok
import org.springframework.context.annotation.Profile
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.web.bind.annotation.*
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import javax.validation.Valid
@RestController
@RequestMapping(Constants.ControllerPaths.GROUP)
@Profile("!emergency")
class GroupController(
private val groupLogic: GroupLogic,
private val userLogic: UserLogic
) {
@GetMapping
@PreAuthorize("hasAnyAuthority('VIEW_RECIPES', 'VIEW_USERS')")
fun getAll() =
ok(groupLogic.getAll())
@GetMapping("{id}")
@PreAuthorizeViewUsers
fun getById(@PathVariable id: Long) =
ok(groupLogic.getById(id))
@GetMapping("{id}/users")
@PreAuthorizeViewUsers
fun getUsersForGroup(@PathVariable id: Long) =
ok(groupLogic.getUsersForGroup(id))
@PostMapping("default/{groupId}")
@PreAuthorizeViewUsers
fun setDefaultGroup(@PathVariable groupId: Long, response: HttpServletResponse) =
noContent {
groupLogic.setResponseDefaultGroup(groupId, response)
}
@GetMapping("default")
@PreAuthorizeViewUsers
fun getRequestDefaultGroup(request: HttpServletRequest) =
ok(with(groupLogic) {
getRequestDefaultGroup(request)
})
@GetMapping("currentuser")
fun getCurrentGroupUser(request: HttpServletRequest) =
ok(with(groupLogic.getRequestDefaultGroup(request)) {
userLogic.getDefaultGroupUser(this)
})
@PostMapping
@PreAuthorizeEditUsers
fun save(@Valid @RequestBody group: GroupDto) =
created<GroupDto>(Constants.ControllerPaths.GROUP) {
groupLogic.save(group)
}
@PutMapping
@PreAuthorizeEditUsers
fun update(@Valid @RequestBody group: GroupDto) =
noContent {
groupLogic.update(group)
}
@DeleteMapping("{id}")
@PreAuthorizeEditUsers
fun deleteById(@PathVariable id: Long) =
noContent {
groupLogic.deleteById(id)
}
}

View File

@ -0,0 +1,40 @@
package dev.fyloz.colorrecipesexplorer.rest.account
import dev.fyloz.colorrecipesexplorer.Constants
import dev.fyloz.colorrecipesexplorer.config.annotations.PreAuthorizeAdmin
import dev.fyloz.colorrecipesexplorer.dtos.account.GroupTokenSaveDto
import dev.fyloz.colorrecipesexplorer.logic.account.GroupTokenLogic
import dev.fyloz.colorrecipesexplorer.rest.created
import dev.fyloz.colorrecipesexplorer.rest.noContent
import dev.fyloz.colorrecipesexplorer.rest.ok
import org.springframework.context.annotation.Profile
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.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import javax.validation.Valid
@RestController
@RequestMapping(Constants.ControllerPaths.GROUP_TOKEN)
@PreAuthorizeAdmin
@Profile("!emergency")
class GroupTokenController(private val groupTokenLogic: GroupTokenLogic) {
@GetMapping
fun getAll() = ok(groupTokenLogic.getAll())
@GetMapping("{id}")
fun getById(@PathVariable id: String) = ok(groupTokenLogic.getById(id))
@PostMapping
fun save(@RequestBody @Valid dto: GroupTokenSaveDto) = with(groupTokenLogic.save(dto)) {
created(Constants.ControllerPaths.GROUP_TOKEN, this, this.id)
}
@DeleteMapping("{id}")
fun deleteById(@PathVariable id: String) = noContent {
groupTokenLogic.deleteById(id)
}
}

View File

@ -1,21 +1,21 @@
package dev.fyloz.colorrecipesexplorer.rest
package dev.fyloz.colorrecipesexplorer.rest.account
import dev.fyloz.colorrecipesexplorer.Constants
import dev.fyloz.colorrecipesexplorer.config.annotations.PreAuthorizeEditUsers
import dev.fyloz.colorrecipesexplorer.config.annotations.PreAuthorizeViewUsers
import dev.fyloz.colorrecipesexplorer.dtos.GroupDto
import dev.fyloz.colorrecipesexplorer.dtos.UserDto
import dev.fyloz.colorrecipesexplorer.dtos.UserSaveDto
import dev.fyloz.colorrecipesexplorer.dtos.UserUpdateDto
import dev.fyloz.colorrecipesexplorer.logic.users.GroupLogic
import dev.fyloz.colorrecipesexplorer.logic.users.UserLogic
import dev.fyloz.colorrecipesexplorer.dtos.account.UserDto
import dev.fyloz.colorrecipesexplorer.dtos.account.UserSaveDto
import dev.fyloz.colorrecipesexplorer.dtos.account.UserUpdateDto
import dev.fyloz.colorrecipesexplorer.logic.account.UserLogic
import dev.fyloz.colorrecipesexplorer.model.account.Permission
import dev.fyloz.colorrecipesexplorer.rest.created
import dev.fyloz.colorrecipesexplorer.rest.noContent
import dev.fyloz.colorrecipesexplorer.rest.ok
import org.springframework.context.annotation.Profile
import org.springframework.http.MediaType
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.web.bind.annotation.*
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import javax.validation.Valid
@RestController
@ -77,70 +77,6 @@ class UserController(private val userLogic: UserLogic) {
userLogic.deleteById(id)
}
@RestController
@RequestMapping(Constants.ControllerPaths.GROUP)
@Profile("!emergency")
class GroupsController(
private val groupLogic: GroupLogic,
private val userLogic: UserLogic
) {
@GetMapping
@PreAuthorize("hasAnyAuthority('VIEW_RECIPES', 'VIEW_USERS')")
fun getAll() =
ok(groupLogic.getAll())
@GetMapping("{id}")
@PreAuthorizeViewUsers
fun getById(@PathVariable id: Long) =
ok(groupLogic.getById(id))
@GetMapping("{id}/users")
@PreAuthorizeViewUsers
fun getUsersForGroup(@PathVariable id: Long) =
ok(groupLogic.getUsersForGroup(id))
@PostMapping("default/{groupId}")
@PreAuthorizeViewUsers
fun setDefaultGroup(@PathVariable groupId: Long, response: HttpServletResponse) =
noContent {
groupLogic.setResponseDefaultGroup(groupId, response)
}
@GetMapping("default")
@PreAuthorizeViewUsers
fun getRequestDefaultGroup(request: HttpServletRequest) =
ok(with(groupLogic) {
getRequestDefaultGroup(request)
})
@GetMapping("currentuser")
fun getCurrentGroupUser(request: HttpServletRequest) =
ok(with(groupLogic.getRequestDefaultGroup(request)) {
userLogic.getDefaultGroupUser(this)
})
@PostMapping
@PreAuthorizeEditUsers
fun save(@Valid @RequestBody group: GroupDto) =
created<GroupDto>(Constants.ControllerPaths.GROUP) {
groupLogic.save(group)
}
@PutMapping
@PreAuthorizeEditUsers
fun update(@Valid @RequestBody group: GroupDto) =
noContent {
groupLogic.update(group)
}
@DeleteMapping("{id}")
@PreAuthorizeEditUsers
fun deleteById(@PathVariable id: Long) =
noContent {
groupLogic.deleteById(id)
}
}
@RestController
@RequestMapping("api")
@Profile("!emergency")

View File

@ -8,6 +8,7 @@ import dev.fyloz.colorrecipesexplorer.model.ConfigurationType
import dev.fyloz.colorrecipesexplorer.model.Recipe
import dev.fyloz.colorrecipesexplorer.model.RecipeGroupInformation
import dev.fyloz.colorrecipesexplorer.repository.RecipeRepository
import dev.fyloz.colorrecipesexplorer.service.account.GroupService
import dev.fyloz.colorrecipesexplorer.utils.collections.lazyMap
import org.springframework.transaction.annotation.Transactional
import java.time.LocalDate
@ -89,4 +90,4 @@ class DefaultRecipeService(
with(Period.parse(configLogic.getContent(ConfigurationType.RECIPE_APPROBATION_EXPIRATION))) {
recipe.approbationDate?.plus(this)?.isBefore(LocalDate.now())
}
}
}

View File

@ -1,11 +1,13 @@
package dev.fyloz.colorrecipesexplorer.service
package dev.fyloz.colorrecipesexplorer.service.account
import dev.fyloz.colorrecipesexplorer.config.annotations.ServiceComponent
import dev.fyloz.colorrecipesexplorer.dtos.GroupDto
import dev.fyloz.colorrecipesexplorer.dtos.account.GroupDto
import dev.fyloz.colorrecipesexplorer.model.account.Group
import dev.fyloz.colorrecipesexplorer.model.account.Permission
import dev.fyloz.colorrecipesexplorer.model.account.flat
import dev.fyloz.colorrecipesexplorer.repository.GroupRepository
import dev.fyloz.colorrecipesexplorer.service.BaseService
import dev.fyloz.colorrecipesexplorer.service.Service
interface GroupService : Service<GroupDto, Group, GroupRepository> {
/** Checks if a group with the given [name] and a different [id] exists. */
@ -28,4 +30,4 @@ class DefaultGroupService(repository: GroupRepository) : BaseService<GroupDto, G
override fun flattenPermissions(group: Group) =
group.permissions.flatMap { it.flat() }.filter { !it.deprecated }
}
}

View File

@ -0,0 +1,48 @@
package dev.fyloz.colorrecipesexplorer.service.account
import dev.fyloz.colorrecipesexplorer.config.annotations.ServiceComponent
import dev.fyloz.colorrecipesexplorer.dtos.account.GroupTokenDto
import dev.fyloz.colorrecipesexplorer.model.account.GroupToken
import dev.fyloz.colorrecipesexplorer.repository.GroupTokenRepository
import org.springframework.data.repository.findByIdOrNull
import java.util.UUID
interface GroupTokenService {
fun existsById(id: UUID): Boolean
fun existsByName(name: String): Boolean
fun getAll(): Collection<GroupTokenDto>
fun getById(id: UUID): GroupTokenDto?
fun save(token: GroupTokenDto): GroupTokenDto
fun deleteById(id: UUID)
fun toDto(entity: GroupToken): GroupTokenDto
fun toEntity(dto: GroupTokenDto): GroupToken
}
@ServiceComponent
class DefaultGroupTokenService(private val repository: GroupTokenRepository, private val groupService: GroupService) :
GroupTokenService {
override fun existsById(id: UUID) = repository.existsById(id)
override fun existsByName(name: String) = repository.existsByName(name)
override fun getAll() = repository.findAll().map(::toDto)
override fun getById(id: UUID): GroupTokenDto? {
val entity = repository.findByIdOrNull(id)
return if (entity != null) toDto(entity) else null
}
override fun save(token: GroupTokenDto): GroupTokenDto {
val entity = repository.save(toEntity(token))
return toDto(entity)
}
override fun deleteById(id: UUID) = repository.deleteById(id)
override fun toDto(entity: GroupToken) =
GroupTokenDto(entity.id, entity.name, entity.isValid, groupService.toDto(entity.group))
override fun toEntity(dto: GroupTokenDto) =
GroupToken(dto.id, dto.name, dto.isValid, groupService.toEntity(dto.group))
}

View File

@ -1,12 +1,14 @@
package dev.fyloz.colorrecipesexplorer.service
package dev.fyloz.colorrecipesexplorer.service.account
import dev.fyloz.colorrecipesexplorer.config.annotations.ServiceComponent
import dev.fyloz.colorrecipesexplorer.dtos.GroupDto
import dev.fyloz.colorrecipesexplorer.dtos.UserDto
import dev.fyloz.colorrecipesexplorer.dtos.account.GroupDto
import dev.fyloz.colorrecipesexplorer.dtos.account.UserDto
import dev.fyloz.colorrecipesexplorer.model.account.Permission
import dev.fyloz.colorrecipesexplorer.model.account.User
import dev.fyloz.colorrecipesexplorer.model.account.flat
import dev.fyloz.colorrecipesexplorer.repository.UserRepository
import dev.fyloz.colorrecipesexplorer.service.BaseService
import dev.fyloz.colorrecipesexplorer.service.Service
import org.springframework.data.repository.findByIdOrNull
interface UserService : Service<UserDto, User, UserRepository> {
@ -100,4 +102,4 @@ class DefaultUserService(repository: UserRepository, private val groupService: G
return perms
}
}
}

View File

@ -3,10 +3,10 @@ package dev.fyloz.colorrecipesexplorer.logic
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import dev.fyloz.colorrecipesexplorer.config.properties.CreSecurityProperties
import dev.fyloz.colorrecipesexplorer.dtos.UserDetails
import dev.fyloz.colorrecipesexplorer.dtos.UserDto
import dev.fyloz.colorrecipesexplorer.logic.users.DefaultJwtLogic
import dev.fyloz.colorrecipesexplorer.logic.users.jwtClaimUser
import dev.fyloz.colorrecipesexplorer.dtos.account.UserDetails
import dev.fyloz.colorrecipesexplorer.dtos.account.UserDto
import dev.fyloz.colorrecipesexplorer.logic.account.DefaultJwtLogic
import dev.fyloz.colorrecipesexplorer.logic.account.jwtClaimUser
import dev.fyloz.colorrecipesexplorer.utils.base64encode
import dev.fyloz.colorrecipesexplorer.utils.isAround
import io.jsonwebtoken.Jwts

View File

@ -2,7 +2,7 @@ package dev.fyloz.colorrecipesexplorer.logic
import dev.fyloz.colorrecipesexplorer.dtos.*
import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException
import dev.fyloz.colorrecipesexplorer.logic.users.GroupLogic
import dev.fyloz.colorrecipesexplorer.logic.account.GroupLogic
import dev.fyloz.colorrecipesexplorer.service.RecipeService
import io.mockk.*
import org.junit.jupiter.api.AfterEach
@ -213,4 +213,4 @@ class DefaultRecipeLogicTest {
mixLogicMock.updateLocations(any())
}
}
}
}

View File

@ -1,6 +1,6 @@
package dev.fyloz.colorrecipesexplorer.logic
import dev.fyloz.colorrecipesexplorer.dtos.GroupDto
import dev.fyloz.colorrecipesexplorer.dtos.account.GroupDto
import dev.fyloz.colorrecipesexplorer.dtos.RecipeGroupInformationDto
import dev.fyloz.colorrecipesexplorer.dtos.RecipeStepDto
import dev.fyloz.colorrecipesexplorer.exception.InvalidPositionError
@ -57,4 +57,4 @@ class DefaultRecipeStepLogicTest {
// Assert
assertThrows<InvalidGroupStepsPositionsException> { recipeStepLogic.validateGroupInformationSteps(groupInfo) }
}
}
}

View File

@ -1,11 +1,9 @@
package dev.fyloz.colorrecipesexplorer.logic.account
import dev.fyloz.colorrecipesexplorer.dtos.GroupDto
import dev.fyloz.colorrecipesexplorer.dtos.UserDto
import dev.fyloz.colorrecipesexplorer.dtos.account.GroupDto
import dev.fyloz.colorrecipesexplorer.dtos.account.UserDto
import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException
import dev.fyloz.colorrecipesexplorer.logic.users.DefaultGroupLogic
import dev.fyloz.colorrecipesexplorer.logic.users.UserLogic
import dev.fyloz.colorrecipesexplorer.service.GroupService
import dev.fyloz.colorrecipesexplorer.service.account.GroupService
import io.mockk.*
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Test
@ -84,4 +82,4 @@ class DefaultGroupLogicTest {
userLogicMock.deleteById(group.defaultGroupUserId)
}
}
}
}

View File

@ -1,15 +1,13 @@
package dev.fyloz.colorrecipesexplorer.logic.account
import dev.fyloz.colorrecipesexplorer.dtos.GroupDto
import dev.fyloz.colorrecipesexplorer.dtos.UserDto
import dev.fyloz.colorrecipesexplorer.dtos.UserSaveDto
import dev.fyloz.colorrecipesexplorer.dtos.UserUpdateDto
import dev.fyloz.colorrecipesexplorer.dtos.account.GroupDto
import dev.fyloz.colorrecipesexplorer.dtos.account.UserDto
import dev.fyloz.colorrecipesexplorer.dtos.account.UserSaveDto
import dev.fyloz.colorrecipesexplorer.dtos.account.UserUpdateDto
import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException
import dev.fyloz.colorrecipesexplorer.exception.NotFoundException
import dev.fyloz.colorrecipesexplorer.logic.users.DefaultUserLogic
import dev.fyloz.colorrecipesexplorer.logic.users.GroupLogic
import dev.fyloz.colorrecipesexplorer.model.account.Permission
import dev.fyloz.colorrecipesexplorer.service.UserService
import dev.fyloz.colorrecipesexplorer.service.account.UserService
import io.mockk.*
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Test
@ -303,4 +301,4 @@ class DefaultUserLogicTest {
userLogic.update(user)
}
}
}
}