From 1137f390b7d057680fa553f821e88234cfed2c64 Mon Sep 17 00:00:00 2001 From: JesseBrault0709 <62299747+JesseBrault0709@users.noreply.github.com> Date: Tue, 9 Jul 2024 17:46:17 +0200 Subject: [PATCH] Get recipe info views from RecipeService and RecipeController. --- .../api/recipe/RecipeControllerTests.java | 28 +++++++- .../api/recipe/RecipeController.java | 23 +++++- .../api/recipe/RecipeRepository.java | 5 ++ .../api/recipe/RecipeService.java | 4 ++ .../api/recipe/RecipeServiceImpl.java | 22 ++++++ .../api/recipe/view/RecipeInfoView.java | 71 +++++++++++++++++++ .../api/security/SecurityConfiguration.java | 2 +- 7 files changed, 151 insertions(+), 4 deletions(-) create mode 100644 src/main/java/app/mealsmadeeasy/api/recipe/view/RecipeInfoView.java diff --git a/src/integrationTest/java/app/mealsmadeeasy/api/recipe/RecipeControllerTests.java b/src/integrationTest/java/app/mealsmadeeasy/api/recipe/RecipeControllerTests.java index d1d44ab..6a2be03 100644 --- a/src/integrationTest/java/app/mealsmadeeasy/api/recipe/RecipeControllerTests.java +++ b/src/integrationTest/java/app/mealsmadeeasy/api/recipe/RecipeControllerTests.java @@ -7,8 +7,10 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.web.servlet.MockMvc; +import static org.hamcrest.Matchers.hasSize; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -39,11 +41,12 @@ public class RecipeControllerTests { } @Test - public void getByIdPublicRecipeNoPrincipal() throws Exception { + @DirtiesContext + public void getRecipePageViewByIdPublicRecipeNoPrincipal() throws Exception { final User owner = this.createTestUser("owner"); final Recipe recipe = this.createTestRecipe(owner); this.recipeService.setPublic(recipe, owner, true); - this.mockMvc.perform(get("/recipe/{id}", recipe.getId())) + this.mockMvc.perform(get("/recipes/{id}", recipe.getId())) .andExpect(status().isOk()) .andExpect(jsonPath("$.id").value(1)) .andExpect(jsonPath("$.title").value("Test Recipe")) @@ -54,4 +57,25 @@ public class RecipeControllerTests { .andExpect(jsonPath("$.viewerCount").value(0)); } + @Test + @DirtiesContext + public void getRecipeInfoViewsNoPrincipal() throws Exception { + final User owner = this.createTestUser("owner"); + final Recipe recipe = this.createTestRecipe(owner); + this.recipeService.setPublic(recipe, owner, true); + this.mockMvc.perform(get("/recipes")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.slice.number").value(0)) + .andExpect(jsonPath("$.slice.size").value(20)) + .andExpect(jsonPath("$.content").isArray()) + .andExpect(jsonPath("$.content", hasSize(1))) + .andExpect(jsonPath("$.content[0].id").value(recipe.getId())) + .andExpect(jsonPath("$.content[0].updated").exists()) + .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].public").value(true)) + .andExpect(jsonPath("$.content[0].starCount").value(0)); + } + } diff --git a/src/main/java/app/mealsmadeeasy/api/recipe/RecipeController.java b/src/main/java/app/mealsmadeeasy/api/recipe/RecipeController.java index 8b4a9ea..e0074b7 100644 --- a/src/main/java/app/mealsmadeeasy/api/recipe/RecipeController.java +++ b/src/main/java/app/mealsmadeeasy/api/recipe/RecipeController.java @@ -1,14 +1,20 @@ package app.mealsmadeeasy.api.recipe; import app.mealsmadeeasy.api.recipe.view.RecipeExceptionView; +import app.mealsmadeeasy.api.recipe.view.RecipeInfoView; import app.mealsmadeeasy.api.recipe.view.RecipePageView; import app.mealsmadeeasy.api.user.User; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; +import java.util.HashMap; +import java.util.Map; + @RestController -@RequestMapping("/recipe") +@RequestMapping("/recipes") public class RecipeController { private final RecipeService recipeService; @@ -31,4 +37,19 @@ public class RecipeController { return ResponseEntity.ok(this.recipeService.getPageViewById(id, user)); } + @GetMapping + public ResponseEntity> getRecipeInfoViews( + Pageable pageable, + @AuthenticationPrincipal User user + ) { + final Slice slice = this.recipeService.getInfoViewsViewableBy(pageable, user); + final Map view = new HashMap<>(); + view.put("content", slice.getContent()); + final Map sliceInfo = new HashMap<>(); + sliceInfo.put("size", slice.getSize()); + sliceInfo.put("number", slice.getNumber()); + view.put("slice", sliceInfo); + return ResponseEntity.ok(view); + } + } diff --git a/src/main/java/app/mealsmadeeasy/api/recipe/RecipeRepository.java b/src/main/java/app/mealsmadeeasy/api/recipe/RecipeRepository.java index b3f2643..4c9366d 100644 --- a/src/main/java/app/mealsmadeeasy/api/recipe/RecipeRepository.java +++ b/src/main/java/app/mealsmadeeasy/api/recipe/RecipeRepository.java @@ -1,6 +1,8 @@ package app.mealsmadeeasy.api.recipe; import app.mealsmadeeasy.api.user.UserEntity; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; @@ -34,4 +36,7 @@ public interface RecipeRepository extends JpaRepository { @Query("SELECT size(r.viewers) FROM Recipe r WHERE r.id = ?1") int getViewerCount(long recipeId); + @Query("SELECT r FROM Recipe r WHERE r.isPublic OR ?1 MEMBER OF r.viewers") + Slice findAllViewableBy(UserEntity viewer, Pageable pageable); + } diff --git a/src/main/java/app/mealsmadeeasy/api/recipe/RecipeService.java b/src/main/java/app/mealsmadeeasy/api/recipe/RecipeService.java index 6ecd181..a8692cb 100644 --- a/src/main/java/app/mealsmadeeasy/api/recipe/RecipeService.java +++ b/src/main/java/app/mealsmadeeasy/api/recipe/RecipeService.java @@ -2,9 +2,12 @@ package app.mealsmadeeasy.api.recipe; import app.mealsmadeeasy.api.recipe.comment.RecipeComment; import app.mealsmadeeasy.api.recipe.star.RecipeStar; +import app.mealsmadeeasy.api.recipe.view.RecipeInfoView; import app.mealsmadeeasy.api.recipe.view.RecipePageView; import app.mealsmadeeasy.api.user.User; import org.jetbrains.annotations.Nullable; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; import java.util.List; @@ -20,6 +23,7 @@ public interface RecipeService { Recipe getByIdWithStars(long id, User viewer) throws RecipeException; RecipePageView getPageViewById(long id, @Nullable User viewer) throws RecipeException; + Slice getInfoViewsViewableBy(Pageable pageable, @Nullable User viewer); List getByMinimumStars(long minimumStars); List getByMinimumStars(long minimumStars, User viewer); diff --git a/src/main/java/app/mealsmadeeasy/api/recipe/RecipeServiceImpl.java b/src/main/java/app/mealsmadeeasy/api/recipe/RecipeServiceImpl.java index 457d7c4..0b25452 100644 --- a/src/main/java/app/mealsmadeeasy/api/recipe/RecipeServiceImpl.java +++ b/src/main/java/app/mealsmadeeasy/api/recipe/RecipeServiceImpl.java @@ -6,6 +6,7 @@ import app.mealsmadeeasy.api.recipe.comment.RecipeCommentRepository; import app.mealsmadeeasy.api.recipe.star.RecipeStar; import app.mealsmadeeasy.api.recipe.star.RecipeStarEntity; import app.mealsmadeeasy.api.recipe.star.RecipeStarRepository; +import app.mealsmadeeasy.api.recipe.view.RecipeInfoView; import app.mealsmadeeasy.api.recipe.view.RecipePageView; import app.mealsmadeeasy.api.user.User; import app.mealsmadeeasy.api.user.UserEntity; @@ -15,6 +16,8 @@ import org.commonmark.renderer.html.HtmlRenderer; import org.jetbrains.annotations.Nullable; import org.jsoup.Jsoup; import org.jsoup.safety.Safelist; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; import org.springframework.security.access.prepost.PostAuthorize; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; @@ -127,6 +130,25 @@ public class RecipeServiceImpl implements RecipeService { return view; } + @Override + public Slice getInfoViewsViewableBy(Pageable pageable, @Nullable User viewer) { + return this.recipeRepository.findAllViewableBy((UserEntity) viewer, pageable).map(entity -> { + final RecipeInfoView view = new RecipeInfoView(); + view.setId(entity.getId()); + if (entity.getModified() != null) { + view.setUpdated(entity.getModified()); + } else { + view.setUpdated(entity.getCreated()); + } + view.setTitle(entity.getTitle()); + view.setOwnerId(entity.getOwner().getId()); + view.setOwnerUsername(entity.getOwner().getUsername()); + view.setPublic(entity.isPublic()); + view.setStarCount(this.getStarCount(entity, viewer)); + return view; + }); + } + @Override public List getByMinimumStars(long minimumStars) { return List.copyOf(this.recipeRepository.findAllPublicByStarsGreaterThanEqual(minimumStars)); diff --git a/src/main/java/app/mealsmadeeasy/api/recipe/view/RecipeInfoView.java b/src/main/java/app/mealsmadeeasy/api/recipe/view/RecipeInfoView.java new file mode 100644 index 0000000..23ce669 --- /dev/null +++ b/src/main/java/app/mealsmadeeasy/api/recipe/view/RecipeInfoView.java @@ -0,0 +1,71 @@ +package app.mealsmadeeasy.api.recipe.view; + +import java.time.LocalDateTime; + +public final class RecipeInfoView { + + private long id; + private LocalDateTime updated; + private String title; + private long ownerId; + private String ownerUsername; + private boolean isPublic; + private int starCount; + + public long getId() { + return this.id; + } + + public void setId(long id) { + this.id = id; + } + + public LocalDateTime getUpdated() { + return this.updated; + } + + public void setUpdated(LocalDateTime updated) { + this.updated = updated; + } + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + + public long getOwnerId() { + return this.ownerId; + } + + public void setOwnerId(long ownerId) { + this.ownerId = ownerId; + } + + public String getOwnerUsername() { + return this.ownerUsername; + } + + public void setOwnerUsername(String ownerUsername) { + this.ownerUsername = ownerUsername; + } + + public boolean isPublic() { + return this.isPublic; + } + + public void setPublic(boolean aPublic) { + isPublic = aPublic; + } + + public int getStarCount() { + return this.starCount; + } + + public void setStarCount(int starCount) { + this.starCount = starCount; + } + +} diff --git a/src/main/java/app/mealsmadeeasy/api/security/SecurityConfiguration.java b/src/main/java/app/mealsmadeeasy/api/security/SecurityConfiguration.java index e9917ab..7ff17e8 100644 --- a/src/main/java/app/mealsmadeeasy/api/security/SecurityConfiguration.java +++ b/src/main/java/app/mealsmadeeasy/api/security/SecurityConfiguration.java @@ -34,7 +34,7 @@ public class SecurityConfiguration { @Bean public WebSecurityCustomizer webSecurityCustomizer() { - return web -> web.ignoring().requestMatchers("/greeting", "/auth/**", "/sign-up/**", "/recipe/**"); + return web -> web.ignoring().requestMatchers("/greeting", "/auth/**", "/sign-up/**", "/recipes/**"); } @Bean