Ajout du support pour les kits de retouches (pas juste les PDFs)
This commit is contained in:
parent
42adb0ce9b
commit
cadf3dde8b
|
@ -19,7 +19,6 @@ plugins {
|
|||
}
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
|
||||
maven {
|
||||
|
|
|
@ -14,12 +14,6 @@ annotation class PreAuthorizeViewRecipes
|
|||
@PreAuthorize("hasAuthority('EDIT_RECIPES')")
|
||||
annotation class PreAuthorizeEditRecipes
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@MustBeDocumented
|
||||
@PreAuthorize("hasAuthority('REMOVE_RECIPES')")
|
||||
annotation class PreAuthorizeRemoveRecipes
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@MustBeDocumented
|
||||
|
@ -37,9 +31,3 @@ annotation class PreAuthorizeViewUsers
|
|||
@MustBeDocumented
|
||||
@PreAuthorize("hasAuthority('EDIT_USERS')")
|
||||
annotation class PreAuthorizeEditUsers
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@MustBeDocumented
|
||||
@PreAuthorize("hasAuthority('REMOVE_USERS')")
|
||||
annotation class PreAuthorizeRemoveUsers
|
||||
|
|
|
@ -8,9 +8,6 @@ import javax.persistence.*
|
|||
import javax.validation.constraints.NotBlank
|
||||
import javax.validation.constraints.NotNull
|
||||
|
||||
private const val COMPANY_ID_NULL_MESSAGE = "Un identifiant est requis"
|
||||
private const val COMPANY_NAME_NULL_MESSAGE = "Un nom est requis"
|
||||
|
||||
@Entity
|
||||
@Table(name = "company")
|
||||
data class Company(
|
||||
|
@ -20,11 +17,15 @@ data class Company(
|
|||
|
||||
@Column(unique = true)
|
||||
override val name: String
|
||||
) : NamedModel
|
||||
) : NamedModel {
|
||||
override fun toString(): String {
|
||||
return name
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
open class CompanySaveDto(
|
||||
@field:NotBlank(message = COMPANY_NAME_NULL_MESSAGE)
|
||||
@field:NotBlank
|
||||
val name: String
|
||||
) : EntityDto<Company> {
|
||||
override fun toEntity(): Company = Company(null, name)
|
||||
|
@ -32,10 +33,9 @@ open class CompanySaveDto(
|
|||
|
||||
|
||||
open class CompanyUpdateDto(
|
||||
@field:NotNull(message = COMPANY_ID_NULL_MESSAGE)
|
||||
val id: Long,
|
||||
|
||||
@field:NullOrNotBlank(message = COMPANY_NAME_NULL_MESSAGE)
|
||||
@field:NotBlank
|
||||
val name: String?
|
||||
) : EntityDto<Company> {
|
||||
override fun toEntity(): Company = Company(id, name ?: "")
|
||||
|
|
|
@ -4,27 +4,11 @@ import com.fasterxml.jackson.annotation.JsonIgnore
|
|||
import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException
|
||||
import dev.fyloz.colorrecipesexplorer.exception.CannotDeleteException
|
||||
import dev.fyloz.colorrecipesexplorer.exception.NotFoundException
|
||||
import dev.fyloz.colorrecipesexplorer.model.validation.NullOrNotBlank
|
||||
import dev.fyloz.colorrecipesexplorer.model.validation.NullOrSize
|
||||
import dev.fyloz.colorrecipesexplorer.rest.CRE_PROPERTIES
|
||||
import dev.fyloz.colorrecipesexplorer.rest.files.FILE_CONTROLLER_PATH
|
||||
import org.springframework.web.multipart.MultipartFile
|
||||
import java.net.URLEncoder
|
||||
import java.nio.charset.StandardCharsets
|
||||
import javax.persistence.*
|
||||
import javax.validation.constraints.Min
|
||||
import javax.validation.constraints.NotBlank
|
||||
import javax.validation.constraints.NotNull
|
||||
|
||||
private const val MATERIAL_ID_NULL_MESSAGE = "Un identifiant est requis"
|
||||
private const val MATERIAL_NAME_NULL_MESSAGE = "Un nom est requis"
|
||||
private const val MATERIAL_INVENTORY_QUANTITY_NULL_MESSAGE = "Une quantité est requise"
|
||||
private const val MATERIAL_INVENTORY_QUANTITY_NEGATIVE_MESSAGE = "La quantité doit être supérieure ou égale à 0"
|
||||
private const val MATERIAL_TYPE_NULL_MESSAGE = "Un type de produit est requis"
|
||||
|
||||
private const val MATERIAL_QUANTITY_MATERIAL_NULL_MESSAGE = "Un produit est requis"
|
||||
private const val MATERIAL_QUANTITY_QUANTITY_NULL_MESSAGE = "Une quantité est requises"
|
||||
private const val MATERIAL_QUANTITY_QUANTITY_NEGATIVE_MESSAGE = "La quantité doit être supérieure ou égale à 0"
|
||||
import javax.validation.constraints.Size
|
||||
|
||||
const val SIMDUT_FILES_PATH = "pdf/simdut"
|
||||
|
||||
|
@ -52,32 +36,27 @@ data class Material(
|
|||
@JsonIgnore
|
||||
@Transient
|
||||
get() = "$SIMDUT_FILES_PATH/$name.pdf"
|
||||
|
||||
|
||||
}
|
||||
|
||||
open class MaterialSaveDto(
|
||||
@field:NotBlank(message = MATERIAL_NAME_NULL_MESSAGE)
|
||||
@field:NotBlank
|
||||
val name: String,
|
||||
|
||||
@field:NotNull(message = MATERIAL_INVENTORY_QUANTITY_NULL_MESSAGE)
|
||||
@field:Min(value = 0, message = MATERIAL_INVENTORY_QUANTITY_NEGATIVE_MESSAGE)
|
||||
@field:Min(0, message = VALIDATION_SIZE_GE_ZERO)
|
||||
val inventoryQuantity: Float,
|
||||
|
||||
@field:NotNull(message = MATERIAL_TYPE_NULL_MESSAGE)
|
||||
val materialTypeId: Long,
|
||||
|
||||
val simdutFile: MultipartFile? = null
|
||||
) : EntityDto<Material>
|
||||
|
||||
open class MaterialUpdateDto(
|
||||
@field:NotNull(message = MATERIAL_ID_NULL_MESSAGE)
|
||||
val id: Long,
|
||||
|
||||
@field:NullOrNotBlank(message = MATERIAL_NAME_NULL_MESSAGE)
|
||||
@field:NotBlank
|
||||
val name: String?,
|
||||
|
||||
@field:NullOrSize(min = 0, message = MATERIAL_INVENTORY_QUANTITY_NEGATIVE_MESSAGE)
|
||||
@field:Min(0, message = VALIDATION_SIZE_GE_ZERO)
|
||||
val inventoryQuantity: Float?,
|
||||
|
||||
val materialTypeId: Long?,
|
||||
|
@ -95,11 +74,9 @@ data class MaterialOutputDto(
|
|||
) : Model
|
||||
|
||||
data class MaterialQuantityDto(
|
||||
@field:NotNull(message = MATERIAL_QUANTITY_MATERIAL_NULL_MESSAGE)
|
||||
val material: Long,
|
||||
|
||||
@field:NotNull(message = MATERIAL_QUANTITY_QUANTITY_NULL_MESSAGE)
|
||||
@field:Min(value = 0, message = MATERIAL_QUANTITY_QUANTITY_NEGATIVE_MESSAGE)
|
||||
@field:Min(0, message = VALIDATION_SIZE_GE_ZERO)
|
||||
val quantity: Float
|
||||
)
|
||||
|
||||
|
@ -147,7 +124,7 @@ fun materialQuantityDto(
|
|||
) = MaterialQuantityDto(materialId, quantity).apply(op)
|
||||
|
||||
// ==== Exceptions ====
|
||||
private const
|
||||
private const
|
||||
val MATERIAL_NOT_FOUND_EXCEPTION_TITLE = "Material not found"
|
||||
private const val MATERIAL_ALREADY_EXISTS_EXCEPTION_TITLE = "Material already exists"
|
||||
private const val MATERIAL_CANNOT_DELETE_EXCEPTION_TITLE = "Cannot delete material"
|
||||
|
|
|
@ -11,10 +11,7 @@ import javax.validation.constraints.NotBlank
|
|||
import javax.validation.constraints.NotNull
|
||||
import javax.validation.constraints.Size
|
||||
|
||||
private const val MATERIAL_TYPE_ID_NULL_MESSAGE = "Un identifiant est requis"
|
||||
private const val MATERIAL_TYPE_NAME_NULL_MESSAGE = "Un nom est requis"
|
||||
private const val MATERIAL_TYPE_PREFIX_NULL_MESSAGE = "Un préfixe est requis"
|
||||
private const val MATERIAL_TYPE_PREFIX_SIZE_MESSAGE = "Le préfixe doit faire exactement 3 caractères"
|
||||
private const val VALIDATION_PREFIX_SIZE = "Must contains exactly 3 characters"
|
||||
|
||||
@Entity
|
||||
@Table(name = "material_type")
|
||||
|
@ -39,11 +36,11 @@ data class MaterialType(
|
|||
) : NamedModel
|
||||
|
||||
open class MaterialTypeSaveDto(
|
||||
@field:NotBlank(message = MATERIAL_TYPE_NAME_NULL_MESSAGE)
|
||||
@field:NotBlank
|
||||
val name: String,
|
||||
|
||||
@field:NotBlank(message = MATERIAL_TYPE_PREFIX_NULL_MESSAGE)
|
||||
@field:Size(min = 3, max = 3, message = MATERIAL_TYPE_PREFIX_SIZE_MESSAGE)
|
||||
@field:NotBlank
|
||||
@field:Size(min = 3, max = 3, message = VALIDATION_PREFIX_SIZE)
|
||||
val prefix: String,
|
||||
|
||||
val usePercentages: Boolean = false
|
||||
|
@ -53,13 +50,12 @@ open class MaterialTypeSaveDto(
|
|||
}
|
||||
|
||||
open class MaterialTypeUpdateDto(
|
||||
@field:NotNull(message = MATERIAL_TYPE_ID_NULL_MESSAGE)
|
||||
val id: Long,
|
||||
|
||||
@field:NullOrNotBlank(message = MATERIAL_TYPE_NAME_NULL_MESSAGE)
|
||||
@field:NotBlank
|
||||
val name: String?,
|
||||
|
||||
@field:NullOrSize(min = 3, max = 3, message = MATERIAL_TYPE_PREFIX_NULL_MESSAGE)
|
||||
@field:Size(min = 3, max = 3, message = VALIDATION_PREFIX_SIZE)
|
||||
val prefix: String?
|
||||
) : EntityDto<MaterialType> {
|
||||
override fun toEntity(): MaterialType =
|
||||
|
|
|
@ -4,20 +4,10 @@ import com.fasterxml.jackson.annotation.JsonIgnore
|
|||
import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException
|
||||
import dev.fyloz.colorrecipesexplorer.exception.CannotDeleteException
|
||||
import dev.fyloz.colorrecipesexplorer.exception.NotFoundException
|
||||
import dev.fyloz.colorrecipesexplorer.model.validation.NullOrNotBlank
|
||||
import javax.persistence.*
|
||||
import javax.validation.constraints.Min
|
||||
import javax.validation.constraints.NotBlank
|
||||
import javax.validation.constraints.NotNull
|
||||
|
||||
private const val MIX_ID_NULL_MESSAGE = "Un identifiant est requis"
|
||||
private const val MIX_NAME_NULL_MESSAGE = "Un nom est requis"
|
||||
private const val MIX_RECIPE_NULL_MESSAGE = "Un recette est requise"
|
||||
private const val MIX_MATERIAL_TYPE_NULL_MESSAGE = "Un type de produit est requis"
|
||||
|
||||
private const val MIX_DEDUCT_MIX_ID_NULL_MESSAGE = "Un identifiant de mélange est requis"
|
||||
private const val MIX_DEDUCT_RATIO_NULL_MESSAGE = "Un ratio est requis"
|
||||
private const val MIX_DEDUCT_RATION_NEGATIVE_MESSAGE = "Le ratio doit être égal ou supérieur à 0"
|
||||
|
||||
@Entity
|
||||
@Table(name = "mix")
|
||||
|
@ -43,33 +33,26 @@ data class Mix(
|
|||
) : Model
|
||||
|
||||
open class MixSaveDto(
|
||||
@field:NotBlank(message = MIX_NAME_NULL_MESSAGE)
|
||||
@field:NotBlank
|
||||
val name: String,
|
||||
|
||||
@field:NotNull(message = MIX_RECIPE_NULL_MESSAGE)
|
||||
val recipeId: Long,
|
||||
|
||||
@field:NotNull(message = MIX_MATERIAL_TYPE_NULL_MESSAGE)
|
||||
val materialTypeId: Long,
|
||||
|
||||
val mixMaterials: Set<MixMaterialDto>?
|
||||
) : EntityDto<Mix> {
|
||||
override fun toEntity(): Mix = throw UnsupportedOperationException()
|
||||
}
|
||||
) : EntityDto<Mix>
|
||||
|
||||
open class MixUpdateDto(
|
||||
@field:NotNull(message = MIX_ID_NULL_MESSAGE)
|
||||
val id: Long,
|
||||
|
||||
@field:NullOrNotBlank(message = MIX_NAME_NULL_MESSAGE)
|
||||
@field:NotBlank
|
||||
val name: String?,
|
||||
|
||||
val materialTypeId: Long?,
|
||||
|
||||
var mixMaterials: Set<MixMaterialDto>?
|
||||
) : EntityDto<Mix> {
|
||||
override fun toEntity(): Mix = throw UnsupportedOperationException()
|
||||
}
|
||||
) : EntityDto<Mix>
|
||||
|
||||
data class MixOutputDto(
|
||||
val id: Long,
|
||||
|
@ -79,16 +62,13 @@ data class MixOutputDto(
|
|||
)
|
||||
|
||||
data class MixDeductDto(
|
||||
@field:NotNull(message = MIX_DEDUCT_MIX_ID_NULL_MESSAGE)
|
||||
val id: Long,
|
||||
|
||||
@field:NotNull(message = MIX_DEDUCT_RATIO_NULL_MESSAGE)
|
||||
@field:Min(value = 0, message = MIX_DEDUCT_RATION_NEGATIVE_MESSAGE)
|
||||
@field:Min(0, message = VALIDATION_SIZE_GE_ZERO)
|
||||
val ratio: Float
|
||||
)
|
||||
|
||||
data class MixLocationDto(
|
||||
@field:NotNull(message = MIX_DEDUCT_MIX_ID_NULL_MESSAGE)
|
||||
val mixId: Long,
|
||||
|
||||
val location: String?
|
||||
|
|
|
@ -6,10 +6,6 @@ import javax.persistence.*
|
|||
import javax.validation.constraints.Min
|
||||
import javax.validation.constraints.NotNull
|
||||
|
||||
private const val MIX_MATERIAL_DTO_MATERIAL_ID_NULL_MESSAGE = "Un identifiant de produit est requis"
|
||||
private const val MIX_MATERIAL_DTO_QUANTITY_NULL_MESSAGE = "Une quantité est requise"
|
||||
private const val MIX_MATERIAL_DTO_QUANTITY_NEGATIVE_MESSAGE = "La quantité ne peut pas être négative"
|
||||
|
||||
@Entity
|
||||
@Table(name = "mix_material")
|
||||
data class MixMaterial(
|
||||
|
@ -26,6 +22,15 @@ data class MixMaterial(
|
|||
var position: Int
|
||||
) : Model
|
||||
|
||||
data class MixMaterialDto(
|
||||
val materialId: Long,
|
||||
|
||||
@field:Min(0, message = VALIDATION_SIZE_GE_ZERO)
|
||||
val quantity: Float,
|
||||
|
||||
val position: Int
|
||||
)
|
||||
|
||||
data class MixMaterialOutputDto(
|
||||
val id: Long,
|
||||
val material: MaterialOutputDto,
|
||||
|
@ -33,17 +38,6 @@ data class MixMaterialOutputDto(
|
|||
val position: Int
|
||||
)
|
||||
|
||||
data class MixMaterialDto(
|
||||
@field:NotNull(message = MIX_MATERIAL_DTO_MATERIAL_ID_NULL_MESSAGE)
|
||||
val materialId: Long,
|
||||
|
||||
@field:NotNull(message = MIX_MATERIAL_DTO_QUANTITY_NULL_MESSAGE)
|
||||
@field:Min(value = 0, message = MIX_MATERIAL_DTO_QUANTITY_NEGATIVE_MESSAGE)
|
||||
val quantity: Float,
|
||||
|
||||
val position: Int
|
||||
)
|
||||
|
||||
// ==== DSL ====
|
||||
fun mixMaterial(
|
||||
id: Long? = null,
|
||||
|
|
|
@ -15,3 +15,8 @@ interface EntityDto<out E> {
|
|||
throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
|
||||
// GENERAL VALIDATION MESSAGES
|
||||
const val VALIDATION_SIZE_GE_ZERO = "Must be greater or equals to 0"
|
||||
const val VALIDATION_SIZE_GE_ONE = "Must be greater or equals to 1"
|
||||
const val VALIDATION_RANGE_PERCENTS = "Must be between 0 and 100"
|
||||
|
|
|
@ -5,8 +5,6 @@ import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException
|
|||
import dev.fyloz.colorrecipesexplorer.exception.NotFoundException
|
||||
import dev.fyloz.colorrecipesexplorer.model.account.Group
|
||||
import dev.fyloz.colorrecipesexplorer.model.account.group
|
||||
import dev.fyloz.colorrecipesexplorer.model.validation.NullOrNotBlank
|
||||
import dev.fyloz.colorrecipesexplorer.model.validation.NullOrSize
|
||||
import dev.fyloz.colorrecipesexplorer.rest.CRE_PROPERTIES
|
||||
import dev.fyloz.colorrecipesexplorer.rest.files.FILE_CONTROLLER_PATH
|
||||
import java.net.URLEncoder
|
||||
|
@ -15,19 +13,7 @@ import java.time.LocalDate
|
|||
import javax.persistence.*
|
||||
import javax.validation.constraints.*
|
||||
|
||||
private const val RECIPE_ID_NULL_MESSAGE = "Un identifiant est requis"
|
||||
private const val RECIPE_NAME_NULL_MESSAGE = "Un nom est requis"
|
||||
private const val RECIPE_DESCRIPTION_NULL_MESSAGE = "Une description est requise"
|
||||
private const val RECIPE_COLOR_NULL_MESSAGE = "Une couleur est requise"
|
||||
private const val RECIPE_GLOSS_NULL_MESSAGE = "Le lustre de la couleur est requis"
|
||||
private const val RECIPE_GLOSS_OUTSIDE_RANGE_MESSAGE = "Le lustre doit être entre 0 et 100"
|
||||
private const val RECIPE_SAMPLE_TOO_SMALL_MESSAGE = "Le numéro d'échantillon doit être supérieur ou égal à 0"
|
||||
private const val RECIPE_COMPANY_NULL_MESSAGE = "Une bannière est requise"
|
||||
|
||||
private const val RECIPE_STEPS_DTO_GROUP_ID_NULL_MESSAGE = "Un identifiant de groupe est requis"
|
||||
private const val RECIPE_STEPS_DTO_MESSAGES_NULL_MESSAGE = "Des messages sont requis"
|
||||
|
||||
private const val NOTE_GROUP_ID_NULL_MESSAGE = "Un identifiant de groupe est requis"
|
||||
private const val VALIDATION_COLOR_PATTERN = "^#([0-9a-f]{6})$"
|
||||
|
||||
const val RECIPE_IMAGES_DIRECTORY = "images/recipes"
|
||||
|
||||
|
@ -91,30 +77,28 @@ data class Recipe(
|
|||
}
|
||||
|
||||
open class RecipeSaveDto(
|
||||
@field:NotBlank(message = RECIPE_NAME_NULL_MESSAGE)
|
||||
@field:NotBlank
|
||||
val name: String,
|
||||
|
||||
@field:NotBlank(message = RECIPE_DESCRIPTION_NULL_MESSAGE)
|
||||
@field:NotBlank
|
||||
val description: String,
|
||||
|
||||
@field:NotBlank(message = RECIPE_COLOR_NULL_MESSAGE)
|
||||
@field:Pattern(regexp = "^#([0-9a-f]{6})$")
|
||||
@field:NotBlank
|
||||
@field:Pattern(regexp = VALIDATION_COLOR_PATTERN)
|
||||
val color: String,
|
||||
|
||||
@field:NotNull(message = RECIPE_GLOSS_NULL_MESSAGE)
|
||||
@field:Min(value = 0, message = RECIPE_GLOSS_OUTSIDE_RANGE_MESSAGE)
|
||||
@field:Max(value = 100, message = RECIPE_GLOSS_OUTSIDE_RANGE_MESSAGE)
|
||||
@field:Min(0, message = VALIDATION_RANGE_PERCENTS)
|
||||
@field:Max(100, message = VALIDATION_RANGE_PERCENTS)
|
||||
val gloss: Byte,
|
||||
|
||||
@field:Min(value = 0, message = RECIPE_SAMPLE_TOO_SMALL_MESSAGE)
|
||||
@field:Min(0, message = VALIDATION_SIZE_GE_ZERO)
|
||||
val sample: Int?,
|
||||
|
||||
val approbationDate: LocalDate?,
|
||||
|
||||
val remark: String?,
|
||||
|
||||
@field:Min(value = 0, message = RECIPE_COMPANY_NULL_MESSAGE)
|
||||
val companyId: Long = -1L,
|
||||
val companyId: Long
|
||||
) : EntityDto<Recipe> {
|
||||
override fun toEntity(): Recipe = recipe(
|
||||
name = name,
|
||||
|
@ -127,24 +111,23 @@ open class RecipeSaveDto(
|
|||
}
|
||||
|
||||
open class RecipeUpdateDto(
|
||||
@field:NotNull(message = RECIPE_ID_NULL_MESSAGE)
|
||||
val id: Long,
|
||||
|
||||
@field:NullOrNotBlank(message = RECIPE_NAME_NULL_MESSAGE)
|
||||
@field:NotBlank
|
||||
val name: String?,
|
||||
|
||||
@field:NullOrNotBlank(message = RECIPE_DESCRIPTION_NULL_MESSAGE)
|
||||
@field:NotBlank
|
||||
val description: String?,
|
||||
|
||||
@field:NullOrNotBlank(message = RECIPE_COLOR_NULL_MESSAGE)
|
||||
@field:Pattern(regexp = "^#([0-9a-f]{6})$")
|
||||
@field:NotBlank
|
||||
@field:Pattern(regexp = VALIDATION_COLOR_PATTERN)
|
||||
val color: String?,
|
||||
|
||||
@field:Min(value = 0, message = RECIPE_GLOSS_OUTSIDE_RANGE_MESSAGE)
|
||||
@field:Max(value = 100, message = RECIPE_GLOSS_OUTSIDE_RANGE_MESSAGE)
|
||||
@field:Min(0, message = VALIDATION_RANGE_PERCENTS)
|
||||
@field:Max(100, message = VALIDATION_RANGE_PERCENTS)
|
||||
val gloss: Byte?,
|
||||
|
||||
@field:NullOrSize(min = 0, message = RECIPE_SAMPLE_TOO_SMALL_MESSAGE)
|
||||
@field:Min(0, message = VALIDATION_SIZE_GE_ZERO)
|
||||
val sample: Int?,
|
||||
|
||||
val approbationDate: LocalDate?,
|
||||
|
@ -188,15 +171,12 @@ data class RecipeGroupInformation(
|
|||
)
|
||||
|
||||
data class RecipeStepsDto(
|
||||
@field:NotNull(message = RECIPE_STEPS_DTO_GROUP_ID_NULL_MESSAGE)
|
||||
val groupId: Long,
|
||||
|
||||
@field:NotNull(message = RECIPE_STEPS_DTO_MESSAGES_NULL_MESSAGE)
|
||||
val steps: Set<RecipeStep>
|
||||
)
|
||||
|
||||
data class RecipePublicDataDto(
|
||||
@field:NotNull(message = RECIPE_ID_NULL_MESSAGE)
|
||||
val recipeId: Long,
|
||||
|
||||
val notes: Set<NoteDto>?,
|
||||
|
@ -205,7 +185,6 @@ data class RecipePublicDataDto(
|
|||
)
|
||||
|
||||
data class NoteDto(
|
||||
@field:NotNull(message = NOTE_GROUP_ID_NULL_MESSAGE)
|
||||
val groupId: Long,
|
||||
|
||||
val content: String?
|
||||
|
@ -290,8 +269,6 @@ private const val RECIPE_NOT_FOUND_EXCEPTION_TITLE = "Recipe not found"
|
|||
private const val RECIPE_ALREADY_EXISTS_EXCEPTION_TITLE = "Recipe already exists"
|
||||
private const val RECIPE_EXCEPTION_ERROR_CODE = "recipe"
|
||||
|
||||
sealed class RecipeException
|
||||
|
||||
fun recipeIdNotFoundException(id: Long) =
|
||||
NotFoundException(
|
||||
RECIPE_EXCEPTION_ERROR_CODE,
|
||||
|
|
|
@ -3,21 +3,16 @@ package dev.fyloz.colorrecipesexplorer.model.account
|
|||
import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException
|
||||
import dev.fyloz.colorrecipesexplorer.exception.NotFoundException
|
||||
import dev.fyloz.colorrecipesexplorer.exception.RestException
|
||||
import dev.fyloz.colorrecipesexplorer.model.EntityDto
|
||||
import dev.fyloz.colorrecipesexplorer.model.Model
|
||||
import dev.fyloz.colorrecipesexplorer.model.NamedModel
|
||||
import dev.fyloz.colorrecipesexplorer.model.*
|
||||
import org.hibernate.annotations.Fetch
|
||||
import org.hibernate.annotations.FetchMode
|
||||
import org.springframework.http.HttpStatus
|
||||
import javax.persistence.*
|
||||
import javax.validation.constraints.NotBlank
|
||||
import javax.validation.constraints.NotEmpty
|
||||
import javax.validation.constraints.NotNull
|
||||
import javax.validation.constraints.Size
|
||||
|
||||
private const val GROUP_ID_NULL_MESSAGE = "Un identifiant est requis"
|
||||
private const val GROUP_NAME_NULL_MESSAGE = "Un nom est requis"
|
||||
private const val GROUP_PERMISSIONS_EMPTY_MESSAGE = "Au moins une permission est requise"
|
||||
|
||||
@Entity
|
||||
@Table(name = "user_group")
|
||||
data class Group(
|
||||
|
@ -43,11 +38,10 @@ data class Group(
|
|||
}
|
||||
|
||||
open class GroupSaveDto(
|
||||
@field:NotBlank(message = GROUP_NAME_NULL_MESSAGE)
|
||||
@field:Size(min = 3)
|
||||
@field:NotBlank
|
||||
val name: String,
|
||||
|
||||
@field:Size(min = 1, message = GROUP_PERMISSIONS_EMPTY_MESSAGE)
|
||||
@field:NotEmpty
|
||||
val permissions: MutableSet<Permission>
|
||||
) : EntityDto<Group> {
|
||||
override fun toEntity(): Group =
|
||||
|
@ -55,14 +49,12 @@ open class GroupSaveDto(
|
|||
}
|
||||
|
||||
open class GroupUpdateDto(
|
||||
@field:NotNull(message = GROUP_ID_NULL_MESSAGE)
|
||||
val id: Long,
|
||||
|
||||
@field:NotBlank(message = GROUP_NAME_NULL_MESSAGE)
|
||||
@field:Size(min = 3)
|
||||
@field:NotBlank
|
||||
val name: String,
|
||||
|
||||
@field:Size(min = 1, message = GROUP_PERMISSIONS_EMPTY_MESSAGE)
|
||||
@field:NotEmpty
|
||||
val permissions: MutableSet<Permission>
|
||||
) : EntityDto<Group> {
|
||||
override fun toEntity(): Group =
|
||||
|
|
|
@ -9,14 +9,11 @@ enum class Permission(
|
|||
) {
|
||||
READ_FILE,
|
||||
WRITE_FILE(listOf(READ_FILE)),
|
||||
REMOVE_FILE(listOf(WRITE_FILE)),
|
||||
|
||||
VIEW_RECIPES(listOf(READ_FILE)),
|
||||
VIEW_CATALOG(listOf(READ_FILE)),
|
||||
VIEW_USERS,
|
||||
|
||||
PRINT_MIXES(listOf(VIEW_RECIPES)),
|
||||
|
||||
EDIT_RECIPES_PUBLIC_DATA(listOf(VIEW_RECIPES)),
|
||||
EDIT_RECIPES(listOf(EDIT_RECIPES_PUBLIC_DATA, WRITE_FILE)),
|
||||
EDIT_MATERIALS(listOf(VIEW_CATALOG, WRITE_FILE)),
|
||||
|
@ -25,29 +22,24 @@ enum class Permission(
|
|||
EDIT_USERS(listOf(VIEW_USERS)),
|
||||
EDIT_CATALOG(listOf(EDIT_MATERIALS, EDIT_MATERIAL_TYPES, EDIT_COMPANIES)),
|
||||
|
||||
REMOVE_RECIPES(listOf(EDIT_RECIPES, REMOVE_FILE)),
|
||||
REMOVE_MATERIALS(listOf(EDIT_MATERIALS, REMOVE_FILE)),
|
||||
REMOVE_MATERIAL_TYPES(listOf(EDIT_MATERIAL_TYPES)),
|
||||
REMOVE_COMPANIES(listOf(EDIT_COMPANIES)),
|
||||
REMOVE_USERS(listOf(EDIT_USERS)),
|
||||
REMOVE_CATALOG(listOf(REMOVE_MATERIALS, REMOVE_MATERIAL_TYPES, REMOVE_COMPANIES)),
|
||||
VIEW_TOUCH_UP_KITS,
|
||||
EDIT_TOUCH_UP_KITS(listOf(VIEW_TOUCH_UP_KITS)),
|
||||
|
||||
PRINT_MIXES(listOf(VIEW_RECIPES)),
|
||||
ADD_TO_INVENTORY(listOf(VIEW_CATALOG)),
|
||||
DEDUCT_FROM_INVENTORY(listOf(VIEW_RECIPES)),
|
||||
GENERATE_TOUCH_UP_KIT,
|
||||
|
||||
ADMIN(
|
||||
listOf(
|
||||
EDIT_RECIPES,
|
||||
EDIT_CATALOG,
|
||||
EDIT_USERS,
|
||||
|
||||
REMOVE_RECIPES,
|
||||
REMOVE_USERS,
|
||||
REMOVE_CATALOG,
|
||||
EDIT_TOUCH_UP_KITS,
|
||||
|
||||
PRINT_MIXES,
|
||||
ADD_TO_INVENTORY,
|
||||
DEDUCT_FROM_INVENTORY,
|
||||
GENERATE_TOUCH_UP_KIT
|
||||
)
|
||||
),
|
||||
|
||||
|
@ -69,6 +61,16 @@ enum class Permission(
|
|||
EDIT_EMPLOYEE_PASSWORD(listOf(EDIT_USERS), true),
|
||||
EDIT_EMPLOYEE_GROUP(listOf(EDIT_USERS), true),
|
||||
|
||||
REMOVE_FILE(listOf(WRITE_FILE), true),
|
||||
GENERATE_TOUCH_UP_KIT(listOf(VIEW_TOUCH_UP_KITS), true),
|
||||
|
||||
REMOVE_RECIPES(listOf(EDIT_RECIPES, REMOVE_FILE), true),
|
||||
REMOVE_MATERIALS(listOf(EDIT_MATERIALS, REMOVE_FILE), true),
|
||||
REMOVE_MATERIAL_TYPES(listOf(EDIT_MATERIAL_TYPES), true),
|
||||
REMOVE_COMPANIES(listOf(EDIT_COMPANIES), true),
|
||||
REMOVE_USERS(listOf(EDIT_USERS), true),
|
||||
REMOVE_CATALOG(listOf(REMOVE_MATERIALS, REMOVE_MATERIAL_TYPES, REMOVE_COMPANIES), true),
|
||||
|
||||
REMOVE_RECIPE(listOf(REMOVE_RECIPES), true),
|
||||
REMOVE_MATERIAL(listOf(REMOVE_MATERIALS), true),
|
||||
REMOVE_MATERIAL_TYPE(listOf(REMOVE_MATERIAL_TYPES), true),
|
||||
|
|
|
@ -4,7 +4,6 @@ import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException
|
|||
import dev.fyloz.colorrecipesexplorer.exception.NotFoundException
|
||||
import dev.fyloz.colorrecipesexplorer.model.EntityDto
|
||||
import dev.fyloz.colorrecipesexplorer.model.Model
|
||||
import dev.fyloz.colorrecipesexplorer.model.validation.NullOrNotBlank
|
||||
import org.hibernate.annotations.Fetch
|
||||
import org.hibernate.annotations.FetchMode
|
||||
import org.springframework.security.core.GrantedAuthority
|
||||
|
@ -13,14 +12,9 @@ import org.springframework.security.crypto.password.PasswordEncoder
|
|||
import java.time.LocalDateTime
|
||||
import javax.persistence.*
|
||||
import javax.validation.constraints.NotBlank
|
||||
import javax.validation.constraints.NotNull
|
||||
import javax.validation.constraints.Size
|
||||
|
||||
private const val USER_ID_NULL_MESSAGE = "Un numéro d'utilisateur est requis"
|
||||
private const val USER_LAST_NAME_EMPTY_MESSAGE = "Un nom est requis"
|
||||
private const val USER_FIRST_NAME_EMPTY_MESSAGE = "Un prénom est requis"
|
||||
private const val USER_PASSWORD_EMPTY_MESSAGE = "Un mot de passe est requis"
|
||||
private const val USER_PASSWORD_TOO_SHORT_MESSAGE = "Le mot de passe doit contenir au moins 8 caractères"
|
||||
private const val VALIDATION_PASSWORD_LENGTH = "Must contains at least 8 characters"
|
||||
|
||||
@Entity
|
||||
@Table(name = "user")
|
||||
|
@ -70,19 +64,17 @@ data class User(
|
|||
get() = flatPermissions.map { it.toAuthority() }.toMutableSet()
|
||||
}
|
||||
|
||||
/** DTO for creating users. Allows a [password] a [groupId]. */
|
||||
open class UserSaveDto(
|
||||
@field:NotNull(message = USER_ID_NULL_MESSAGE)
|
||||
val id: Long,
|
||||
|
||||
@field:NotBlank(message = USER_FIRST_NAME_EMPTY_MESSAGE)
|
||||
@field:NotBlank
|
||||
val firstName: String,
|
||||
|
||||
@field:NotBlank(message = USER_LAST_NAME_EMPTY_MESSAGE)
|
||||
@field:NotBlank
|
||||
val lastName: String,
|
||||
|
||||
@field:NotBlank(message = USER_PASSWORD_EMPTY_MESSAGE)
|
||||
@field:Size(min = 8, message = USER_PASSWORD_TOO_SHORT_MESSAGE)
|
||||
@field:NotBlank
|
||||
@field:Size(min = 8, message = VALIDATION_PASSWORD_LENGTH)
|
||||
val password: String,
|
||||
|
||||
val groupId: Long?,
|
||||
|
@ -92,13 +84,12 @@ open class UserSaveDto(
|
|||
) : EntityDto<User>
|
||||
|
||||
open class UserUpdateDto(
|
||||
@field:NotNull(message = USER_ID_NULL_MESSAGE)
|
||||
val id: Long,
|
||||
|
||||
@field:NullOrNotBlank(message = USER_FIRST_NAME_EMPTY_MESSAGE)
|
||||
@field:NotBlank
|
||||
val firstName: String?,
|
||||
|
||||
@field:NullOrNotBlank(message = USER_LAST_NAME_EMPTY_MESSAGE)
|
||||
@field:NotBlank
|
||||
val lastName: String?,
|
||||
|
||||
val groupId: Long?,
|
||||
|
|
|
@ -1,12 +1,211 @@
|
|||
package dev.fyloz.colorrecipesexplorer.model.touchupkit
|
||||
|
||||
import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException
|
||||
import dev.fyloz.colorrecipesexplorer.exception.NotFoundException
|
||||
import dev.fyloz.colorrecipesexplorer.model.EntityDto
|
||||
import dev.fyloz.colorrecipesexplorer.model.Model
|
||||
import dev.fyloz.colorrecipesexplorer.model.VALIDATION_SIZE_GE_ONE
|
||||
import java.time.LocalDate
|
||||
import javax.persistence.*
|
||||
import javax.validation.constraints.Min
|
||||
import javax.validation.constraints.NotBlank
|
||||
import javax.validation.constraints.NotEmpty
|
||||
|
||||
const val TOUCH_UP_KIT_DELIMITER = ';'
|
||||
|
||||
@Entity
|
||||
@Table(name = "touch_up_kit")
|
||||
data class TouchUpKit(
|
||||
val id: Long,
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
override val id: Long?,
|
||||
|
||||
val project: String,
|
||||
val buggy: String
|
||||
|
||||
val buggy: String,
|
||||
|
||||
val company: String,
|
||||
|
||||
val quantity: Int,
|
||||
|
||||
@Column(name = "shipping_date")
|
||||
val shippingDate: LocalDate,
|
||||
|
||||
@Column(name = "finish")
|
||||
private val finishConcatenated: String,
|
||||
|
||||
@Column(name = "material")
|
||||
private val materialConcatenated: String,
|
||||
|
||||
@OneToMany(cascade = [CascadeType.ALL], fetch = FetchType.EAGER, orphanRemoval = true)
|
||||
@JoinColumn(name = "touch_up_kit_id")
|
||||
val content: Set<TouchUpKitProduct>
|
||||
) : Model {
|
||||
val finish
|
||||
get() = finishConcatenated.split(TOUCH_UP_KIT_DELIMITER)
|
||||
|
||||
val material
|
||||
get() = materialConcatenated.split(TOUCH_UP_KIT_DELIMITER)
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table(name = "touch_up_kit_product")
|
||||
data class TouchUpKitProduct(
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
override val id: Long?,
|
||||
|
||||
val name: String,
|
||||
|
||||
val description: String?,
|
||||
|
||||
val quantity: Float
|
||||
) : Model
|
||||
|
||||
data class TouchUpKitSaveDto(
|
||||
@field:NotBlank
|
||||
val project: String,
|
||||
|
||||
@field:NotBlank
|
||||
val buggy: String,
|
||||
|
||||
@field:NotBlank
|
||||
val company: String,
|
||||
|
||||
@field:Min(1, message = VALIDATION_SIZE_GE_ONE)
|
||||
val quantity: Int,
|
||||
|
||||
val shippingDate: LocalDate,
|
||||
|
||||
@field:NotEmpty
|
||||
val finish: List<String>,
|
||||
|
||||
@field:NotEmpty
|
||||
val material: List<String>,
|
||||
|
||||
@field:NotEmpty
|
||||
val content: Set<TouchUpKitProductDto>
|
||||
) : EntityDto<TouchUpKit> {
|
||||
override fun toEntity() = touchUpKit(this)
|
||||
}
|
||||
|
||||
data class TouchUpKitUpdateDto(
|
||||
val id: Long,
|
||||
|
||||
@field:NotBlank
|
||||
val project: String?,
|
||||
|
||||
@field:NotBlank
|
||||
val buggy: String?,
|
||||
|
||||
@field:NotBlank
|
||||
val company: String?,
|
||||
|
||||
@field:Min(1, message = VALIDATION_SIZE_GE_ONE)
|
||||
val quantity: Int?,
|
||||
|
||||
val shippingDate: LocalDate?,
|
||||
|
||||
@field:NotEmpty
|
||||
val finish: List<String>?,
|
||||
|
||||
@field:NotEmpty
|
||||
val material: List<String>?,
|
||||
|
||||
@field:NotEmpty
|
||||
val content: Set<TouchUpKitProductDto>?
|
||||
) : EntityDto<TouchUpKit>
|
||||
|
||||
data class TouchUpKitOutputDto(
|
||||
override val id: Long,
|
||||
val project: String,
|
||||
val buggy: String,
|
||||
val company: String,
|
||||
val quantity: Int,
|
||||
val shippingDate: LocalDate,
|
||||
val finish: List<String>,
|
||||
val material: List<String>,
|
||||
val content: Set<TouchUpKitProduct>,
|
||||
val pdfUrl: String
|
||||
) : Model
|
||||
|
||||
data class TouchUpKitProductDto(
|
||||
val name: String,
|
||||
val description: String?,
|
||||
val quantity: Float
|
||||
)
|
||||
|
||||
sealed class TouchUpKitCompany {
|
||||
inline class CompanyName(val name: String)
|
||||
class Company(val company: Company)
|
||||
}
|
||||
// ==== DSL ====
|
||||
fun touchUpKit(
|
||||
id: Long? = null,
|
||||
project: String = "project",
|
||||
buggy: String = "buggy",
|
||||
company: String = "company",
|
||||
quantity: Int = 1,
|
||||
shippingDate: LocalDate = LocalDate.now(),
|
||||
finish: List<String>,
|
||||
material: List<String>,
|
||||
content: Set<TouchUpKitProduct>,
|
||||
op: TouchUpKit.() -> Unit = {}
|
||||
) = TouchUpKit(
|
||||
id,
|
||||
project,
|
||||
buggy,
|
||||
company,
|
||||
quantity,
|
||||
shippingDate,
|
||||
finish.reduce { acc, f -> "$acc$TOUCH_UP_KIT_DELIMITER$f" },
|
||||
material.reduce { acc, f -> "$acc$TOUCH_UP_KIT_DELIMITER$f" },
|
||||
content
|
||||
).apply(op)
|
||||
|
||||
fun touchUpKit(touchUpKitSaveDto: TouchUpKitSaveDto) =
|
||||
with(touchUpKitSaveDto) {
|
||||
touchUpKit(
|
||||
project = project,
|
||||
buggy = buggy,
|
||||
company = company,
|
||||
quantity = quantity,
|
||||
shippingDate = shippingDate,
|
||||
finish = finish,
|
||||
material = material,
|
||||
content = content.map { touchUpKitProduct(it) }.toSet()
|
||||
)
|
||||
}
|
||||
|
||||
fun touchUpKitProduct(
|
||||
id: Long? = null,
|
||||
name: String = "product",
|
||||
description: String? = "description",
|
||||
quantity: Float = 1f,
|
||||
op: TouchUpKitProduct.() -> Unit = {}
|
||||
) = TouchUpKitProduct(id, name, description, quantity)
|
||||
.apply(op)
|
||||
|
||||
fun touchUpKitProduct(touchUpKitProductDto: TouchUpKitProductDto) =
|
||||
touchUpKitProduct(
|
||||
name = touchUpKitProductDto.name,
|
||||
description = touchUpKitProductDto.description,
|
||||
quantity = touchUpKitProductDto.quantity
|
||||
)
|
||||
|
||||
// ==== Exceptions ====
|
||||
private const val TOUCH_UP_KIT_NOT_FOUND_EXCEPTION_TITLE = "Touch up kit not found"
|
||||
private const val TOUCH_UP_KIT_ALREADY_EXISTS_EXCEPTION_TITLE = "Touch up kit already exists"
|
||||
private const val TOUCH_UP_KIT_EXCEPTION_ERROR_CODE = "touchupkit"
|
||||
|
||||
fun touchUpKitIdNotFoundException(id: Long) =
|
||||
NotFoundException(
|
||||
TOUCH_UP_KIT_EXCEPTION_ERROR_CODE,
|
||||
TOUCH_UP_KIT_NOT_FOUND_EXCEPTION_TITLE,
|
||||
"A touch up kit with the id $id could not be found",
|
||||
id
|
||||
)
|
||||
|
||||
fun touchUpKitIdAlreadyExistsException(id: Long) =
|
||||
AlreadyExistsException(
|
||||
TOUCH_UP_KIT_EXCEPTION_ERROR_CODE,
|
||||
TOUCH_UP_KIT_ALREADY_EXISTS_EXCEPTION_TITLE,
|
||||
"A touch up kit with the id $id already exists",
|
||||
id
|
||||
)
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package dev.fyloz.colorrecipesexplorer.repository
|
||||
|
||||
import dev.fyloz.colorrecipesexplorer.model.touchupkit.TouchUpKit
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
|
||||
interface TouchUpKitRepository : JpaRepository<TouchUpKit, Long>
|
|
@ -1,7 +1,6 @@
|
|||
package dev.fyloz.colorrecipesexplorer.rest
|
||||
|
||||
import dev.fyloz.colorrecipesexplorer.config.annotations.PreAuthorizeEditUsers
|
||||
import dev.fyloz.colorrecipesexplorer.config.annotations.PreAuthorizeRemoveUsers
|
||||
import dev.fyloz.colorrecipesexplorer.config.annotations.PreAuthorizeViewUsers
|
||||
import dev.fyloz.colorrecipesexplorer.model.account.*
|
||||
import dev.fyloz.colorrecipesexplorer.service.UserService
|
||||
|
@ -87,7 +86,7 @@ class UserController(private val userService: UserService) {
|
|||
}
|
||||
|
||||
@DeleteMapping("{id}")
|
||||
@PreAuthorizeRemoveUsers
|
||||
@PreAuthorizeEditUsers
|
||||
fun deleteById(@PathVariable id: Long) =
|
||||
userService.deleteById(id)
|
||||
}
|
||||
|
@ -147,7 +146,7 @@ class GroupsController(
|
|||
}
|
||||
|
||||
@DeleteMapping("{id}")
|
||||
@PreAuthorizeRemoveUsers
|
||||
@PreAuthorizeEditUsers
|
||||
fun deleteById(@PathVariable id: Long) =
|
||||
noContent {
|
||||
groupService.deleteById(id)
|
||||
|
|
|
@ -38,7 +38,7 @@ class CompanyController(private val companyService: CompanyService) {
|
|||
}
|
||||
|
||||
@DeleteMapping("{id}")
|
||||
@PreAuthorize("hasAuthority('REMOVE_COMPANIES')")
|
||||
@PreAuthorize("hasAuthority('EDIT_COMPANIES')")
|
||||
fun deleteById(@PathVariable id: Long) =
|
||||
noContent {
|
||||
companyService.deleteById(id)
|
||||
|
|
|
@ -64,7 +64,7 @@ class MaterialController(
|
|||
}
|
||||
|
||||
@DeleteMapping("{id}")
|
||||
@PreAuthorize("hasAuthority('REMOVE_MATERIALS')")
|
||||
@PreAuthorize("hasAuthority('EDIT_MATERIALS')")
|
||||
fun deleteById(@PathVariable id: Long) =
|
||||
noContent {
|
||||
materialService.deleteById(id)
|
||||
|
|
|
@ -38,7 +38,7 @@ class MaterialTypeController(private val materialTypeService: MaterialTypeServic
|
|||
}
|
||||
|
||||
@DeleteMapping("{id}")
|
||||
@PreAuthorize("hasAuthority('REMOVE_MATERIAL_TYPES')")
|
||||
@PreAuthorize("hasAuthority('EDIT_MATERIAL_TYPES')")
|
||||
fun deleteById(@PathVariable id: Long) =
|
||||
noContent {
|
||||
materialTypeService.deleteById(id)
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
package dev.fyloz.colorrecipesexplorer.rest
|
||||
|
||||
import dev.fyloz.colorrecipesexplorer.config.annotations.PreAuthorizeEditRecipes
|
||||
import dev.fyloz.colorrecipesexplorer.config.annotations.PreAuthorizeRemoveRecipes
|
||||
import dev.fyloz.colorrecipesexplorer.config.annotations.PreAuthorizeViewRecipes
|
||||
import dev.fyloz.colorrecipesexplorer.config.properties.CreProperties
|
||||
import dev.fyloz.colorrecipesexplorer.model.*
|
||||
import dev.fyloz.colorrecipesexplorer.rest.files.FILE_CONTROLLER_PATH
|
||||
import dev.fyloz.colorrecipesexplorer.service.MixService
|
||||
import dev.fyloz.colorrecipesexplorer.service.RecipeImageService
|
||||
import dev.fyloz.colorrecipesexplorer.service.RecipeService
|
||||
|
@ -14,8 +11,6 @@ import org.springframework.http.ResponseEntity
|
|||
import org.springframework.security.access.prepost.PreAuthorize
|
||||
import org.springframework.web.bind.annotation.*
|
||||
import org.springframework.web.multipart.MultipartFile
|
||||
import java.net.URLEncoder
|
||||
import java.nio.charset.StandardCharsets
|
||||
import javax.validation.Valid
|
||||
|
||||
|
||||
|
@ -61,7 +56,7 @@ class RecipeController(
|
|||
}
|
||||
|
||||
@DeleteMapping("{id}")
|
||||
@PreAuthorizeRemoveRecipes
|
||||
@PreAuthorizeEditRecipes
|
||||
fun deleteById(@PathVariable id: Long) =
|
||||
noContent {
|
||||
recipeService.deleteById(id)
|
||||
|
@ -105,7 +100,7 @@ class MixController(private val mixService: MixService) {
|
|||
}
|
||||
|
||||
@DeleteMapping("{id}")
|
||||
@PreAuthorizeRemoveRecipes
|
||||
@PreAuthorizeEditRecipes
|
||||
fun deleteById(@PathVariable id: Long) =
|
||||
noContent {
|
||||
mixService.deleteById(id)
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
package dev.fyloz.colorrecipesexplorer.rest
|
||||
|
||||
import dev.fyloz.colorrecipesexplorer.model.touchupkit.TouchUpKitOutputDto
|
||||
import dev.fyloz.colorrecipesexplorer.model.touchupkit.TouchUpKitSaveDto
|
||||
import dev.fyloz.colorrecipesexplorer.model.touchupkit.TouchUpKitUpdateDto
|
||||
import dev.fyloz.colorrecipesexplorer.service.touchupkit.TouchUpKitService
|
||||
import org.springframework.core.io.ByteArrayResource
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.security.access.prepost.PreAuthorize
|
||||
import org.springframework.web.bind.annotation.*
|
||||
import javax.validation.Valid
|
||||
|
||||
const val TOUCH_UP_KIT_CONTROLLER_PATH = "/api/touchupkit"
|
||||
|
||||
@RestController
|
||||
@RequestMapping(TOUCH_UP_KIT_CONTROLLER_PATH)
|
||||
@PreAuthorize("hasAuthority('VIEW_TOUCH_UP_KITS')")
|
||||
class TouchUpKitController(
|
||||
private val touchUpKitService: TouchUpKitService
|
||||
) {
|
||||
@GetMapping
|
||||
fun getAll() =
|
||||
ok(touchUpKitService.getAllForOutput())
|
||||
|
||||
@GetMapping("{id}")
|
||||
fun getById(@PathVariable id: Long) =
|
||||
ok(touchUpKitService.getByIdForOutput(id))
|
||||
|
||||
@PostMapping
|
||||
@PreAuthorize("hasAuthority('EDIT_TOUCH_UP_KITS')")
|
||||
fun save(@Valid @RequestBody touchUpKit: TouchUpKitSaveDto) =
|
||||
created<TouchUpKitOutputDto>(TOUCH_UP_KIT_CONTROLLER_PATH) {
|
||||
with(touchUpKitService) {
|
||||
save(touchUpKit).toOutput()
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
@PreAuthorize("hasAuthority('EDIT_TOUCH_UP_KITS')")
|
||||
fun update(@Valid @RequestBody touchUpKit: TouchUpKitUpdateDto) =
|
||||
noContent {
|
||||
touchUpKitService.update(touchUpKit)
|
||||
}
|
||||
|
||||
@DeleteMapping("{id}")
|
||||
@PreAuthorize("hasAuthority('EDIT_TOUCH_UP_KITS')")
|
||||
fun deleteById(@PathVariable id: Long) =
|
||||
noContent {
|
||||
touchUpKitService.deleteById(id)
|
||||
}
|
||||
|
||||
@GetMapping("pdf")
|
||||
fun getJobPdf(@RequestParam project: String): ResponseEntity<ByteArrayResource> {
|
||||
with(touchUpKitService.generateJobPdfResource(project)) {
|
||||
return ResponseEntity.ok()
|
||||
.header("Content-Disposition", "filename=TouchUpKit_$project.pdf")
|
||||
.contentLength(this.contentLength())
|
||||
.contentType(MediaType.APPLICATION_PDF)
|
||||
.body(this)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -46,7 +46,7 @@ class FileController(
|
|||
}
|
||||
|
||||
@DeleteMapping
|
||||
@PreAuthorize("hasAnyAuthority('REMOVE_FILE')")
|
||||
@PreAuthorize("hasAnyAuthority('WRITE_FILE')")
|
||||
fun delete(@RequestParam path: String): ResponseEntity<Void> {
|
||||
return noContent {
|
||||
fileService.delete(path)
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
package dev.fyloz.colorrecipesexplorer.rest.files
|
||||
|
||||
import dev.fyloz.colorrecipesexplorer.service.files.TouchUpKitService
|
||||
import org.springframework.core.io.ByteArrayResource
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.security.access.prepost.PreAuthorize
|
||||
import org.springframework.web.bind.annotation.*
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/touchup")
|
||||
@PreAuthorize("hasAuthority('GENERATE_TOUCH_UP_KIT')")
|
||||
class TouchUpKitController(
|
||||
private val touchUpKitService: TouchUpKitService
|
||||
) {
|
||||
@GetMapping
|
||||
fun getJobPdf(@RequestParam job: String): ResponseEntity<ByteArrayResource> {
|
||||
with(touchUpKitService.generateJobPdfResource(job)) {
|
||||
return ResponseEntity.ok()
|
||||
.header("Content-Disposition", "filename=TouchUpKit_$job.pdf")
|
||||
.contentLength(this.contentLength())
|
||||
.contentType(MediaType.APPLICATION_PDF)
|
||||
.body(this)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -136,7 +136,7 @@ class MaterialServiceImpl(
|
|||
|
||||
override fun delete(entity: Material) {
|
||||
if (!repository.canBeDeleted(entity.id!!)) throw cannotDeleteMaterialException(entity)
|
||||
fileService.delete(entity.simdutFilePath)
|
||||
if (fileService.exists(entity.simdutFilePath)) fileService.delete(entity.simdutFilePath)
|
||||
super.delete(entity)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
package dev.fyloz.colorrecipesexplorer.service.files
|
||||
package dev.fyloz.colorrecipesexplorer.service.touchupkit
|
||||
|
||||
import dev.fyloz.colorrecipesexplorer.config.properties.CreProperties
|
||||
import dev.fyloz.colorrecipesexplorer.model.touchupkit.*
|
||||
import dev.fyloz.colorrecipesexplorer.repository.TouchUpKitRepository
|
||||
import dev.fyloz.colorrecipesexplorer.rest.TOUCH_UP_KIT_CONTROLLER_PATH
|
||||
import dev.fyloz.colorrecipesexplorer.service.AbstractExternalModelService
|
||||
import dev.fyloz.colorrecipesexplorer.service.ExternalModelService
|
||||
import dev.fyloz.colorrecipesexplorer.service.files.FileService
|
||||
import dev.fyloz.colorrecipesexplorer.utils.*
|
||||
import org.springframework.core.io.ByteArrayResource
|
||||
import org.springframework.stereotype.Service
|
||||
|
@ -10,7 +16,8 @@ private const val TOUCH_UP_KIT_FILES_PATH = "pdf/touchupkits"
|
|||
const val TOUCH_UP_TEXT_FR = "KIT DE RETOUCHE"
|
||||
const val TOUCH_UP_TEXT_EN = "TOUCH UP KIT"
|
||||
|
||||
interface TouchUpKitService {
|
||||
interface TouchUpKitService :
|
||||
ExternalModelService<TouchUpKit, TouchUpKitSaveDto, TouchUpKitUpdateDto, TouchUpKitOutputDto, TouchUpKitRepository> {
|
||||
/** Generates and returns a [PdfDocument] for the given [job]. */
|
||||
fun generateJobPdf(job: String): PdfDocument
|
||||
|
||||
|
@ -29,8 +36,45 @@ interface TouchUpKitService {
|
|||
@Service
|
||||
class TouchUpKitServiceImpl(
|
||||
private val fileService: FileService,
|
||||
private val creProperties: CreProperties
|
||||
) : TouchUpKitService {
|
||||
touchUpKitRepository: TouchUpKitRepository,
|
||||
private val creProperties: CreProperties,
|
||||
) : AbstractExternalModelService<TouchUpKit, TouchUpKitSaveDto, TouchUpKitUpdateDto, TouchUpKitOutputDto, TouchUpKitRepository>(
|
||||
touchUpKitRepository
|
||||
), TouchUpKitService {
|
||||
override fun idNotFoundException(id: Long) = touchUpKitIdNotFoundException(id)
|
||||
override fun idAlreadyExistsException(id: Long) = touchUpKitIdAlreadyExistsException(id)
|
||||
|
||||
override fun TouchUpKit.toOutput() = TouchUpKitOutputDto(
|
||||
this.id!!,
|
||||
this.project,
|
||||
this.buggy,
|
||||
this.company,
|
||||
this.quantity,
|
||||
this.shippingDate,
|
||||
this.finish,
|
||||
this.material,
|
||||
this.content,
|
||||
this.pdfUrl()
|
||||
)
|
||||
|
||||
override fun update(entity: TouchUpKitUpdateDto): TouchUpKit {
|
||||
val persistedKit by lazy { getById(entity.id) }
|
||||
|
||||
return super.update(with(entity) {
|
||||
touchUpKit(
|
||||
id = id,
|
||||
project = project ?: persistedKit.project,
|
||||
buggy = buggy ?: persistedKit.buggy,
|
||||
company = company ?: persistedKit.company,
|
||||
quantity = quantity ?: persistedKit.quantity,
|
||||
shippingDate = shippingDate ?: persistedKit.shippingDate,
|
||||
finish = finish ?: persistedKit.finish,
|
||||
material = material ?: persistedKit.material,
|
||||
content = content?.map { touchUpKitProduct(it) }?.toSet() ?: persistedKit.content
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
override fun generateJobPdf(job: String) = pdf {
|
||||
container {
|
||||
centeredVertically = true
|
||||
|
@ -75,4 +119,7 @@ class TouchUpKitServiceImpl(
|
|||
|
||||
private fun String.pdfDocumentPath() =
|
||||
"$TOUCH_UP_KIT_FILES_PATH/$this.pdf"
|
||||
|
||||
private fun TouchUpKit.pdfUrl() =
|
||||
"${creProperties.deploymentUrl}$TOUCH_UP_KIT_CONTROLLER_PATH/pdf?job=$project"
|
||||
}
|
|
@ -21,7 +21,7 @@ entities.material-types.baseName=Base
|
|||
databaseupdater.username=root
|
||||
databaseupdater.password=pass
|
||||
# DEBUG
|
||||
spring.jpa.show-sql=true
|
||||
spring.jpa.show-sql=false
|
||||
# Do not modify
|
||||
spring.messages.fallback-to-system-locale=true
|
||||
spring.servlet.multipart.max-file-size=10MB
|
||||
|
@ -30,4 +30,6 @@ spring.jpa.open-in-view=true
|
|||
server.http2.enabled=true
|
||||
server.error.whitelabel.enabled=false
|
||||
spring.h2.console.enabled=false
|
||||
spring.jackson.deserialization.fail-on-null-for-primitives=true
|
||||
spring.jackson.default-property-inclusion=non_null
|
||||
spring.profiles.active=@spring.profiles.active@
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
junit.jupiter.testinstance.lifecycle.default=per_class
|
|
@ -1,6 +1,10 @@
|
|||
package dev.fyloz.colorrecipesexplorer.service.files
|
||||
|
||||
import dev.fyloz.colorrecipesexplorer.config.properties.CreProperties
|
||||
import dev.fyloz.colorrecipesexplorer.repository.TouchUpKitRepository
|
||||
import dev.fyloz.colorrecipesexplorer.service.touchupkit.TOUCH_UP_TEXT_EN
|
||||
import dev.fyloz.colorrecipesexplorer.service.touchupkit.TOUCH_UP_TEXT_FR
|
||||
import dev.fyloz.colorrecipesexplorer.service.touchupkit.TouchUpKitServiceImpl
|
||||
import dev.fyloz.colorrecipesexplorer.utils.PdfDocument
|
||||
import dev.fyloz.colorrecipesexplorer.utils.toByteArrayResource
|
||||
import io.mockk.*
|
||||
|
@ -10,13 +14,14 @@ import org.springframework.core.io.ByteArrayResource
|
|||
import kotlin.test.assertEquals
|
||||
|
||||
private class TouchUpKitServiceTestContext {
|
||||
val touchUpKitRepository = mockk<TouchUpKitRepository>()
|
||||
val fileService = mockk<FileService> {
|
||||
every { write(any<ByteArrayResource>(), any(), any()) } just Runs
|
||||
}
|
||||
val creProperties = mockk<CreProperties> {
|
||||
every { cacheGeneratedFiles } returns false
|
||||
}
|
||||
val touchUpKitService = spyk(TouchUpKitServiceImpl(fileService, creProperties))
|
||||
val touchUpKitService = spyk(TouchUpKitServiceImpl(fileService, touchUpKitRepository, creProperties))
|
||||
val pdfDocumentData = mockk<ByteArrayResource>()
|
||||
val pdfDocument = mockk<PdfDocument> {
|
||||
mockkStatic(PdfDocument::toByteArrayResource)
|
||||
|
|
Loading…
Reference in New Issue