Cleanup
This commit is contained in:
parent
50442d7ebc
commit
ed8abaa456
|
@ -90,7 +90,11 @@ tasks.withType<JavaCompile> {
|
|||
}
|
||||
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
|
||||
kotlinOptions.jvmTarget = "11"
|
||||
kotlinOptions {
|
||||
jvmTarget = "11"
|
||||
useIR = true
|
||||
freeCompilerArgs = freeCompilerArgs + "-Xopt-in=kotlin.contracts.ExperimentalContracts"
|
||||
}
|
||||
}
|
||||
|
||||
tasks.dokkaHtml {
|
||||
|
|
|
@ -13,12 +13,9 @@ import org.springframework.web.bind.annotation.ExceptionHandler
|
|||
import org.springframework.web.context.request.WebRequest
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler
|
||||
|
||||
abstract class RestException(val httpStatus: HttpStatus) : RuntimeException() {
|
||||
abstract val exceptionMessage: String
|
||||
abstract class RestException(val exceptionMessage: String, val httpStatus: HttpStatus) : RuntimeException(exceptionMessage) {
|
||||
abstract fun buildBody(): RestExceptionBody
|
||||
|
||||
override val message: String by lazy { exceptionMessage }
|
||||
|
||||
open inner class RestExceptionBody(val status: Int = httpStatus.value(), @JsonProperty("message") val message: String = exceptionMessage)
|
||||
}
|
||||
|
||||
|
|
|
@ -5,15 +5,32 @@ import dev.fyloz.trial.colorrecipesexplorer.model.Model
|
|||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.web.bind.annotation.ResponseStatus
|
||||
|
||||
class EntityAlreadyExistsException(modelType: Class<out Model>, val identifierType: IdentifierType, val identifierName: String?, val requestedId: Any) : ModelException(modelType) {
|
||||
constructor(modelType: Class<out Model>, identifierType: IdentifierType, requestedId: Any) : this(modelType, identifierType, identifierType.name, requestedId)
|
||||
constructor(exception: EntityAlreadyExistsException) : this(exception.type, exception.identifierType, exception.identifierName, exception.requestedId)
|
||||
class EntityAlreadyExistsException(
|
||||
modelType: Class<out Model>,
|
||||
val identifierType: IdentifierType,
|
||||
val identifierName: String?,
|
||||
val requestedId: Any
|
||||
) : ModelException(modelType) {
|
||||
constructor(modelType: Class<out Model>, identifierType: IdentifierType, requestedId: Any) : this(
|
||||
modelType,
|
||||
identifierType,
|
||||
identifierType.name,
|
||||
requestedId
|
||||
)
|
||||
|
||||
constructor(exception: EntityAlreadyExistsException) : this(
|
||||
exception.type,
|
||||
exception.identifierType,
|
||||
exception.identifierName,
|
||||
exception.requestedId
|
||||
)
|
||||
}
|
||||
|
||||
@ResponseStatus(HttpStatus.CONFLICT)
|
||||
class EntityAlreadyExistsRestException(val value: Any) : RestException(HttpStatus.CONFLICT) {
|
||||
override val exceptionMessage: String = "An entity with the given identifier already exists"
|
||||
class EntityAlreadyExistsRestException(val value: Any) :
|
||||
RestException("An entity with the given identifier already exists", HttpStatus.CONFLICT) {
|
||||
|
||||
@Suppress("unused")
|
||||
override fun buildBody(): RestExceptionBody = object : RestExceptionBody() {
|
||||
val id = value
|
||||
}
|
||||
|
|
|
@ -5,14 +5,17 @@ import dev.fyloz.trial.colorrecipesexplorer.model.Model
|
|||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.web.bind.annotation.ResponseStatus
|
||||
|
||||
class EntityNotFoundException(modelType: Class<out Model>, val identifierType: IdentifierType, val identifierName: String, val requestedId: Any) : ModelException(modelType) {
|
||||
constructor(modelType: Class<out Model>, identifierType: IdentifierType, requestedId: Any) : this(modelType, identifierType, identifierType.name, requestedId)
|
||||
}
|
||||
class EntityNotFoundException(
|
||||
modelType: Class<out Model>,
|
||||
val identifierType: IdentifierType,
|
||||
val requestedId: Any
|
||||
) : ModelException(modelType)
|
||||
|
||||
@ResponseStatus(HttpStatus.NOT_FOUND)
|
||||
class EntityNotFoundRestException(val value: Any) : RestException(HttpStatus.NOT_FOUND) {
|
||||
override val exceptionMessage: String = "An entity could not be found with the given identifier"
|
||||
class EntityNotFoundRestException(val value: Any) :
|
||||
RestException("An entity could not be found with the given identifier", HttpStatus.NOT_FOUND) {
|
||||
|
||||
@Suppress("unused")
|
||||
override fun buildBody(): RestExceptionBody = object : RestExceptionBody() {
|
||||
val id = value
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ public class MixTypeJavaService extends AbstractJavaService<MixType, MixTypeRepo
|
|||
public MixType getByMaterial(Material material) {
|
||||
Optional<MixType> found = findOptional(repository.findByMaterial(material));
|
||||
if (found.isEmpty())
|
||||
throw new EntityNotFoundException(type, ModelException.IdentifierType.OTHER, MixTypeKt.IDENTIFIER_MATERIAL_NAME, material);
|
||||
throw new EntityNotFoundException(type, ModelException.IdentifierType.OTHER, material);
|
||||
|
||||
return found.get();
|
||||
}
|
||||
|
|
|
@ -2,20 +2,15 @@ package dev.fyloz.trial.colorrecipesexplorer
|
|||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.config.properties.CREProperties
|
||||
import dev.fyloz.trial.colorrecipesexplorer.config.properties.MaterialTypeProperties
|
||||
import org.slf4j.Logger
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||
import org.springframework.boot.jdbc.DataSourceBuilder
|
||||
import org.springframework.boot.runApplication
|
||||
import org.springframework.context.annotation.Bean
|
||||
import javax.sql.DataSource
|
||||
|
||||
@SpringBootApplication(exclude = [LiquibaseAutoConfiguration::class])
|
||||
@EnableConfigurationProperties(MaterialTypeProperties::class, CREProperties::class, DatabaseUpdaterProperties::class)
|
||||
class ColorRecipesExplorerApplication
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
fun main() {
|
||||
runApplication<ColorRecipesExplorerApplication>()
|
||||
}
|
||||
|
|
|
@ -189,9 +189,9 @@ const val defaultGroupCookieName = "Default-Group"
|
|||
val blacklistedJwtTokens = mutableListOf<String>()
|
||||
|
||||
class JwtAuthenticationFilter(
|
||||
val authManager: AuthenticationManager,
|
||||
val employeeService: EmployeeService,
|
||||
val securityConfigurationProperties: SecurityConfigurationProperties
|
||||
private val authManager: AuthenticationManager,
|
||||
private val employeeService: EmployeeService,
|
||||
private val securityConfigurationProperties: SecurityConfigurationProperties
|
||||
) : UsernamePasswordAuthenticationFilter() {
|
||||
private var debugMode = false
|
||||
|
||||
|
@ -238,8 +238,8 @@ class JwtAuthenticationFilter(
|
|||
}
|
||||
|
||||
class JwtAuthorizationFilter(
|
||||
val userDetailsService: EmployeeUserDetailsServiceImpl,
|
||||
val securityConfigurationProperties: SecurityConfigurationProperties,
|
||||
private val userDetailsService: EmployeeUserDetailsServiceImpl,
|
||||
private val securityConfigurationProperties: SecurityConfigurationProperties,
|
||||
authenticationManager: AuthenticationManager
|
||||
) : BasicAuthenticationFilter(authenticationManager) {
|
||||
override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain) {
|
||||
|
|
|
@ -2,6 +2,7 @@ package dev.fyloz.trial.colorrecipesexplorer.model
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import dev.fyloz.trial.colorrecipesexplorer.model.validation.NullOrNotBlank
|
||||
import org.hibernate.annotations.Fetch
|
||||
import org.hibernate.annotations.FetchMode
|
||||
import org.springframework.security.core.GrantedAuthority
|
||||
|
@ -109,18 +110,15 @@ open class EmployeeUpdateDto(
|
|||
@field:NotNull(message = EMPLOYEE_ID_NULL_MESSAGE)
|
||||
val id: Long,
|
||||
|
||||
@field:NotBlank(message = EMPLOYEE_FIRST_NAME_EMPTY_MESSAGE)
|
||||
val firstName: String = "",
|
||||
@field:NullOrNotBlank(message = EMPLOYEE_FIRST_NAME_EMPTY_MESSAGE)
|
||||
val firstName: String?,
|
||||
|
||||
@field:NotBlank(message = EMPLOYEE_LAST_NAME_EMPTY_MESSAGE)
|
||||
val lastName: String = "",
|
||||
@field:NullOrNotBlank(message = EMPLOYEE_LAST_NAME_EMPTY_MESSAGE)
|
||||
val lastName: String?,
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
val permissions: Set<EmployeePermission> = mutableSetOf()
|
||||
) : EntityDto<Employee> {
|
||||
override fun toEntity(): Employee =
|
||||
Employee(id, firstName, lastName, permissions = permissions.toMutableSet())
|
||||
}
|
||||
val permissions: Set<EmployeePermission>?
|
||||
) : EntityDto<Employee>
|
||||
|
||||
|
||||
private const val GROUP_ID_NULL_MESSAGE = "Un identifiant est requis"
|
||||
|
@ -148,6 +146,7 @@ data class EmployeeGroup(
|
|||
@JsonIgnore
|
||||
val employees: MutableSet<Employee> = mutableSetOf()
|
||||
) : NamedModel {
|
||||
@JsonProperty("employeeCount")
|
||||
fun getEmployeeCount() = employees.size
|
||||
|
||||
override fun equals(other: Any?): Boolean = other is EmployeeGroup && id == other.id && name == other.name
|
||||
|
@ -313,16 +312,6 @@ fun employee(
|
|||
lastLoginTime
|
||||
).apply(op)
|
||||
|
||||
fun employee(
|
||||
employee: Employee,
|
||||
newId: Long? = null
|
||||
) = with(employee) {
|
||||
Employee(
|
||||
newId
|
||||
?: id, firstName, lastName, password, isDefaultGroupUser, isSystemUser, group, permissions, lastLoginTime
|
||||
)
|
||||
}
|
||||
|
||||
fun employeeSaveDto(
|
||||
passwordEncoder: PasswordEncoder = BCryptPasswordEncoder(),
|
||||
id: Long = 0L,
|
||||
|
@ -350,12 +339,6 @@ fun employeeGroup(
|
|||
op: EmployeeGroup.() -> Unit = {}
|
||||
) = EmployeeGroup(id, name, permissions, employees).apply(op)
|
||||
|
||||
fun employeeGroup(
|
||||
employeeGroup: EmployeeGroup,
|
||||
newId: Long? = null,
|
||||
newName: String? = null
|
||||
) = with(employeeGroup) { EmployeeGroup(newId ?: id, newName ?: name, permissions, employees) }
|
||||
|
||||
fun employeeGroupSaveDto(
|
||||
name: String = "name",
|
||||
permissions: MutableSet<EmployeePermission> = mutableSetOf(),
|
||||
|
|
|
@ -9,7 +9,6 @@ import javax.persistence.*
|
|||
import javax.validation.constraints.Min
|
||||
import javax.validation.constraints.NotBlank
|
||||
import javax.validation.constraints.NotNull
|
||||
import javax.validation.constraints.Size
|
||||
|
||||
private const val MATERIAL_ID_NULL_MESSAGE = "Un identifiant est requis"
|
||||
private const val MATERIAL_NAME_NULL_MESSAGE = "Un nom est requis"
|
||||
|
@ -98,6 +97,7 @@ data class InventoryMaterial(
|
|||
@NotNull val lowQuantity: Boolean = false
|
||||
)
|
||||
|
||||
@Suppress("unused")
|
||||
fun Material.toInventoryMaterial(minimumQuantity: Float): InventoryMaterial {
|
||||
Assert.notNull(id, "Cannot convert a material without id to an inventory material")
|
||||
Assert.notNull(name, "Cannot convert a material without name to an inventory material")
|
||||
|
|
|
@ -11,7 +11,7 @@ interface NamedModel : Model {
|
|||
|
||||
interface EntityDto<out E> {
|
||||
/** Converts the dto to an actual entity. */
|
||||
fun toEntity(): E
|
||||
fun toEntity(): E {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
|
||||
fun Collection<Model>.sortedById(): Collection<Model> = this.sortedBy { it.id }
|
||||
|
|
|
@ -50,6 +50,19 @@ data class Recipe(
|
|||
@OneToMany(cascade = [CascadeType.ALL], mappedBy = "recipe")
|
||||
var steps: MutableCollection<RecipeStep>
|
||||
) : Model {
|
||||
constructor() : this(
|
||||
null,
|
||||
"name",
|
||||
"description",
|
||||
0,
|
||||
null,
|
||||
"remark",
|
||||
"note",
|
||||
company(),
|
||||
mutableListOf(),
|
||||
mutableListOf()
|
||||
)
|
||||
|
||||
constructor(
|
||||
id: Long,
|
||||
name: String,
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.model
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore
|
||||
import dev.fyloz.trial.colorrecipesexplorer.model.validation.NullOrNotBlank
|
||||
import java.util.*
|
||||
import javax.persistence.*
|
||||
import javax.validation.constraints.NotNull
|
||||
|
||||
@Entity
|
||||
@Table(name = "recipe_step")
|
||||
|
|
|
@ -3,7 +3,6 @@ package dev.fyloz.trial.colorrecipesexplorer.model.validation
|
|||
import javax.validation.Constraint
|
||||
import javax.validation.ConstraintValidator
|
||||
import javax.validation.ConstraintValidatorContext
|
||||
import javax.validation.Payload
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.reflect.KClass
|
||||
|
@ -15,8 +14,7 @@ private const val MESSAGE = "must be null or not blank"
|
|||
@Constraint(validatedBy = [NullOrNotBlankValidator::class])
|
||||
annotation class NullOrNotBlank(
|
||||
val message: String = MESSAGE,
|
||||
val groups: Array<KClass<*>> = [],
|
||||
val payload: Array<KClass<out Payload>> = []
|
||||
val groups: Array<KClass<*>> = []
|
||||
)
|
||||
|
||||
class NullOrNotBlankValidator : ConstraintValidator<NullOrNotBlank, String> {
|
||||
|
@ -42,5 +40,4 @@ fun isNotNullAndNotBlank(value: String?): Boolean {
|
|||
return value != null && value.isNotBlank()
|
||||
}
|
||||
|
||||
@ExperimentalContracts
|
||||
fun String?.or(alternative: String): String = if (isNotNullAndNotBlank(this)) this else alternative
|
||||
infix fun String?.or(alternative: String): String = if (isNotNullAndNotBlank(this)) this else alternative
|
||||
|
|
|
@ -3,7 +3,6 @@ package dev.fyloz.trial.colorrecipesexplorer.model.validation
|
|||
import javax.validation.Constraint
|
||||
import javax.validation.ConstraintValidator
|
||||
import javax.validation.ConstraintValidatorContext
|
||||
import javax.validation.Payload
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
private const val MIN_SIZE = Long.MIN_VALUE
|
||||
|
@ -17,8 +16,7 @@ annotation class NullOrSize(
|
|||
val min: Long = MIN_SIZE,
|
||||
val max: Long = MAX_SIZE,
|
||||
val message: String = MESSAGE,
|
||||
val groups: Array<KClass<*>> = [],
|
||||
val payload: Array<KClass<out Payload>> = []
|
||||
val groups: Array<KClass<*>> = []
|
||||
)
|
||||
|
||||
class NullOrSizeValidator : ConstraintValidator<NullOrSize, Any> {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//package dev.fyloz.trial.colorrecipesexplorer.rest
|
||||
//
|
||||
package dev.fyloz.trial.colorrecipesexplorer.rest
|
||||
|
||||
//import dev.fyloz.trial.colorrecipesexplorer.model.InventoryMaterial
|
||||
//import dev.fyloz.trial.colorrecipesexplorer.service.InventoryService
|
||||
//import org.springframework.http.ResponseEntity
|
||||
|
|
|
@ -34,7 +34,7 @@ interface RestModelApiController<E : Model, S : EntityDto<E>, U : EntityDto<E>>
|
|||
|
||||
abstract class AbstractRestApiController<E, N : EntityDto<E>, U : EntityDto<E>, S : ExternalService<E, N, U, *>>(
|
||||
val service: S,
|
||||
protected val controllerPath: String
|
||||
private val controllerPath: String
|
||||
) :
|
||||
RestApiController<E, N, U> {
|
||||
protected abstract fun getEntityId(entity: E): Any?
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.service
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.config.SecurityConfigurationProperties
|
||||
import dev.fyloz.trial.colorrecipesexplorer.config.blacklistedJwtTokens
|
||||
import dev.fyloz.trial.colorrecipesexplorer.config.defaultGroupCookieName
|
||||
import dev.fyloz.trial.colorrecipesexplorer.exception.model.EntityAlreadyExistsRestException
|
||||
import dev.fyloz.trial.colorrecipesexplorer.exception.model.EntityNotFoundException
|
||||
import dev.fyloz.trial.colorrecipesexplorer.exception.model.EntityNotFoundRestException
|
||||
import dev.fyloz.trial.colorrecipesexplorer.model.*
|
||||
import dev.fyloz.trial.colorrecipesexplorer.model.validation.or
|
||||
import dev.fyloz.trial.colorrecipesexplorer.repository.EmployeeGroupRepository
|
||||
import dev.fyloz.trial.colorrecipesexplorer.repository.EmployeeRepository
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
|
@ -170,13 +170,13 @@ class EmployeeServiceImpl(employeeRepository: EmployeeRepository, val passwordEn
|
|||
return update(with(entity) {
|
||||
Employee(
|
||||
id = id,
|
||||
firstName = if (firstName.isNotBlank()) firstName else persistedEmployee.firstName,
|
||||
lastName = if (lastName.isNotBlank()) lastName else persistedEmployee.lastName,
|
||||
firstName = firstName or persistedEmployee.firstName,
|
||||
lastName = lastName or persistedEmployee.lastName,
|
||||
password = persistedEmployee.password,
|
||||
isDefaultGroupUser = false,
|
||||
isSystemUser = false,
|
||||
group = persistedEmployee.group,
|
||||
permissions = if (permissions.isNotEmpty()) permissions.toMutableSet() else persistedEmployee.permissions,
|
||||
permissions = permissions?.toMutableSet() ?: persistedEmployee.permissions,
|
||||
lastLoginTime = persistedEmployee.lastLoginTime
|
||||
)
|
||||
})
|
||||
|
|
|
@ -1,20 +1,12 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.service
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.exception.TooLowQuantityException
|
||||
import dev.fyloz.trial.colorrecipesexplorer.model.InventoryMaterial
|
||||
import dev.fyloz.trial.colorrecipesexplorer.model.Material
|
||||
import dev.fyloz.trial.colorrecipesexplorer.model.dto.InventoryDto
|
||||
import dev.fyloz.trial.colorrecipesexplorer.model.toInventoryMaterial
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
const val minimumQuantity = 100.0f // TODO quantity stored in database
|
||||
|
||||
@Service
|
||||
class InventoryService(val materialService: MaterialService) {
|
||||
fun getAllMaterials(): Collection<InventoryMaterial> {
|
||||
return materialService.getAllNotMixType().map { it.toInventoryMaterial(minimumQuantity) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Use all materials in the given [mixes].
|
||||
* @throws TooLowQuantityException When there is not enough stock for a material
|
||||
|
|
|
@ -105,8 +105,7 @@ class MaterialTypeServiceImpl(repository: MaterialTypeRepository, private val ma
|
|||
}
|
||||
|
||||
@ResponseStatus(HttpStatus.CONFLICT)
|
||||
class CannotDeleteUsedMaterialTypeRestException : RestException(HttpStatus.CONFLICT) {
|
||||
override val exceptionMessage: String = "Cannot delete a used material type"
|
||||
|
||||
class CannotDeleteUsedMaterialTypeRestException :
|
||||
RestException("Cannot delete a used material type", HttpStatus.CONFLICT) {
|
||||
override fun buildBody(): RestExceptionBody = object : RestExceptionBody() {}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ interface RecipeService : ExternalModelService<Recipe, RecipeSaveDto, RecipeUpda
|
|||
/** Gets all recipes with the given [company]. */
|
||||
fun getAllByCompany(company: Company): Collection<Recipe>
|
||||
|
||||
/** Updates the public data of a recipe with the given [publicDateDto]. */
|
||||
/** Updates the public data of a recipe with the given [publicDataDto]. */
|
||||
fun updatePublicData(publicDataDto: RecipePublicDataDto)
|
||||
|
||||
/** Adds the given [mix] to the given [recipe]. */
|
||||
|
|
|
@ -11,7 +11,6 @@ import dev.fyloz.trial.colorrecipesexplorer.rest.RestApiController
|
|||
import io.jsonwebtoken.lang.Assert
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
|
||||
/**
|
||||
* A service implementing the basics CRUD operations for the given entities.
|
||||
|
@ -144,6 +143,7 @@ interface ExternalNamedModelService<E : NamedModel, S : EntityDto<E>, U : Entity
|
|||
NamedModelService<E, R>, ExternalModelService<E, S, U, R>
|
||||
|
||||
/** An [AbstractService] with the functionalities of a [ExternalService]. */
|
||||
@Suppress("unused")
|
||||
abstract class AbstractExternalService<E, S : EntityDto<E>, U : EntityDto<E>, R : JpaRepository<E, *>>(repository: R) :
|
||||
AbstractService<E, R>(repository), ExternalService<E, S, U, R>
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import org.springframework.beans.factory.annotation.Autowired
|
|||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
@Disabled
|
||||
@DataJpaTest
|
||||
class RecipeStepRepositoryTest @Autowired constructor(
|
||||
|
|
Loading…
Reference in New Issue