Recipe GET now working by ownerUsername and slug.

This commit is contained in:
Jesse Brault 2024-07-29 17:43:39 -05:00
parent 3d7d5d00f1
commit 57d2451be9
18 changed files with 136 additions and 37 deletions

View File

@ -39,6 +39,7 @@ public class RecipeControllerTests {
private Recipe createTestRecipe(User owner, boolean isPublic) { private Recipe createTestRecipe(User owner, boolean isPublic) {
final RecipeCreateSpec spec = new RecipeCreateSpec(); final RecipeCreateSpec spec = new RecipeCreateSpec();
spec.setSlug("test-recipe");
spec.setTitle("Test Recipe"); spec.setTitle("Test Recipe");
spec.setRawText("# Hello, World!"); spec.setRawText("# Hello, World!");
spec.setPublic(isPublic); spec.setPublic(isPublic);
@ -50,12 +51,12 @@ public class RecipeControllerTests {
public void getRecipePageViewByIdPublicRecipeNoPrincipal() throws Exception { public void getRecipePageViewByIdPublicRecipeNoPrincipal() throws Exception {
final User owner = this.createTestUser("owner"); final User owner = this.createTestUser("owner");
final Recipe recipe = this.createTestRecipe(owner, true); final Recipe recipe = this.createTestRecipe(owner, true);
this.mockMvc.perform(get("/recipes/{id}", recipe.getId())) this.mockMvc.perform(get("/recipes/{username}/{slug}", recipe.getOwner().getUsername(), recipe.getSlug()))
.andExpect(status().isOk()) .andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(1)) .andExpect(jsonPath("$.id").value(1))
.andExpect(jsonPath("$.slug").value(recipe.getSlug()))
.andExpect(jsonPath("$.title").value("Test Recipe")) .andExpect(jsonPath("$.title").value("Test Recipe"))
.andExpect(jsonPath("$.text").value("<h1>Hello, World!</h1>")) .andExpect(jsonPath("$.text").value("<h1>Hello, World!</h1>"))
.andExpect(jsonPath("$.ownerId").value(owner.getId()))
.andExpect(jsonPath("$.ownerUsername").value(owner.getUsername())) .andExpect(jsonPath("$.ownerUsername").value(owner.getUsername()))
.andExpect(jsonPath("$.starCount").value(0)) .andExpect(jsonPath("$.starCount").value(0))
.andExpect(jsonPath("$.viewerCount").value(0)); .andExpect(jsonPath("$.viewerCount").value(0));
@ -74,8 +75,8 @@ public class RecipeControllerTests {
.andExpect(jsonPath("$.content", hasSize(1))) .andExpect(jsonPath("$.content", hasSize(1)))
.andExpect(jsonPath("$.content[0].id").value(recipe.getId())) .andExpect(jsonPath("$.content[0].id").value(recipe.getId()))
.andExpect(jsonPath("$.content[0].updated").exists()) .andExpect(jsonPath("$.content[0].updated").exists())
.andExpect(jsonPath("$.content[0].slug").value(recipe.getSlug()))
.andExpect(jsonPath("$.content[0].title").value(recipe.getTitle())) .andExpect(jsonPath("$.content[0].title").value(recipe.getTitle()))
.andExpect(jsonPath("$.content[0].ownerId").value(owner.getId()))
.andExpect(jsonPath("$.content[0].ownerUsername").value(owner.getUsername())) .andExpect(jsonPath("$.content[0].ownerUsername").value(owner.getUsername()))
.andExpect(jsonPath("$.content[0].public").value(true)) .andExpect(jsonPath("$.content[0].public").value(true))
.andExpect(jsonPath("$.content[0].starCount").value(0)); .andExpect(jsonPath("$.content[0].starCount").value(0));

View File

@ -42,6 +42,7 @@ public class RecipeRepositoryTests {
@DirtiesContext @DirtiesContext
public void findsAllPublicRecipes() { public void findsAllPublicRecipes() {
final RecipeEntity publicRecipe = new RecipeEntity(); final RecipeEntity publicRecipe = new RecipeEntity();
publicRecipe.setSlug("public-recipe");
publicRecipe.setPublic(true); publicRecipe.setPublic(true);
publicRecipe.setOwner(this.getOwnerUser()); publicRecipe.setOwner(this.getOwnerUser());
publicRecipe.setTitle("Public Recipe"); publicRecipe.setTitle("Public Recipe");
@ -56,6 +57,7 @@ public class RecipeRepositoryTests {
@DirtiesContext @DirtiesContext
public void doesNotFindNonPublicRecipe() { public void doesNotFindNonPublicRecipe() {
final RecipeEntity nonPublicRecipe = new RecipeEntity(); final RecipeEntity nonPublicRecipe = new RecipeEntity();
nonPublicRecipe.setSlug("non-public-recipe");
nonPublicRecipe.setOwner(this.getOwnerUser()); nonPublicRecipe.setOwner(this.getOwnerUser());
nonPublicRecipe.setTitle("Non-Public Recipe"); nonPublicRecipe.setTitle("Non-Public Recipe");
nonPublicRecipe.setRawText("Hello, World!"); nonPublicRecipe.setRawText("Hello, World!");
@ -69,6 +71,7 @@ public class RecipeRepositoryTests {
@DirtiesContext @DirtiesContext
public void findsAllForViewer() { public void findsAllForViewer() {
final RecipeEntity recipe = new RecipeEntity(); final RecipeEntity recipe = new RecipeEntity();
recipe.setSlug("test-recipe");
recipe.setOwner(this.getOwnerUser()); recipe.setOwner(this.getOwnerUser());
recipe.setTitle("Test Recipe"); recipe.setTitle("Test Recipe");
recipe.setRawText("Hello, World!"); recipe.setRawText("Hello, World!");
@ -89,6 +92,7 @@ public class RecipeRepositoryTests {
@DirtiesContext @DirtiesContext
public void doesNotIncludeNonViewable() { public void doesNotIncludeNonViewable() {
final RecipeEntity recipe = new RecipeEntity(); final RecipeEntity recipe = new RecipeEntity();
recipe.setSlug("test-recipe");
recipe.setOwner(this.getOwnerUser()); recipe.setOwner(this.getOwnerUser());
recipe.setTitle("Test Recipe"); recipe.setTitle("Test Recipe");
recipe.setRawText("Hello, World!"); recipe.setRawText("Hello, World!");

View File

@ -43,11 +43,16 @@ public class RecipeServiceTests {
} }
private Recipe createTestRecipe(@Nullable User owner) { private Recipe createTestRecipe(@Nullable User owner) {
return this.createTestRecipe(owner, false); return this.createTestRecipe(owner, false, null);
} }
private Recipe createTestRecipe(@Nullable User owner, boolean isPublic) { private Recipe createTestRecipe(@Nullable User owner, boolean isPublic) {
return this.createTestRecipe(owner, isPublic, null);
}
private Recipe createTestRecipe(@Nullable User owner, boolean isPublic, @Nullable String slug) {
final RecipeCreateSpec spec = new RecipeCreateSpec(); final RecipeCreateSpec spec = new RecipeCreateSpec();
spec.setSlug(slug != null ? slug : "my-recipe");
spec.setTitle("My Recipe"); spec.setTitle("My Recipe");
spec.setRawText("Hello!"); spec.setRawText("Hello!");
spec.setPublic(isPublic); spec.setPublic(isPublic);
@ -88,6 +93,7 @@ public class RecipeServiceTests {
final Recipe recipe = this.createTestRecipe(owner, true); final Recipe recipe = this.createTestRecipe(owner, true);
final Recipe byId = this.recipeService.getById(recipe.getId(), null); final Recipe byId = this.recipeService.getById(recipe.getId(), null);
assertThat(byId.getId(), is(recipe.getId())); assertThat(byId.getId(), is(recipe.getId()));
assertThat(byId.getSlug(), is(recipe.getSlug()));
assertThat(byId.getTitle(), is("My Recipe")); assertThat(byId.getTitle(), is("My Recipe"));
assertThat(byId.getRawText(), is("Hello!")); assertThat(byId.getRawText(), is("Hello!"));
assertThat(byId.isPublic(), is(true)); assertThat(byId.isPublic(), is(true));
@ -167,9 +173,9 @@ public class RecipeServiceTests {
final User u0 = this.createTestUser("u0"); final User u0 = this.createTestUser("u0");
final User u1 = this.createTestUser("u1"); final User u1 = this.createTestUser("u1");
final Recipe r0 = this.createTestRecipe(owner, true); final Recipe r0 = this.createTestRecipe(owner, true, "r0");
final Recipe r1 = this.createTestRecipe(owner, true); final Recipe r1 = this.createTestRecipe(owner, true, "r1");
final Recipe r2 = this.createTestRecipe(owner, true); final Recipe r2 = this.createTestRecipe(owner, true, "r2");
// r0.stars = 0, r1.stars = 1, r2.stars = 2 // r0.stars = 0, r1.stars = 1, r2.stars = 2
this.recipeStarService.create(r1.getId(), u0.getUsername()); this.recipeStarService.create(r1.getId(), u0.getUsername());
@ -197,9 +203,9 @@ public class RecipeServiceTests {
final User u1 = this.createTestUser("u1"); final User u1 = this.createTestUser("u1");
final User viewer = this.createTestUser("recipeViewer"); final User viewer = this.createTestUser("recipeViewer");
Recipe r0 = this.createTestRecipe(owner); // not public Recipe r0 = this.createTestRecipe(owner, false, "r0"); // not public
Recipe r1 = this.createTestRecipe(owner); Recipe r1 = this.createTestRecipe(owner, false, "r1");
Recipe r2 = this.createTestRecipe(owner); Recipe r2 = this.createTestRecipe(owner, false, "r2");
for (final User starer : List.of(u0, u1)) { for (final User starer : List.of(u0, u1)) {
r0 = this.recipeService.addViewer(r0.getId(), owner, starer); r0 = this.recipeService.addViewer(r0.getId(), owner, starer);
@ -243,8 +249,8 @@ public class RecipeServiceTests {
public void getPublicRecipes() { public void getPublicRecipes() {
final User owner = this.createTestUser("recipeOwner"); final User owner = this.createTestUser("recipeOwner");
Recipe r0 = this.createTestRecipe(owner, true); Recipe r0 = this.createTestRecipe(owner, true, "r0");
Recipe r1 = this.createTestRecipe(owner, true); Recipe r1 = this.createTestRecipe(owner, true, "r1");
final List<Recipe> publicRecipes = this.recipeService.getPublicRecipes(); final List<Recipe> publicRecipes = this.recipeService.getPublicRecipes();
assertThat(publicRecipes.size(), is(2)); assertThat(publicRecipes.size(), is(2));
@ -279,6 +285,7 @@ public class RecipeServiceTests {
public void updateRawText() throws RecipeException { public void updateRawText() throws RecipeException {
final User owner = this.createTestUser("recipeOwner"); final User owner = this.createTestUser("recipeOwner");
final RecipeCreateSpec createSpec = new RecipeCreateSpec(); final RecipeCreateSpec createSpec = new RecipeCreateSpec();
createSpec.setSlug("my-recipe");
createSpec.setTitle("My Recipe"); createSpec.setTitle("My Recipe");
createSpec.setRawText("# A Heading"); createSpec.setRawText("# A Heading");
Recipe recipe = this.recipeService.create(owner, createSpec); Recipe recipe = this.recipeService.create(owner, createSpec);

View File

@ -2,6 +2,7 @@ spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1 spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa spring.datasource.username=sa
spring.datasource.password=sa spring.datasource.password=sa
app.mealsmadeeasy.api.baseUrl=http://localhost:8080
app.mealsmadeeasy.api.security.access-token-lifetime=60 app.mealsmadeeasy.api.security.access-token-lifetime=60
app.mealsmadeeasy.api.security.refresh-token-lifetime=120 app.mealsmadeeasy.api.security.refresh-token-lifetime=120
app.mealsmadeeasy.api.minio.endpoint=http://localhost:9000 app.mealsmadeeasy.api.minio.endpoint=http://localhost:9000

View File

@ -61,6 +61,7 @@ public class DevConfiguration {
logger.info("Created {}", obazdaImage); logger.info("Created {}", obazdaImage);
final RecipeCreateSpec recipeCreateSpec = new RecipeCreateSpec(); final RecipeCreateSpec recipeCreateSpec = new RecipeCreateSpec();
recipeCreateSpec.setSlug("test-recipe");
recipeCreateSpec.setTitle("Test Recipe"); recipeCreateSpec.setTitle("Test Recipe");
recipeCreateSpec.setRawText("Hello, World!"); recipeCreateSpec.setRawText("Hello, World!");
recipeCreateSpec.setPublic(true); recipeCreateSpec.setPublic(true);

View File

@ -13,6 +13,7 @@ public interface Recipe {
Long getId(); Long getId();
LocalDateTime getCreated(); LocalDateTime getCreated();
@Nullable LocalDateTime getModified(); @Nullable LocalDateTime getModified();
String getSlug();
String getTitle(); String getTitle();
String getRawText(); String getRawText();
User getOwner(); User getOwner();

View File

@ -31,10 +31,14 @@ public class RecipeController {
)); ));
} }
@GetMapping("/{id}") @GetMapping("/{username}/{slug}")
public ResponseEntity<FullRecipeView> getById(@PathVariable long id, @AuthenticationPrincipal User user) public ResponseEntity<FullRecipeView> getById(
@PathVariable String username,
@PathVariable String slug,
@AuthenticationPrincipal User viewer
)
throws RecipeException { throws RecipeException {
return ResponseEntity.ok(this.recipeService.getFullViewById(id, user)); return ResponseEntity.ok(this.recipeService.getFullViewByUsernameAndSlug(username, slug, viewer));
} }
@GetMapping @GetMapping

View File

@ -27,6 +27,9 @@ public final class RecipeEntity implements Recipe {
private LocalDateTime modified; private LocalDateTime modified;
@Column(nullable = false, unique = true)
private String slug;
@Column(nullable = false) @Column(nullable = false)
private String title; private String title;
@ -86,6 +89,15 @@ public final class RecipeEntity implements Recipe {
this.modified = modified; this.modified = modified;
} }
@Override
public String getSlug() {
return this.slug;
}
public void setSlug(String slug) {
this.slug = slug;
}
@Override @Override
public String getTitle() { public String getTitle() {
return this.title; return this.title;

View File

@ -3,7 +3,7 @@ package app.mealsmadeeasy.api.recipe;
public class RecipeException extends Exception { public class RecipeException extends Exception {
public enum Type { public enum Type {
INVALID_OWNER_USERNAME, INVALID_STAR, NOT_VIEWABLE, INVALID_COMMENT_ID, INVALID_ID INVALID_OWNER_USERNAME, INVALID_STAR, NOT_VIEWABLE, INVALID_COMMENT_ID, INVALID_USERNAME_OR_SLUG, INVALID_ID
} }
private final Type type; private final Type type;

View File

@ -18,6 +18,9 @@ public interface RecipeRepository extends JpaRepository<RecipeEntity, Long> {
List<RecipeEntity> findAllByOwner(UserEntity owner); List<RecipeEntity> findAllByOwner(UserEntity owner);
@Query("SELECT r from Recipe r WHERE r.owner.username = ?1 AND r.slug = ?2")
Optional<RecipeEntity> findByOwnerUsernameAndSlug(String ownerUsername, String slug);
@Query("SELECT r FROM Recipe r WHERE size(r.stars) >= ?1 AND (r.isPublic OR ?2 MEMBER OF r.viewers)") @Query("SELECT r FROM Recipe r WHERE size(r.stars) >= ?1 AND (r.isPublic OR ?2 MEMBER OF r.viewers)")
List<RecipeEntity> findAllViewableByStarsGreaterThanEqual(long stars, UserEntity viewer); List<RecipeEntity> findAllViewableByStarsGreaterThanEqual(long stars, UserEntity viewer);

View File

@ -7,5 +7,6 @@ public interface RecipeSecurity {
boolean isOwner(Recipe recipe, User user); boolean isOwner(Recipe recipe, User user);
boolean isOwner(long recipeId, User user) throws RecipeException; boolean isOwner(long recipeId, User user) throws RecipeException;
boolean isViewableBy(Recipe recipe, @Nullable User user) throws RecipeException; boolean isViewableBy(Recipe recipe, @Nullable User user) throws RecipeException;
boolean isViewableBy(String ownerUsername, String slug, @Nullable User user) throws RecipeException;
boolean isViewableBy(long recipeId, @Nullable User user) throws RecipeException; boolean isViewableBy(long recipeId, @Nullable User user) throws RecipeException;
} }

View File

@ -56,6 +56,16 @@ public class RecipeSecurityImpl implements RecipeSecurity {
return false; return false;
} }
@Override
public boolean isViewableBy(String ownerUsername, String slug, @Nullable User user) throws RecipeException {
final Recipe recipe = this.recipeRepository.findByOwnerUsernameAndSlug(ownerUsername, slug)
.orElseThrow(() -> new RecipeException(
RecipeException.Type.INVALID_USERNAME_OR_SLUG,
"No such Recipe for username " + ownerUsername + " and slug: " + slug
));
return this.isViewableBy(recipe, user);
}
@Override @Override
public boolean isViewableBy(long recipeId, @Nullable User user) throws RecipeException { public boolean isViewableBy(long recipeId, @Nullable User user) throws RecipeException {
final Recipe recipe = this.recipeRepository.findById(recipeId).orElseThrow(() -> new RecipeException( final Recipe recipe = this.recipeRepository.findById(recipeId).orElseThrow(() -> new RecipeException(

View File

@ -18,6 +18,7 @@ public interface RecipeService {
Recipe getById(long id, @Nullable User viewer) throws RecipeException; Recipe getById(long id, @Nullable User viewer) throws RecipeException;
Recipe getByIdWithStars(long id, @Nullable User viewer) throws RecipeException; Recipe getByIdWithStars(long id, @Nullable User viewer) throws RecipeException;
FullRecipeView getFullViewById(long id, @Nullable User viewer) throws RecipeException; FullRecipeView getFullViewById(long id, @Nullable User viewer) throws RecipeException;
FullRecipeView getFullViewByUsernameAndSlug(String username, String slug, @Nullable User viewer) throws RecipeException;
Slice<RecipeInfoView> getInfoViewsViewableBy(Pageable pageable, @Nullable User viewer); Slice<RecipeInfoView> getInfoViewsViewableBy(Pageable pageable, @Nullable User viewer);
List<Recipe> getByMinimumStars(long minimumStars, @Nullable User viewer); List<Recipe> getByMinimumStars(long minimumStars, @Nullable User viewer);

View File

@ -53,6 +53,7 @@ public class RecipeServiceImpl implements RecipeService {
final RecipeEntity draft = new RecipeEntity(); final RecipeEntity draft = new RecipeEntity();
draft.setCreated(LocalDateTime.now()); draft.setCreated(LocalDateTime.now());
draft.setOwner((UserEntity) owner); draft.setOwner((UserEntity) owner);
draft.setSlug(spec.getSlug());
draft.setTitle(spec.getTitle()); draft.setTitle(spec.getTitle());
draft.setRawText(spec.getRawText()); draft.setRawText(spec.getRawText());
draft.setMainImage((S3ImageEntity) spec.getMainImage()); draft.setMainImage((S3ImageEntity) spec.getMainImage());
@ -97,26 +98,44 @@ public class RecipeServiceImpl implements RecipeService {
return this.recipeRepository.getViewerCount(recipeId); return this.recipeRepository.getViewerCount(recipeId);
} }
@Override private FullRecipeView getFullView(RecipeEntity recipe) {
@PostAuthorize("@recipeSecurity.isViewableBy(#id, #viewer)")
public FullRecipeView getFullViewById(long id, @Nullable User viewer) throws RecipeException {
final RecipeEntity recipe = this.recipeRepository.findById(id).orElseThrow(() -> new RecipeException(
RecipeException.Type.INVALID_ID, "No such Recipe for id: " + id
));
final FullRecipeView view = new FullRecipeView(); final FullRecipeView view = new FullRecipeView();
view.setId(recipe.getId()); view.setId(recipe.getId());
view.setCreated(recipe.getCreated()); view.setCreated(recipe.getCreated());
view.setModified(recipe.getModified()); view.setModified(recipe.getModified());
view.setSlug(recipe.getSlug());
view.setTitle(recipe.getTitle()); view.setTitle(recipe.getTitle());
view.setText(this.getRenderedMarkdown(recipe)); view.setText(this.getRenderedMarkdown(recipe));
view.setOwnerId(recipe.getOwner().getId()); view.setOwnerId(recipe.getOwner().getId());
view.setOwnerUsername(recipe.getOwner().getUsername()); view.setOwnerUsername(recipe.getOwner().getUsername());
view.setStarCount(this.getStarCount(recipe)); view.setStarCount(this.getStarCount(recipe));
view.setViewerCount(this.getViewerCount(recipe.getId())); view.setViewerCount(this.getViewerCount(recipe.getId()));
view.setMainImage(this.imageService.toImageView(recipe.getMainImage())); if (recipe.getMainImage() != null) {
view.setMainImage(this.imageService.toImageView(recipe.getMainImage()));
}
return view; return view;
} }
@Override
@PreAuthorize("@recipeSecurity.isViewableBy(#id, #viewer)")
public FullRecipeView getFullViewById(long id, @Nullable User viewer) throws RecipeException {
final RecipeEntity recipe = this.recipeRepository.findById(id).orElseThrow(() -> new RecipeException(
RecipeException.Type.INVALID_ID, "No such Recipe for id: " + id
));
return this.getFullView(recipe);
}
@Override
@PreAuthorize("@recipeSecurity.isViewableBy(#username, #slug, #viewer)")
public FullRecipeView getFullViewByUsernameAndSlug(String username, String slug, @Nullable User viewer) throws RecipeException {
final RecipeEntity recipe = this.recipeRepository.findByOwnerUsernameAndSlug(username, slug)
.orElseThrow(() -> new RecipeException(
RecipeException.Type.INVALID_USERNAME_OR_SLUG,
"No such Recipe for username " + username + " and slug: " + slug
));
return this.getFullView(recipe);
}
@Override @Override
public Slice<RecipeInfoView> getInfoViewsViewableBy(Pageable pageable, @Nullable User viewer) { public Slice<RecipeInfoView> getInfoViewsViewableBy(Pageable pageable, @Nullable User viewer) {
return this.recipeRepository.findAllViewableBy((UserEntity) viewer, pageable).map(entity -> { return this.recipeRepository.findAllViewableBy((UserEntity) viewer, pageable).map(entity -> {
@ -127,12 +146,14 @@ public class RecipeServiceImpl implements RecipeService {
} else { } else {
view.setUpdated(entity.getCreated()); view.setUpdated(entity.getCreated());
} }
view.setSlug(entity.getSlug());
view.setTitle(entity.getTitle()); view.setTitle(entity.getTitle());
view.setOwnerId(entity.getOwner().getId());
view.setOwnerUsername(entity.getOwner().getUsername()); view.setOwnerUsername(entity.getOwner().getUsername());
view.setPublic(entity.isPublic()); view.setPublic(entity.isPublic());
view.setStarCount(this.getStarCount(entity)); view.setStarCount(this.getStarCount(entity));
view.setMainImage(this.imageService.toImageView(entity.getMainImage())); if (entity.getMainImage() != null) {
view.setMainImage(this.imageService.toImageView(entity.getMainImage()));
}
return view; return view;
}); });
} }
@ -164,6 +185,10 @@ public class RecipeServiceImpl implements RecipeService {
public Recipe update(long id, RecipeUpdateSpec spec, User modifier) throws RecipeException { public Recipe update(long id, RecipeUpdateSpec spec, User modifier) throws RecipeException {
final RecipeEntity entity = this.findRecipeEntity(id); final RecipeEntity entity = this.findRecipeEntity(id);
boolean didModify = false; boolean didModify = false;
if (spec.getSlug() != null) {
entity.setSlug(spec.getSlug());
didModify = true;
}
if (spec.getTitle() != null) { if (spec.getTitle() != null) {
entity.setTitle(spec.getTitle()); entity.setTitle(spec.getTitle());
didModify = true; didModify = true;

View File

@ -5,11 +5,20 @@ import org.jetbrains.annotations.Nullable;
public class RecipeCreateSpec { public class RecipeCreateSpec {
private String slug;
private String title; private String title;
private String rawText; private String rawText;
private boolean isPublic; private boolean isPublic;
private @Nullable Image mainImage; private @Nullable Image mainImage;
public String getSlug() {
return this.slug;
}
public void setSlug(String slug) {
this.slug = slug;
}
public String getTitle() { public String getTitle() {
return this.title; return this.title;
} }

View File

@ -5,11 +5,20 @@ import org.jetbrains.annotations.Nullable;
public class RecipeUpdateSpec { public class RecipeUpdateSpec {
private @Nullable String slug;
private @Nullable String title; private @Nullable String title;
private @Nullable String rawText; private @Nullable String rawText;
private @Nullable Boolean isPublic; private @Nullable Boolean isPublic;
private @Nullable Image mainImage; private @Nullable Image mainImage;
public @Nullable String getSlug() {
return this.slug;
}
public void setSlug(@Nullable String slug) {
this.slug = slug;
}
public @Nullable String getTitle() { public @Nullable String getTitle() {
return this.title; return this.title;
} }

View File

@ -10,6 +10,7 @@ public class FullRecipeView {
private long id; private long id;
private LocalDateTime created; private LocalDateTime created;
private LocalDateTime modified; private LocalDateTime modified;
private String slug;
private String title; private String title;
private String text; private String text;
private long ownerId; private long ownerId;
@ -42,6 +43,14 @@ public class FullRecipeView {
this.modified = modified; this.modified = modified;
} }
public String getSlug() {
return this.slug;
}
public void setSlug(String slug) {
this.slug = slug;
}
public String getTitle() { public String getTitle() {
return this.title; return this.title;
} }

View File

@ -1,6 +1,7 @@
package app.mealsmadeeasy.api.recipe.view; package app.mealsmadeeasy.api.recipe.view;
import app.mealsmadeeasy.api.image.view.ImageView; import app.mealsmadeeasy.api.image.view.ImageView;
import org.jetbrains.annotations.Nullable;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@ -8,12 +9,12 @@ public final class RecipeInfoView {
private long id; private long id;
private LocalDateTime updated; private LocalDateTime updated;
private String slug;
private String title; private String title;
private long ownerId;
private String ownerUsername; private String ownerUsername;
private boolean isPublic; private boolean isPublic;
private int starCount; private int starCount;
private ImageView mainImage; private @Nullable ImageView mainImage;
public long getId() { public long getId() {
return this.id; return this.id;
@ -31,6 +32,14 @@ public final class RecipeInfoView {
this.updated = updated; this.updated = updated;
} }
public String getSlug() {
return this.slug;
}
public void setSlug(String slug) {
this.slug = slug;
}
public String getTitle() { public String getTitle() {
return this.title; return this.title;
} }
@ -39,14 +48,6 @@ public final class RecipeInfoView {
this.title = title; this.title = title;
} }
public long getOwnerId() {
return this.ownerId;
}
public void setOwnerId(long ownerId) {
this.ownerId = ownerId;
}
public String getOwnerUsername() { public String getOwnerUsername() {
return this.ownerUsername; return this.ownerUsername;
} }
@ -71,11 +72,11 @@ public final class RecipeInfoView {
this.starCount = starCount; this.starCount = starCount;
} }
public ImageView getMainImage() { public @Nullable ImageView getMainImage() {
return this.mainImage; return this.mainImage;
} }
public void setMainImage(ImageView mainImage) { public void setMainImage(@Nullable ImageView mainImage) {
this.mainImage = mainImage; this.mainImage = mainImage;
} }