MME-9 Add ingredients to Recipe entity.
This commit is contained in:
parent
a92084a35a
commit
98c89f6247
@ -1,5 +1,6 @@
|
||||
package app.mealsmadeeasy.api.recipe;
|
||||
|
||||
import app.mealsmadeeasy.api.MinIOTestsExtension;
|
||||
import app.mealsmadeeasy.api.PostgresTestsExtension;
|
||||
import app.mealsmadeeasy.api.image.Image;
|
||||
import app.mealsmadeeasy.api.image.ImageException;
|
||||
@ -36,6 +37,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
// TODO: test prep/cooking/total times included
|
||||
@SpringBootTest
|
||||
@ExtendWith(PostgresTestsExtension.class)
|
||||
@ExtendWith(MinIOTestsExtension.class)
|
||||
public class RecipeServiceTests {
|
||||
|
||||
@Autowired
|
||||
@ -107,16 +109,31 @@ public class RecipeServiceTests {
|
||||
public void whenCreate_allFieldsTransferredFromSpec() throws Exception {
|
||||
final User owner = this.seedUser();
|
||||
final Image image = this.seedImage(owner);
|
||||
|
||||
final List<RecipeCreateSpec.IngredientCreateSpec> ingredients = List.of(
|
||||
RecipeCreateSpec.IngredientCreateSpec.builder()
|
||||
.amount("1T")
|
||||
.name("Butter")
|
||||
.notes("softened")
|
||||
.build(),
|
||||
RecipeCreateSpec.IngredientCreateSpec.builder()
|
||||
.amount("2T")
|
||||
.name("Shortening")
|
||||
.notes("vegan")
|
||||
.build()
|
||||
);
|
||||
final RecipeCreateSpec spec = RecipeCreateSpec.builder()
|
||||
.title("Recipe Title")
|
||||
.slug("recipe-slug")
|
||||
.preparationTime(15)
|
||||
.cookingTime(30)
|
||||
.totalTime(45)
|
||||
.ingredients(ingredients)
|
||||
.rawText("# Hello Recipe")
|
||||
.isPublic(true)
|
||||
.mainImage(image)
|
||||
.build();
|
||||
|
||||
final Recipe recipe = this.recipeService.create(owner, spec, false);
|
||||
assertThat(recipe.getId(), is(notNullValue()));
|
||||
assertThat(recipe.getTitle(), is("Recipe Title"));
|
||||
@ -124,6 +141,8 @@ public class RecipeServiceTests {
|
||||
assertThat(recipe.getPreparationTime(), is(15));
|
||||
assertThat(recipe.getCookingTime(), is(30));
|
||||
assertThat(recipe.getTotalTime(), is(45));
|
||||
assertThat(recipe.getIngredients(), is(notNullValue()));
|
||||
assertThat(recipe.getIngredients().size(), is(2));
|
||||
assertThat(recipe.getRawText(), is("# Hello Recipe"));
|
||||
assertThat(recipe.getMainImage(), is(notNullValue()));
|
||||
assertThat(recipe.getMainImage().getId(), is(image.getId()));
|
||||
@ -305,6 +324,61 @@ public class RecipeServiceTests {
|
||||
assertThat(viewableInfos, containsRecipes(r0, r1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenUpdate_allFieldsTransferred() throws Exception {
|
||||
final User owner = this.seedUser();
|
||||
final Recipe base = this.createTestRecipe(owner);
|
||||
|
||||
final List<RecipeUpdateSpec.IngredientUpdateSpec> ingredients = List.of(
|
||||
RecipeUpdateSpec.IngredientUpdateSpec.builder()
|
||||
.amount("1T")
|
||||
.name("Butter")
|
||||
.notes("Softened")
|
||||
.build(),
|
||||
RecipeUpdateSpec.IngredientUpdateSpec.builder()
|
||||
.amount("2T")
|
||||
.name("Shortening")
|
||||
.notes("Vegan")
|
||||
.build()
|
||||
);
|
||||
|
||||
final Image image = this.seedImage(owner);
|
||||
final RecipeUpdateSpec.MainImageUpdateSpec mainImageSpec = RecipeUpdateSpec.MainImageUpdateSpec.builder()
|
||||
.username(image.getOwner().getUsername())
|
||||
.filename(image.getUserFilename())
|
||||
.build();
|
||||
|
||||
final RecipeUpdateSpec spec = RecipeUpdateSpec.builder()
|
||||
.title("New Title")
|
||||
.preparationTime(20)
|
||||
.cookingTime(40)
|
||||
.totalTime(60)
|
||||
.ingredients(ingredients)
|
||||
.rawText("Updated text.")
|
||||
.isPublic(true)
|
||||
.mainImage(mainImageSpec)
|
||||
.build();
|
||||
|
||||
final Recipe updated = this.recipeService.update(
|
||||
base.getOwner().getUsername(),
|
||||
base.getSlug(),
|
||||
spec,
|
||||
owner
|
||||
);
|
||||
|
||||
assertThat(updated.getId(), is(base.getId()));
|
||||
assertThat(updated.getTitle(), is("New Title"));
|
||||
assertThat(updated.getSlug(), is(base.getSlug()));
|
||||
assertThat(updated.getPreparationTime(), is(20));
|
||||
assertThat(updated.getCookingTime(), is(40));
|
||||
assertThat(updated.getTotalTime(), is(60));
|
||||
assertThat(updated.getIngredients(), is(notNullValue()));
|
||||
assertThat(updated.getIngredients().size(), is(2));
|
||||
assertThat(updated.getIsPublic(), is(true));
|
||||
assertThat(updated.getMainImage(), is(notNullValue()));
|
||||
assertThat(updated.getMainImage().getId(), is(image.getId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateRawText() {
|
||||
final User owner = this.seedUser();
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package app.mealsmadeeasy.api.recipe;
|
||||
|
||||
import app.mealsmadeeasy.api.MinIOTestsExtension;
|
||||
import app.mealsmadeeasy.api.PostgresTestsExtension;
|
||||
import app.mealsmadeeasy.api.auth.AuthService;
|
||||
import app.mealsmadeeasy.api.auth.LoginDetails;
|
||||
@ -25,6 +26,7 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
@ -35,6 +37,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
@SpringBootTest
|
||||
@AutoConfigureMockMvc
|
||||
@ExtendWith(PostgresTestsExtension.class)
|
||||
@ExtendWith(MinIOTestsExtension.class)
|
||||
public class RecipesControllerTests {
|
||||
|
||||
private static InputStream getHal9000() {
|
||||
@ -222,13 +225,39 @@ public class RecipesControllerTests {
|
||||
public void updateRecipe() throws Exception {
|
||||
final User owner = this.seedUser();
|
||||
final Recipe recipe = this.createTestRecipe(owner, false);
|
||||
final String accessToken = this.getAccessToken(owner);
|
||||
final String body = this.getUpdateBody();
|
||||
final Image image = this.createHal9000(owner);
|
||||
|
||||
final RecipeUpdateSpec spec = RecipeUpdateSpec.builder()
|
||||
.title("Updated Test Recipe")
|
||||
.preparationTime(15)
|
||||
.cookingTime(30)
|
||||
.totalTime(45)
|
||||
.ingredients(List.of(
|
||||
RecipeUpdateSpec.IngredientUpdateSpec.builder()
|
||||
.amount("1T")
|
||||
.name("Butter")
|
||||
.notes("Softened")
|
||||
.build(),
|
||||
RecipeUpdateSpec.IngredientUpdateSpec.builder()
|
||||
.amount("2T")
|
||||
.name("Shortening")
|
||||
.notes("Vegan")
|
||||
.build()
|
||||
))
|
||||
.rawText("# Hello, Updated World!")
|
||||
.isPublic(true)
|
||||
.mainImage(RecipeUpdateSpec.MainImageUpdateSpec.builder()
|
||||
.username(image.getOwner().getUsername())
|
||||
.filename(image.getUserFilename())
|
||||
.build())
|
||||
.build();
|
||||
final String updateBody = this.objectMapper.writeValueAsString(spec);
|
||||
|
||||
this.mockMvc.perform(
|
||||
post("/recipes/{username}/{slug}", owner.getUsername(), recipe.getSlug())
|
||||
.header("Authorization", "Bearer " + accessToken)
|
||||
.header("Authorization", "Bearer " + this.getAccessToken(owner))
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(body)
|
||||
.content(updateBody)
|
||||
)
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.recipe.id").value(recipe.getId()))
|
||||
@ -236,6 +265,15 @@ public class RecipesControllerTests {
|
||||
.andExpect(jsonPath("$.recipe.preparationTime").value(15))
|
||||
.andExpect(jsonPath("$.recipe.cookingTime").value(30))
|
||||
.andExpect(jsonPath("$.recipe.totalTime").value(45))
|
||||
|
||||
.andExpect(jsonPath("$.recipe.ingredients").isArray())
|
||||
.andExpect(jsonPath("$.recipe.ingredients[0].amount").value("1T"))
|
||||
.andExpect(jsonPath("$.recipe.ingredients[0].name").value("Butter"))
|
||||
.andExpect(jsonPath("$.recipe.ingredients[0].notes").value("Softened"))
|
||||
.andExpect(jsonPath("$.recipe.ingredients[1].amount").value("2T"))
|
||||
.andExpect(jsonPath("$.recipe.ingredients[1].name").value("Shortening"))
|
||||
.andExpect(jsonPath("$.recipe.ingredients[1].notes").value("Vegan"))
|
||||
|
||||
.andExpect(jsonPath("$.recipe.text").value("<h1>Hello, Updated World!</h1>"))
|
||||
.andExpect(jsonPath("$.recipe.rawText").value("# Hello, Updated World!"))
|
||||
.andExpect(jsonPath("$.recipe.owner.id").value(owner.getId()))
|
||||
@ -243,7 +281,10 @@ public class RecipesControllerTests {
|
||||
.andExpect(jsonPath("$.recipe.starCount").value(0))
|
||||
.andExpect(jsonPath("$.recipe.viewerCount").value(0))
|
||||
.andExpect(jsonPath("$.recipe.public").value(true))
|
||||
.andExpect(jsonPath("$.recipe.mainImage").value(nullValue()))
|
||||
|
||||
.andExpect(jsonPath("$.recipe.mainImage.owner.username").value(owner.getUsername()))
|
||||
.andExpect(jsonPath("$.recipe.mainImage.filename").value(image.getUserFilename()))
|
||||
|
||||
.andExpect(jsonPath("$.isStarred").value(false))
|
||||
.andExpect(jsonPath("$.isOwner").value(true));
|
||||
}
|
||||
|
||||
@ -4,14 +4,17 @@ import app.mealsmadeeasy.api.image.Image;
|
||||
import app.mealsmadeeasy.api.recipe.comment.RecipeComment;
|
||||
import app.mealsmadeeasy.api.recipe.star.RecipeStar;
|
||||
import app.mealsmadeeasy.api.user.User;
|
||||
import io.hypersistence.utils.hibernate.type.json.JsonBinaryType;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import org.hibernate.annotations.Type;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
@ -21,20 +24,54 @@ import java.util.Set;
|
||||
@ToString
|
||||
public class Recipe {
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public static class Ingredient {
|
||||
|
||||
@Nullable
|
||||
private String amount;
|
||||
|
||||
private String name;
|
||||
|
||||
@Nullable
|
||||
private String notes;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o instanceof Ingredient other) {
|
||||
return Objects.equals(this.amount, other.amount)
|
||||
&& Objects.equals(this.name, other.name)
|
||||
&& Objects.equals(this.notes, other.notes);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.amount, this.name, this.notes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(nullable = false, updatable = false)
|
||||
@Basic(optional = false)
|
||||
@Column(updatable = false)
|
||||
private Integer id;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Basic(optional = false)
|
||||
private OffsetDateTime created;
|
||||
|
||||
private OffsetDateTime modified;
|
||||
|
||||
@Column(nullable = false, unique = true)
|
||||
@Basic(optional = false)
|
||||
@Column(unique = true)
|
||||
private String slug;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Basic(optional = false)
|
||||
private String title;
|
||||
|
||||
@Nullable
|
||||
@ -46,7 +83,13 @@ public class Recipe {
|
||||
@Nullable
|
||||
private Integer totalTime;
|
||||
|
||||
@Column(columnDefinition = "TEXT", nullable = false)
|
||||
@Type(JsonBinaryType.class)
|
||||
@Column(columnDefinition = "JSONB")
|
||||
@Nullable
|
||||
private List<Ingredient> ingredients;
|
||||
|
||||
@Basic(optional = false)
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String rawText;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
@ -63,7 +106,7 @@ public class Recipe {
|
||||
@OneToMany(mappedBy = "recipe", orphanRemoval = true, cascade = CascadeType.ALL)
|
||||
private Set<RecipeComment> comments = new HashSet<>();
|
||||
|
||||
@Column(nullable = false)
|
||||
@Basic(optional = false)
|
||||
private Boolean isPublic = false;
|
||||
|
||||
@ManyToMany
|
||||
|
||||
@ -50,6 +50,20 @@ public class RecipeService {
|
||||
draft.setOwner(owner);
|
||||
draft.setSlug(spec.getSlug());
|
||||
draft.setTitle(spec.getTitle());
|
||||
|
||||
if (spec.getIngredients() != null) {
|
||||
draft.setIngredients(spec.getIngredients().stream()
|
||||
.map(ingredientSpec -> {
|
||||
final Recipe.Ingredient ingredient = new Recipe.Ingredient();
|
||||
ingredient.setAmount(ingredientSpec.amount());
|
||||
ingredient.setName(ingredientSpec.name());
|
||||
ingredient.setNotes(ingredientSpec.notes());
|
||||
return ingredient;
|
||||
})
|
||||
.toList()
|
||||
);
|
||||
}
|
||||
|
||||
draft.setRawText(spec.getRawText());
|
||||
draft.setMainImage(spec.getMainImage());
|
||||
draft.setIsPublic(spec.isPublic());
|
||||
@ -57,12 +71,14 @@ public class RecipeService {
|
||||
draft.setCookingTime(spec.getCookingTime());
|
||||
draft.setTotalTime(spec.getTotalTime());
|
||||
final Recipe saved = this.recipeRepository.save(draft);
|
||||
|
||||
if (queueSummaryJob) {
|
||||
this.jobService.create(
|
||||
RecipeSummaryJobHandler.JOB_KEY,
|
||||
new RecipeSummaryJobHandler.RecipeSummaryJobPayload(saved.getId())
|
||||
);
|
||||
}
|
||||
|
||||
return saved;
|
||||
}
|
||||
|
||||
@ -160,6 +176,19 @@ public class RecipeService {
|
||||
recipe.setTotalTime(spec.getTotalTime());
|
||||
}
|
||||
|
||||
if (spec.getIngredients() != null) {
|
||||
recipe.setIngredients(spec.getIngredients().stream()
|
||||
.map(ingredientSpec -> {
|
||||
final Recipe.Ingredient ingredient = new Recipe.Ingredient();
|
||||
ingredient.setAmount(ingredientSpec.amount());
|
||||
ingredient.setName(ingredientSpec.name());
|
||||
ingredient.setNotes(ingredientSpec.notes());
|
||||
return ingredient;
|
||||
})
|
||||
.toList()
|
||||
);
|
||||
}
|
||||
|
||||
if (spec.getRawText() != null) {
|
||||
recipe.setRawText(spec.getRawText());
|
||||
recipe.setCachedRenderedText(null);
|
||||
|
||||
@ -9,6 +9,7 @@ import app.mealsmadeeasy.api.recipe.comment.RecipeCommentService;
|
||||
import app.mealsmadeeasy.api.recipe.comment.RecipeCommentView;
|
||||
import app.mealsmadeeasy.api.recipe.converter.RecipeToFullViewConverter;
|
||||
import app.mealsmadeeasy.api.recipe.converter.RecipeToInfoViewConverter;
|
||||
import app.mealsmadeeasy.api.recipe.converter.RecipeUpdateBodyToSpecConverter;
|
||||
import app.mealsmadeeasy.api.recipe.spec.RecipeUpdateSpec;
|
||||
import app.mealsmadeeasy.api.recipe.star.RecipeStar;
|
||||
import app.mealsmadeeasy.api.recipe.star.RecipeStarService;
|
||||
@ -43,6 +44,7 @@ public class RecipesController {
|
||||
private final ObjectMapper objectMapper;
|
||||
private final RecipeToFullViewConverter recipeToFullViewConverter;
|
||||
private final RecipeToInfoViewConverter recipeToInfoViewConverter;
|
||||
private final RecipeUpdateBodyToSpecConverter updateBodyToSpecConverter;
|
||||
|
||||
private Map<String, Object> getFullViewWrapper(String username, String slug, FullRecipeView view, @Nullable User viewer) {
|
||||
Map<String, Object> wrapper = new HashMap<>();
|
||||
@ -72,7 +74,7 @@ public class RecipesController {
|
||||
@RequestBody RecipeUpdateBody updateBody,
|
||||
@AuthenticationPrincipal User principal
|
||||
) {
|
||||
final RecipeUpdateSpec spec = RecipeUpdateSpec.from(updateBody);
|
||||
final RecipeUpdateSpec spec = this.updateBodyToSpecConverter.convert(updateBody);
|
||||
final Recipe updated = this.recipeService.update(username, slug, spec, principal);
|
||||
final FullRecipeView view = this.recipeToFullViewConverter.convert(updated, includeRawText, principal);
|
||||
return ResponseEntity.ok(this.getFullViewWrapper(username, slug, view, principal));
|
||||
|
||||
@ -3,6 +3,8 @@ package app.mealsmadeeasy.api.recipe.body;
|
||||
import lombok.Data;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class RecipeUpdateBody {
|
||||
|
||||
@ -12,10 +14,18 @@ public class RecipeUpdateBody {
|
||||
private String filename;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class IngredientUpdateBody {
|
||||
private @Nullable String amount;
|
||||
private String name;
|
||||
private @Nullable String notes;
|
||||
}
|
||||
|
||||
private @Nullable String title;
|
||||
private @Nullable Integer preparationTime;
|
||||
private @Nullable Integer cookingTime;
|
||||
private @Nullable Integer totalTime;
|
||||
private @Nullable List<IngredientUpdateBody> ingredients;
|
||||
private @Nullable String rawText;
|
||||
private @Nullable Boolean isPublic;
|
||||
private @Nullable MainImageUpdateBody mainImage;
|
||||
|
||||
@ -32,12 +32,26 @@ public class RecipeToFullViewConverter {
|
||||
.starCount(this.recipeService.getStarCount(recipe))
|
||||
.viewerCount(this.recipeService.getViewerCount(recipe))
|
||||
.isPublic(recipe.getIsPublic());
|
||||
|
||||
if (recipe.getIngredients() != null) {
|
||||
b.ingredients(recipe.getIngredients().stream()
|
||||
.map(ingredient -> FullRecipeView.IngredientView.builder()
|
||||
.amount(ingredient.getAmount())
|
||||
.name(ingredient.getName())
|
||||
.notes(ingredient.getNotes())
|
||||
.build())
|
||||
.toList()
|
||||
);
|
||||
}
|
||||
|
||||
if (recipe.getMainImage() != null) {
|
||||
b.mainImage(this.imageToViewConverter.convert(recipe.getMainImage(), viewer, false));
|
||||
}
|
||||
|
||||
if (includeRawText) {
|
||||
b.rawText(recipe.getRawText());
|
||||
}
|
||||
|
||||
return b.build();
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
package app.mealsmadeeasy.api.recipe.converter;
|
||||
|
||||
import app.mealsmadeeasy.api.recipe.body.RecipeUpdateBody;
|
||||
import app.mealsmadeeasy.api.recipe.spec.RecipeUpdateSpec;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class RecipeUpdateBodyToSpecConverter {
|
||||
|
||||
public RecipeUpdateSpec convert(RecipeUpdateBody body) {
|
||||
final var b = RecipeUpdateSpec.builder()
|
||||
.title(body.getTitle())
|
||||
.preparationTime(body.getPreparationTime())
|
||||
.cookingTime(body.getCookingTime())
|
||||
.totalTime(body.getTotalTime())
|
||||
.rawText(body.getRawText())
|
||||
.isPublic(body.getIsPublic());
|
||||
|
||||
if (body.getIngredients() != null) {
|
||||
b.ingredients(body.getIngredients().stream()
|
||||
.map(ingredient -> RecipeUpdateSpec.IngredientUpdateSpec.builder()
|
||||
.amount(ingredient.getAmount())
|
||||
.name(ingredient.getName())
|
||||
.notes(ingredient.getNotes())
|
||||
.build())
|
||||
.toList()
|
||||
);
|
||||
}
|
||||
|
||||
final @Nullable RecipeUpdateBody.MainImageUpdateBody mainImage = body.getMainImage();
|
||||
if (mainImage != null) {
|
||||
b.mainImage(
|
||||
RecipeUpdateSpec.MainImageUpdateSpec.builder()
|
||||
.username(mainImage.getUsername())
|
||||
.filename(mainImage.getFilename())
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
return b.build();
|
||||
}
|
||||
|
||||
}
|
||||
@ -5,15 +5,27 @@ import lombok.Builder;
|
||||
import lombok.Value;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Value
|
||||
@Builder
|
||||
public class RecipeCreateSpec {
|
||||
|
||||
@Builder
|
||||
public record IngredientCreateSpec(
|
||||
@Nullable String amount,
|
||||
String name,
|
||||
@Nullable String notes
|
||||
) {}
|
||||
|
||||
String slug;
|
||||
String title;
|
||||
@Nullable Integer preparationTime;
|
||||
@Nullable Integer cookingTime;
|
||||
@Nullable Integer totalTime;
|
||||
@Nullable List<IngredientCreateSpec> ingredients;
|
||||
String rawText;
|
||||
boolean isPublic;
|
||||
@Nullable Image mainImage;
|
||||
|
||||
}
|
||||
|
||||
@ -2,12 +2,13 @@ package app.mealsmadeeasy.api.recipe.spec;
|
||||
|
||||
import app.mealsmadeeasy.api.image.Image;
|
||||
import app.mealsmadeeasy.api.recipe.Recipe;
|
||||
import app.mealsmadeeasy.api.recipe.body.RecipeUpdateBody;
|
||||
import lombok.Builder;
|
||||
import lombok.Value;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
// For now, we cannot change slug after creation.
|
||||
// In the future, we may be able to have redirects from
|
||||
// old slugs to new slugs.
|
||||
@ -22,25 +23,8 @@ public class RecipeUpdateSpec {
|
||||
String filename;
|
||||
}
|
||||
|
||||
public static RecipeUpdateSpec from(RecipeUpdateBody body) {
|
||||
final var b = RecipeUpdateSpec.builder()
|
||||
.title(body.getTitle())
|
||||
.preparationTime(body.getPreparationTime())
|
||||
.cookingTime(body.getCookingTime())
|
||||
.totalTime(body.getTotalTime())
|
||||
.rawText(body.getRawText())
|
||||
.isPublic(body.getIsPublic());
|
||||
final @Nullable RecipeUpdateBody.MainImageUpdateBody mainImage = body.getMainImage();
|
||||
if (mainImage != null) {
|
||||
b.mainImage(
|
||||
MainImageUpdateSpec.builder()
|
||||
.username(mainImage.getUsername())
|
||||
.filename(mainImage.getFilename())
|
||||
.build()
|
||||
);
|
||||
}
|
||||
return b.build();
|
||||
}
|
||||
@Builder
|
||||
public record IngredientUpdateSpec(@Nullable String amount, String name, @Nullable String notes) {}
|
||||
|
||||
// For testing convenience only.
|
||||
@ApiStatus.Internal
|
||||
@ -67,6 +51,7 @@ public class RecipeUpdateSpec {
|
||||
@Nullable Integer preparationTime;
|
||||
@Nullable Integer cookingTime;
|
||||
@Nullable Integer totalTime;
|
||||
@Nullable List<IngredientUpdateSpec> ingredients;
|
||||
String rawText;
|
||||
Boolean isPublic;
|
||||
@Nullable MainImageUpdateSpec mainImage;
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package app.mealsmadeeasy.api.recipe.view;
|
||||
|
||||
import app.mealsmadeeasy.api.image.view.ImageView;
|
||||
import app.mealsmadeeasy.api.recipe.Recipe;
|
||||
import app.mealsmadeeasy.api.user.view.UserInfoView;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.Builder;
|
||||
@ -9,39 +8,14 @@ import lombok.Value;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Value
|
||||
@Builder
|
||||
public class FullRecipeView {
|
||||
|
||||
public static FullRecipeView from(
|
||||
Recipe recipe,
|
||||
String renderedText,
|
||||
boolean includeRawText,
|
||||
int starCount,
|
||||
int viewerCount,
|
||||
@Nullable ImageView mainImage
|
||||
) {
|
||||
final var b = FullRecipeView.builder()
|
||||
.id(recipe.getId())
|
||||
.created(recipe.getCreated())
|
||||
.modified(recipe.getModified())
|
||||
.slug(recipe.getSlug())
|
||||
.title(recipe.getTitle())
|
||||
.preparationTime(recipe.getPreparationTime())
|
||||
.cookingTime(recipe.getCookingTime())
|
||||
.totalTime(recipe.getTotalTime())
|
||||
.text(renderedText)
|
||||
.owner(UserInfoView.from(recipe.getOwner()))
|
||||
.starCount(starCount)
|
||||
.viewerCount(viewerCount)
|
||||
.mainImage(mainImage)
|
||||
.isPublic(recipe.getIsPublic());
|
||||
if (includeRawText) {
|
||||
b.rawText(recipe.getRawText());
|
||||
}
|
||||
return b.build();
|
||||
}
|
||||
@Builder
|
||||
public record IngredientView(@Nullable String amount, String name, @Nullable String notes) {}
|
||||
|
||||
Integer id;
|
||||
OffsetDateTime created;
|
||||
@ -51,6 +25,7 @@ public class FullRecipeView {
|
||||
@Nullable Integer preparationTime;
|
||||
@Nullable Integer cookingTime;
|
||||
@Nullable Integer totalTime;
|
||||
@Nullable List<IngredientView> ingredients;
|
||||
String text;
|
||||
@Nullable String rawText;
|
||||
UserInfoView owner;
|
||||
|
||||
@ -0,0 +1 @@
|
||||
ALTER TABLE recipe ADD COLUMN ingredients JSONB;
|
||||
Loading…
Reference in New Issue
Block a user