diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/model/Mix.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/model/Mix.java deleted file mode 100644 index ff7303f..0000000 --- a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/model/Mix.java +++ /dev/null @@ -1,59 +0,0 @@ -package dev.fyloz.trial.colorrecipesexplorer.model; - -import lombok.*; - -import javax.persistence.*; -import javax.validation.constraints.NotNull; -import java.util.List; -import java.util.Objects; - -@Entity -@Data -@RequiredArgsConstructor -@NoArgsConstructor -@AllArgsConstructor -public class Mix implements Model { - - public static final String IDENTIFIER_MIX_TYPE_NAME = "mixType"; - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE) - @Basic - private Long id; - - @NonNull - @ToString.Exclude - @NotNull - @ManyToOne - private Recipe recipe; - - @NonNull - @NotNull - @ManyToOne - private MixType mixType; - - @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL) - @JoinColumn(name = "mix") - private List mixMaterials; - - // Casier - private String location; - - public MixType getMixType() { - return mixType; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Mix mix = (Mix) o; - return Objects.equals(recipe, mix.recipe) && - Objects.equals(mixType, mix.mixType); - } - - @Override - public int hashCode() { - return Objects.hash(recipe, mixType); - } -} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/repository/MixRepository.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/repository/MixRepository.java deleted file mode 100644 index 6de331a..0000000 --- a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/repository/MixRepository.java +++ /dev/null @@ -1,15 +0,0 @@ -package dev.fyloz.trial.colorrecipesexplorer.repository; - -import dev.fyloz.trial.colorrecipesexplorer.model.Mix; -import dev.fyloz.trial.colorrecipesexplorer.model.Recipe; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -import java.util.List; - -@Repository -public interface MixRepository extends JpaRepository { - - List findAllByRecipe(Recipe recipe); - -} diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/service/model/MixService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/service/model/MixJavaService.java similarity index 94% rename from src/main/java/dev/fyloz/trial/colorrecipesexplorer/service/model/MixService.java rename to src/main/java/dev/fyloz/trial/colorrecipesexplorer/service/model/MixJavaService.java index c9370b3..9e60e63 100644 --- a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/service/model/MixService.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/service/model/MixJavaService.java @@ -4,9 +4,9 @@ import dev.fyloz.trial.colorrecipesexplorer.exception.model.EntityAlreadyExistsE import dev.fyloz.trial.colorrecipesexplorer.exception.model.ModelException; import dev.fyloz.trial.colorrecipesexplorer.model.*; import dev.fyloz.trial.colorrecipesexplorer.model.dto.MixFormDto; +import dev.fyloz.trial.colorrecipesexplorer.repository.MixRepository; import dev.fyloz.trial.colorrecipesexplorer.service.AbstractJavaService; import dev.fyloz.trial.colorrecipesexplorer.utils.MixBuilder; -import dev.fyloz.trial.colorrecipesexplorer.repository.MixRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -16,13 +16,13 @@ import java.util.Comparator; import java.util.stream.Collectors; @Service -public class MixService extends AbstractJavaService { +public class MixJavaService extends AbstractJavaService { private MaterialJavaService materialService; private MixMaterialJavaService mixQuantityService; private MixTypeJavaService mixTypeService; - public MixService() { + public MixJavaService() { super(Mix.class); } @@ -97,7 +97,7 @@ public class MixService extends AbstractJavaService { .build(); if (mix.getRecipe().containsMixType(mix.getMixType())) - throw new EntityAlreadyExistsException(type, ModelException.IdentifierType.OTHER, Mix.IDENTIFIER_MIX_TYPE_NAME, mix.getMixType().getName()); + throw new EntityAlreadyExistsException(type, ModelException.IdentifierType.OTHER, MixKt.IDENTIFIER_MIX_TYPE_NAME, mix.getMixType().getName()); mixTypeService.save(mix.getMixType()); save(mix); @@ -112,7 +112,7 @@ public class MixService extends AbstractJavaService { MixType mixType = mix.getMixType(); if (!formDto.getOldMixTypeName().equals(mixType.getName()) && mixTypeService.existsByName(formDto.getMixTypeName()) && mix.getRecipe().containsMixType(mixType)) - throw new EntityAlreadyExistsException(type, ModelException.IdentifierType.OTHER, Mix.IDENTIFIER_MIX_TYPE_NAME, mix.getMixType().getName()); + throw new EntityAlreadyExistsException(type, ModelException.IdentifierType.OTHER, MixKt.IDENTIFIER_MIX_TYPE_NAME, mix.getMixType().getName()); if (materialService.existsByName(mixType.getName()) && !materialService.getByName(mixType.getName()).isMixType()) throw new EntityAlreadyExistsException(type, ModelException.IdentifierType.OTHER, MixTypeKt.IDENTIFIER_MATERIAL_NAME, mixType.getName()); diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/service/model/RecipeJavaService.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/service/model/RecipeJavaService.java index 6f75c9e..9694379 100644 --- a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/service/model/RecipeJavaService.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/service/model/RecipeJavaService.java @@ -20,7 +20,7 @@ import java.util.stream.Collectors; public class RecipeJavaService extends AbstractJavaService { private CompanyJavaService companyService; - private MixService mixService; + private MixJavaService mixService; private RecipeStepJavaService stepService; private ImagesService imagesService; @@ -39,7 +39,7 @@ public class RecipeJavaService extends AbstractJavaService mixQuantities = new ArrayList<>(); + private Collection mixMaterials = new ArrayList<>(); private Map quantities = new LinkedHashMap<>(); @@ -31,7 +30,7 @@ public class MixBuilder { this.recipe = mix.getRecipe(); this.mixType = mix.getMixType(); this.location = mix.getLocation(); - this.mixQuantities = mix.getMixMaterials(); + this.mixMaterials = mix.getMixMaterials(); return this; } @@ -82,25 +81,22 @@ public class MixBuilder { } public MixBuilder withMixQuantity(MixMaterial mixMaterial) { - this.mixQuantities.add(mixMaterial); + this.mixMaterials.add(mixMaterial); return this; } public MixBuilder withMixQuantities(List mixQuantities) { - this.mixQuantities = mixQuantities; + this.mixMaterials = mixQuantities; return this; } public Mix build() { - Mix mix = new Mix(this.recipe, this.mixType); + Mix mix = new Mix(this.id, this.location, this.recipe, this.mixType, new ArrayList<>()); createMixQuantities(mix); - - mix.setId(this.id); - mix.setLocation(this.location); - mix.setMixMaterials(this.mixQuantities); + mix.getMixMaterials().addAll(this.mixMaterials); return mix; } @@ -115,6 +111,6 @@ public class MixBuilder { mixQuantities.add(new MixMaterial(mix, material, quantity)); } - this.mixQuantities = mixQuantities; + this.mixMaterials = mixQuantities; } } diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/thymeleaf/OthersController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/thymeleaf/OthersController.java index 12ecc1c..684fe40 100644 --- a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/thymeleaf/OthersController.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/thymeleaf/OthersController.java @@ -4,7 +4,7 @@ import dev.fyloz.trial.colorrecipesexplorer.exception.model.EntityNotFoundExcept import dev.fyloz.trial.colorrecipesexplorer.web.response.ModelResponseBuilder; import dev.fyloz.trial.colorrecipesexplorer.web.response.ResponseCode; import dev.fyloz.trial.colorrecipesexplorer.service.files.MarkdownFilesService; -import dev.fyloz.trial.colorrecipesexplorer.service.model.MixService; +import dev.fyloz.trial.colorrecipesexplorer.service.model.MixJavaService; import dev.fyloz.trial.colorrecipesexplorer.service.model.RecipeJavaService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; @@ -24,12 +24,12 @@ import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.*; @Profile("thymeleaf") public class OthersController { - private MixService mixService; + private MixJavaService mixService; private RecipeJavaService recipeService; private MarkdownFilesService markdownService; @Autowired - public OthersController(MixService mixService, RecipeJavaService recipeService, MarkdownFilesService markdownService) { + public OthersController(MixJavaService mixService, RecipeJavaService recipeService, MarkdownFilesService markdownService) { this.mixService = mixService; this.recipeService = recipeService; this.markdownService = markdownService; diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/thymeleaf/creators/MixCreatorController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/thymeleaf/creators/MixCreatorController.java index 746b7b0..b55cdde 100644 --- a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/thymeleaf/creators/MixCreatorController.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/thymeleaf/creators/MixCreatorController.java @@ -2,12 +2,12 @@ package dev.fyloz.trial.colorrecipesexplorer.web.controller.thymeleaf.creators; import dev.fyloz.trial.colorrecipesexplorer.exception.model.EntityAlreadyExistsException; import dev.fyloz.trial.colorrecipesexplorer.exception.model.EntityNotFoundException; +import dev.fyloz.trial.colorrecipesexplorer.model.MixKt; import dev.fyloz.trial.colorrecipesexplorer.model.MixTypeKt; import dev.fyloz.trial.colorrecipesexplorer.model.Recipe; import dev.fyloz.trial.colorrecipesexplorer.web.response.ModelResponseBuilder; import dev.fyloz.trial.colorrecipesexplorer.web.response.ResponseCode; import dev.fyloz.trial.colorrecipesexplorer.web.response.ResponseDataType; -import dev.fyloz.trial.colorrecipesexplorer.model.Mix; import dev.fyloz.trial.colorrecipesexplorer.model.dto.MixFormDto; import dev.fyloz.trial.colorrecipesexplorer.service.ServiceKt; import dev.fyloz.trial.colorrecipesexplorer.service.model.*; @@ -29,13 +29,13 @@ import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.*; @Profile("thymeleaf") public class MixCreatorController { - private MixService mixService; + private MixJavaService mixService; private RecipeJavaService recipeService; private MaterialJavaService materialService; private MaterialTypeJavaService materialTypeService; @Autowired - public MixCreatorController(MixService mixService, RecipeJavaService recipeService, MaterialJavaService materialService, MixTypeJavaService mixTypeService, MaterialTypeJavaService materialTypeService) { + public MixCreatorController(MixJavaService mixService, RecipeJavaService recipeService, MaterialJavaService materialService, MixTypeJavaService mixTypeService, MaterialTypeJavaService materialTypeService) { this.mixService = mixService; this.recipeService = recipeService; this.materialService = materialService; @@ -78,7 +78,7 @@ public class MixCreatorController { } catch (EntityNotFoundException ex) { modelResponseBuilder.addResponseCode(ResponseCode.MATERIAL_NOT_FOUND, ex.getRequestedId()); } catch (EntityAlreadyExistsException ex) { - if (ex.getIdentifierName().equals(Mix.IDENTIFIER_MIX_TYPE_NAME)) + if (ex.getIdentifierName().equals(MixKt.IDENTIFIER_MIX_TYPE_NAME)) modelResponseBuilder.addResponseCode(ResponseCode.MIX_TYPE_ALREADY_USED, ex.getRequestedId()); else if (ex.getIdentifierName().equals(MixTypeKt.IDENTIFIER_MATERIAL_NAME)) modelResponseBuilder.addResponseCode(ResponseCode.MATERIAL_AND_MIX_TYPE_CANNOT_HAVE_SAME_NAME); diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/thymeleaf/editors/MixEditorController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/thymeleaf/editors/MixEditorController.java index 5ba7e2b..92ced92 100644 --- a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/thymeleaf/editors/MixEditorController.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/thymeleaf/editors/MixEditorController.java @@ -2,15 +2,16 @@ package dev.fyloz.trial.colorrecipesexplorer.web.controller.thymeleaf.editors; import dev.fyloz.trial.colorrecipesexplorer.exception.model.EntityAlreadyExistsException; import dev.fyloz.trial.colorrecipesexplorer.exception.model.EntityNotFoundException; +import dev.fyloz.trial.colorrecipesexplorer.model.Mix; +import dev.fyloz.trial.colorrecipesexplorer.model.MixKt; import dev.fyloz.trial.colorrecipesexplorer.model.MixTypeKt; import dev.fyloz.trial.colorrecipesexplorer.web.response.ModelResponseBuilder; import dev.fyloz.trial.colorrecipesexplorer.web.response.ResponseCode; import dev.fyloz.trial.colorrecipesexplorer.web.response.ResponseDataType; -import dev.fyloz.trial.colorrecipesexplorer.model.Mix; import dev.fyloz.trial.colorrecipesexplorer.model.dto.MixFormDto; import dev.fyloz.trial.colorrecipesexplorer.service.model.MaterialJavaService; import dev.fyloz.trial.colorrecipesexplorer.service.model.MaterialTypeJavaService; -import dev.fyloz.trial.colorrecipesexplorer.service.model.MixService; +import dev.fyloz.trial.colorrecipesexplorer.service.model.MixJavaService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; import org.springframework.http.MediaType; @@ -26,12 +27,12 @@ import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.*; @Profile("thymeleaf") public class MixEditorController { - private MixService mixService; + private MixJavaService mixService; private MaterialJavaService materialService; private MaterialTypeJavaService materialTypeService; @Autowired - public MixEditorController(MixService mixService, MaterialJavaService materialService, MaterialTypeJavaService materialTypeService) { + public MixEditorController(MixJavaService mixService, MaterialJavaService materialService, MaterialTypeJavaService materialTypeService) { this.mixService = mixService; this.materialService = materialService; this.materialTypeService = materialTypeService; @@ -74,7 +75,7 @@ public class MixEditorController { } catch (EntityAlreadyExistsException ex) { if (ex.getIdentifierName().equals(MixTypeKt.IDENTIFIER_MATERIAL_NAME)) modelResponseBuilder.addResponseCode(ResponseCode.MATERIAL_AND_MIX_TYPE_CANNOT_HAVE_SAME_NAME); - else if (ex.getIdentifierName().equals(Mix.IDENTIFIER_MIX_TYPE_NAME)) + else if (ex.getIdentifierName().equals(MixKt.IDENTIFIER_MIX_TYPE_NAME)) modelResponseBuilder.addResponseCode(ResponseCode.MIX_TYPE_ALREADY_USED, ex.getRequestedId()); else throw new EntityAlreadyExistsException(ex); } diff --git a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/thymeleaf/removers/MixRemoverController.java b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/thymeleaf/removers/MixRemoverController.java index 3971032..227efbe 100644 --- a/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/thymeleaf/removers/MixRemoverController.java +++ b/src/main/java/dev/fyloz/trial/colorrecipesexplorer/web/controller/thymeleaf/removers/MixRemoverController.java @@ -1,10 +1,10 @@ package dev.fyloz.trial.colorrecipesexplorer.web.controller.thymeleaf.removers; import dev.fyloz.trial.colorrecipesexplorer.exception.model.EntityNotFoundException; +import dev.fyloz.trial.colorrecipesexplorer.model.Mix; import dev.fyloz.trial.colorrecipesexplorer.web.response.ModelResponseBuilder; import dev.fyloz.trial.colorrecipesexplorer.web.response.ResponseCode; -import dev.fyloz.trial.colorrecipesexplorer.model.Mix; -import dev.fyloz.trial.colorrecipesexplorer.service.model.MixService; +import dev.fyloz.trial.colorrecipesexplorer.service.model.MixJavaService; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @@ -17,9 +17,9 @@ import static dev.fyloz.trial.colorrecipesexplorer.web.WebsitePaths.*; @Profile("thymeleaf") public class MixRemoverController { - private MixService mixService; + private MixJavaService mixService; - public MixRemoverController(MixService mixService) { + public MixRemoverController(MixJavaService mixService) { this.mixService = mixService; } diff --git a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/model/Mix.kt b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/model/Mix.kt new file mode 100644 index 0000000..3c973a8 --- /dev/null +++ b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/model/Mix.kt @@ -0,0 +1,39 @@ +package dev.fyloz.trial.colorrecipesexplorer.model + +import java.util.* +import javax.persistence.* + +const val IDENTIFIER_MIX_TYPE_NAME = "mixType" + +@Entity +data class Mix( + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE) + override val id: Long?, + + var location: String?, + + @ManyToOne + val recipe: Recipe, + + @ManyToOne + val mixType: MixType, + + @OneToMany + val mixMaterials: Collection, +) : Model { + constructor(recipe: Recipe, mixType: MixType) : this(null, null, recipe, mixType, listOf()) + + override fun equals(other: Any?): Boolean = other is Mix && recipe == other.recipe && mixType == other.mixType + override fun hashCode(): Int = Objects.hash(recipe, mixType) +} + +// ==== DSL ==== +fun mix( + id: Long? = null, + location: String = "location", + recipe: Recipe = recipe(), + mixType: MixType = mixType(), + mixMaterials: Collection = listOf(), + op: Mix.() -> Unit = {} +) = Mix(id, location, recipe, mixType, mixMaterials).apply(op) diff --git a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/model/Recipe.kt b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/model/Recipe.kt index 9de7d65..f25c1e2 100644 --- a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/model/Recipe.kt +++ b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/model/Recipe.kt @@ -44,10 +44,10 @@ data class Recipe( @JsonIgnore @OneToMany - val mixes: List, + val mixes: MutableCollection, - @OneToMany - var steps: List + @OneToMany(cascade = [CascadeType.ALL]) + var steps: MutableCollection ) : Model { constructor( id: Long, @@ -58,7 +58,7 @@ data class Recipe( approbationDate: LocalDate?, remark: String, note: String - ) : this(id, name, description, sample, approbationDate, remark, note, company, listOf(), listOf()) + ) : this(id, name, description, sample, approbationDate, remark, note, company, mutableListOf(), mutableListOf()) val mixesSortedById: Collection @JsonIgnore @@ -67,7 +67,7 @@ data class Recipe( /** The mix types contained in this recipe. */ val mixTypes: Collection @JsonIgnore - get() = mixes.map { it.getMixType() as MixType } + get() = mixes.map { it.mixType } /** Checks if the recipe contains the given [mixType]. */ fun containsMixType(mixType: MixType) = mixTypes.contains(mixType) @@ -76,6 +76,15 @@ data class Recipe( override fun hashCode(): Int = Objects.hash(name, company) } +data class RecipePublicDataDto( + @field:NotNull(message = RECIPE_ID_NULL_MESSAGE) + val id: Long, + + val note: String?, + + val mixesLocation: Map? +) + open class RecipeSaveDto( @field:NotBlank(message = RECIPE_NAME_NULL_MESSAGE) val name: String, @@ -106,22 +115,22 @@ open class RecipeSaveDto( open class RecipeUpdateDto( @field:NotNull(message = RECIPE_ID_NULL_MESSAGE) - val id: Long = 0L, + val id: Long, @field:NullOrNotBlank(message = RECIPE_NAME_NULL_MESSAGE) - val name: String? = "name", + val name: String?, @field:NullOrNotBlank(message = RECIPE_DESCRIPTION_NULL_MESSAGE) - val description: String? = "description", + val description: String?, @field:NullOrSize(min = 0, message = RECIPE_SAMPLE_TOO_SMALL_MESSAGE) - val sample: Int? = -1, + val sample: Int?, - val approbationDate: LocalDate? = LocalDate.MIN, + val approbationDate: LocalDate?, - val remark: String? = "remark", + val remark: String?, - val steps: List? = listOf() + val steps: List? ) : EntityDto { override fun toEntity(): Recipe = recipe( id, @@ -130,7 +139,7 @@ open class RecipeUpdateDto( sample = sample ?: -1, approbationDate = approbationDate ?: LocalDate.MIN, remark = remark ?: "remark", - steps = steps ?: listOf() + steps = steps?.toMutableList() ?: mutableListOf() ) } @@ -144,11 +153,18 @@ fun recipe( remark: String = "remark", note: String = "", company: Company = company(), - mixes: List = listOf(), - steps: List = listOf(), + mixes: MutableCollection = mutableListOf(), + steps: MutableCollection = mutableListOf(), op: Recipe.() -> Unit = {} ) = Recipe(id, name, description, sample, approbationDate, remark, note, company, mixes, steps).apply(op) +fun recipePublicDataDto( + id: Long = 0L, + note: String? = "note", + mixesLocation: Map? = mapOf(), + op: RecipePublicDataDto.() -> Unit = {} +) = RecipePublicDataDto(id, note, mixesLocation).apply(op) + fun recipeSaveDto( name: String = "name", description: String = "description", diff --git a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/repository/MixRepository.kt b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/repository/MixRepository.kt new file mode 100644 index 0000000..c7e3ac3 --- /dev/null +++ b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/repository/MixRepository.kt @@ -0,0 +1,6 @@ +package dev.fyloz.trial.colorrecipesexplorer.repository + +import dev.fyloz.trial.colorrecipesexplorer.model.Mix +import org.springframework.data.jpa.repository.JpaRepository + +interface MixRepository : JpaRepository diff --git a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/rest/RecipeController.kt b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/rest/RecipeController.kt index b51a365..aa0176b 100644 --- a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/rest/RecipeController.kt +++ b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/rest/RecipeController.kt @@ -1,20 +1,30 @@ package dev.fyloz.trial.colorrecipesexplorer.rest import dev.fyloz.trial.colorrecipesexplorer.model.Recipe +import dev.fyloz.trial.colorrecipesexplorer.model.RecipePublicDataDto import dev.fyloz.trial.colorrecipesexplorer.model.RecipeSaveDto import dev.fyloz.trial.colorrecipesexplorer.model.RecipeUpdateDto import dev.fyloz.trial.colorrecipesexplorer.service.RecipeService +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.PutMapping +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 private const val RECIPE_CONTROLLER_PATH = "api/recipe" @RestController @RequestMapping(RECIPE_CONTROLLER_PATH) - class RecipeController(recipeService: RecipeService) : AbstractModelRestApiController( recipeService, RECIPE_CONTROLLER_PATH - ) + ) { + @PutMapping("public") + fun updatePublicData(@Valid @RequestBody publicDataDto: RecipePublicDataDto): ResponseEntity { + service.updatePublicData(publicDataDto) + return ResponseEntity.noContent().build() + } +} diff --git a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/MixService.kt b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/MixService.kt new file mode 100644 index 0000000..6c9546c --- /dev/null +++ b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/MixService.kt @@ -0,0 +1,18 @@ +package dev.fyloz.trial.colorrecipesexplorer.service + +import dev.fyloz.trial.colorrecipesexplorer.model.Mix +import dev.fyloz.trial.colorrecipesexplorer.repository.MixRepository +import org.springframework.stereotype.Service + +interface MixService : ModelService { + /** Updates the location of the given [mix] to the given [location]. */ + fun updateLocation(mix: Mix, location: String) +} + +@Service +class MixServiceImpl(mixRepository: MixRepository) : AbstractModelService(mixRepository), + MixService { + override fun updateLocation(mix: Mix, location: String) { + update(mix.apply { this.location = location }) + } +} diff --git a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/RecipeService.kt b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/RecipeService.kt index b77660d..1c82239 100644 --- a/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/RecipeService.kt +++ b/src/main/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/RecipeService.kt @@ -1,10 +1,13 @@ package dev.fyloz.trial.colorrecipesexplorer.service import dev.fyloz.trial.colorrecipesexplorer.model.* +import dev.fyloz.trial.colorrecipesexplorer.model.validation.isNotNullAndNotBlank +import dev.fyloz.trial.colorrecipesexplorer.model.validation.isNullOrNotBlank import dev.fyloz.trial.colorrecipesexplorer.model.validation.or import dev.fyloz.trial.colorrecipesexplorer.repository.RecipeRepository import org.springframework.stereotype.Service import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract interface RecipeService : ExternalModelService { /** Checks if one or more recipes have the given [company]. */ @@ -12,16 +15,24 @@ interface RecipeService : ExternalModelService + + /** Updates the public data of a recipe with the given [publicDateDto]. */ + fun updatePublicData(publicDataDto: RecipePublicDataDto) } @Service -class RecipeServiceImpl(recipeRepository: RecipeRepository, val companyService: CompanyService) : +class RecipeServiceImpl( + recipeRepository: RecipeRepository, + val companyService: CompanyService, + val mixService: MixService +) : AbstractExternalModelService(recipeRepository), RecipeService { override fun existsByCompany(company: Company): Boolean = repository.existsByCompany(company) override fun getAllByCompany(company: Company): Collection = repository.findAllByCompany(company) override fun save(entity: RecipeSaveDto): Recipe { + // TODO checks if name is unique in the scope of the [company] return save(with(entity) { recipe( name = name, @@ -49,8 +60,27 @@ class RecipeServiceImpl(recipeRepository: RecipeRepository, val companyService: note = persistedRecipe.note, company = persistedRecipe.company, mixes = persistedRecipe.mixes, - steps = if (!steps.isNullOrEmpty()) steps else persistedRecipe.steps + steps = steps?.toMutableList() ?: persistedRecipe.steps ) }) } + + @ExperimentalContracts + override fun updatePublicData(publicDataDto: RecipePublicDataDto) { + val recipe = getById(publicDataDto.id) + + if (isNotNullAndNotBlank(publicDataDto.note)) { + update(recipe.apply { note = publicDataDto.note }) + } + + with(publicDataDto.mixesLocation) { + if (!isNullOrEmpty()) { + // Map each mix ID to their mix in the recipe + map { recipe.mixes.firstOrNull { mix -> mix.id == it.key } to it.value } + // Remove pairs with a null mix + .filter { it.first != null } + .forEach { mixService.updateLocation(it.first!!, it.second) } + } + } + } } diff --git a/src/test/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/MixServiceTest.kt b/src/test/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/MixServiceTest.kt new file mode 100644 index 0000000..f6f153e --- /dev/null +++ b/src/test/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/MixServiceTest.kt @@ -0,0 +1,30 @@ +package dev.fyloz.trial.colorrecipesexplorer.service + +import com.nhaarman.mockitokotlin2.* +import dev.fyloz.trial.colorrecipesexplorer.model.Mix +import dev.fyloz.trial.colorrecipesexplorer.model.mix +import dev.fyloz.trial.colorrecipesexplorer.repository.MixRepository +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test + +class MixServiceTest : AbstractModelServiceTest() { + override val repository: MixRepository = mock() + override val service: MixService = spy(MixServiceImpl(repository)) + + override val entity: Mix = mix(id = 0L, location = "location") + override val anotherEntity: Mix = mix(id = 1L) + + @Nested + inner class UpdateLocation { + @Test + fun `calls update() with the given mix with the given location`() { + val newLocation = "new location" + val expected = entity.apply { location = newLocation } + doReturn(expected).whenever(service).update(expected) + + service.updateLocation(entity, newLocation) + + verify(service).update(expected) + } + } +} diff --git a/src/test/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/RecipeServiceTest.kt b/src/test/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/RecipeServiceTest.kt index 2ac5df3..c836414 100644 --- a/src/test/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/RecipeServiceTest.kt +++ b/src/test/kotlin/dev/fyloz/trial/colorrecipesexplorer/service/RecipeServiceTest.kt @@ -1,9 +1,6 @@ package dev.fyloz.trial.colorrecipesexplorer.service -import com.nhaarman.mockitokotlin2.doReturn -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.spy -import com.nhaarman.mockitokotlin2.whenever +import com.nhaarman.mockitokotlin2.* import dev.fyloz.trial.colorrecipesexplorer.model.* import dev.fyloz.trial.colorrecipesexplorer.repository.RecipeRepository import org.junit.jupiter.api.Nested @@ -16,7 +13,8 @@ class RecipeServiceTest : AbstractExternalModelServiceTest() { override val repository: RecipeRepository = mock() private val companyService: CompanyService = mock() - override val service: RecipeService = spy(RecipeServiceImpl(repository, companyService)) + private val mixService: MixService = mock() + override val service: RecipeService = spy(RecipeServiceImpl(repository, companyService, mixService)) private val company: Company = company(id = 0L) override val entity: Recipe = recipe(id = 0L, name = "recipe", company = company) @@ -66,4 +64,33 @@ class RecipeServiceTest : saveDtoTest(entity, entitySaveDto, service) } } + + @Nested + inner class UpdatePublicDate { + @Test + fun `calls update with the updated note`() { + val publicDataDto = recipePublicDataDto(id = entity.id!!, note = "newNote", mixesLocation = null) + val expected = entity.apply { note = publicDataDto.note!! } + doReturn(entity).whenever(service).getById(entity.id!!) + doReturn(expected).whenever(service).update(expected) + + service.updatePublicData(publicDataDto) + + verify(service).update(expected) + } + + @Test + fun `calls mixService_updateLocation() with every mix and locations`() { + val mix = mix(id = 0L) + val mixRecipe = entity.apply { mixes.add(mix) } + val location = "location" + val mixLocation = mapOf(mix.id!! to location) + val publicDataDto = recipePublicDataDto(id = mixRecipe.id!!, note = null, mixesLocation = mixLocation) + doReturn(mixRecipe).whenever(service).getById(mixRecipe.id!!) + + service.updatePublicData(publicDataDto) + + verify(mixService).updateLocation(mix, location) + } + } }