Ajout d'un endpoint REST permettant de mettre à jour les informations publiques d'une recette.

This commit is contained in:
FyloZ 2021-01-24 14:58:55 -05:00
parent 04e7049e2e
commit c2c58be6bf
17 changed files with 231 additions and 132 deletions

View File

@ -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<MixMaterial> 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);
}
}

View File

@ -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<Mix, Long> {
List<Mix> findAllByRecipe(Recipe recipe);
}

View File

@ -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<Mix, MixRepository> {
public class MixJavaService extends AbstractJavaService<Mix, MixRepository> {
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<Mix, MixRepository> {
.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<Mix, MixRepository> {
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());

View File

@ -20,7 +20,7 @@ import java.util.stream.Collectors;
public class RecipeJavaService extends AbstractJavaService<Recipe, RecipeRepository> {
private CompanyJavaService companyService;
private MixService mixService;
private MixJavaService mixService;
private RecipeStepJavaService stepService;
private ImagesService imagesService;
@ -39,7 +39,7 @@ public class RecipeJavaService extends AbstractJavaService<Recipe, RecipeReposit
}
@Autowired
public void setMixService(MixService mixService) {
public void setMixService(MixJavaService mixService) {
this.mixService = mixService;
}

View File

@ -4,7 +4,6 @@ import dev.fyloz.trial.colorrecipesexplorer.model.*;
import dev.fyloz.trial.colorrecipesexplorer.model.dto.MixFormDto;
import dev.fyloz.trial.colorrecipesexplorer.service.model.MaterialJavaService;
import dev.fyloz.trial.colorrecipesexplorer.service.model.MixTypeJavaService;
import dev.fyloz.trial.colorrecipesexplorer.model.Material;
import java.util.*;
@ -17,7 +16,7 @@ public class MixBuilder {
private Recipe recipe;
private MixType mixType;
private String location;
private List<MixMaterial> mixQuantities = new ArrayList<>();
private Collection<MixMaterial> mixMaterials = new ArrayList<>();
private Map<String, Float> 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<MixMaterial> 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;
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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<MixMaterial>,
) : 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<MixMaterial> = listOf(),
op: Mix.() -> Unit = {}
) = Mix(id, location, recipe, mixType, mixMaterials).apply(op)

View File

@ -44,10 +44,10 @@ data class Recipe(
@JsonIgnore
@OneToMany
val mixes: List<Mix>,
val mixes: MutableCollection<Mix>,
@OneToMany
var steps: List<RecipeStep>
@OneToMany(cascade = [CascadeType.ALL])
var steps: MutableCollection<RecipeStep>
) : 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<Mix>
@JsonIgnore
@ -67,7 +67,7 @@ data class Recipe(
/** The mix types contained in this recipe. */
val mixTypes: Collection<MixType>
@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<Long, String>?
)
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<RecipeStep>? = listOf()
val steps: List<RecipeStep>?
) : EntityDto<Recipe> {
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<Mix> = listOf(),
steps: List<RecipeStep> = listOf(),
mixes: MutableCollection<Mix> = mutableListOf(),
steps: MutableCollection<RecipeStep> = 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<Long, String>? = mapOf(),
op: RecipePublicDataDto.() -> Unit = {}
) = RecipePublicDataDto(id, note, mixesLocation).apply(op)
fun recipeSaveDto(
name: String = "name",
description: String = "description",

View File

@ -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<Mix, Long>

View File

@ -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<Recipe, RecipeSaveDto, RecipeUpdateDto, RecipeService>(
recipeService,
RECIPE_CONTROLLER_PATH
)
) {
@PutMapping("public")
fun updatePublicData(@Valid @RequestBody publicDataDto: RecipePublicDataDto): ResponseEntity<Void> {
service.updatePublicData(publicDataDto)
return ResponseEntity.noContent().build()
}
}

View File

@ -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<Mix, MixRepository> {
/** Updates the location of the given [mix] to the given [location]. */
fun updateLocation(mix: Mix, location: String)
}
@Service
class MixServiceImpl(mixRepository: MixRepository) : AbstractModelService<Mix, MixRepository>(mixRepository),
MixService {
override fun updateLocation(mix: Mix, location: String) {
update(mix.apply { this.location = location })
}
}

View File

@ -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<Recipe, RecipeSaveDto, RecipeUpdateDto, RecipeRepository> {
/** Checks if one or more recipes have the given [company]. */
@ -12,16 +15,24 @@ 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]. */
fun updatePublicData(publicDataDto: RecipePublicDataDto)
}
@Service
class RecipeServiceImpl(recipeRepository: RecipeRepository, val companyService: CompanyService) :
class RecipeServiceImpl(
recipeRepository: RecipeRepository,
val companyService: CompanyService,
val mixService: MixService
) :
AbstractExternalModelService<Recipe, RecipeSaveDto, RecipeUpdateDto, RecipeRepository>(recipeRepository),
RecipeService {
override fun existsByCompany(company: Company): Boolean = repository.existsByCompany(company)
override fun getAllByCompany(company: Company): Collection<Recipe> = 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) }
}
}
}
}

View File

@ -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<Mix, MixService, MixRepository>() {
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)
}
}
}

View File

@ -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<Recipe, RecipeSaveDto, RecipeUpdateDto, RecipeService, RecipeRepository>() {
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)
}
}
}