RecipeController for getting RecipePageView.
This commit is contained in:
parent
97bbab3cf0
commit
019210d334
@ -35,7 +35,7 @@ public class RecipeControllerTests {
|
||||
}
|
||||
|
||||
private Recipe createTestRecipe(User owner) {
|
||||
return this.recipeService.create(owner, "Test Recipe", "Hello, World!");
|
||||
return this.recipeService.create(owner, "Test Recipe", "# Hello, World!");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -46,7 +46,12 @@ public class RecipeControllerTests {
|
||||
this.mockMvc.perform(get("/recipe/{id}", recipe.getId()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.id").value(1))
|
||||
.andExpect(jsonPath("$.title").value("Test Recipe"));
|
||||
.andExpect(jsonPath("$.title").value("Test Recipe"))
|
||||
.andExpect(jsonPath("$.text").value("<h1>Hello, World!</h1>"))
|
||||
.andExpect(jsonPath("$.ownerId").value(owner.getId()))
|
||||
.andExpect(jsonPath("$.ownerUsername").value(owner.getUsername()))
|
||||
.andExpect(jsonPath("$.starCount").value(0))
|
||||
.andExpect(jsonPath("$.viewerCount").value(0));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package app.mealsmadeeasy.api.recipe;
|
||||
|
||||
import app.mealsmadeeasy.api.recipe.view.RecipeExceptionView;
|
||||
import app.mealsmadeeasy.api.recipe.view.RecipeGetView;
|
||||
import app.mealsmadeeasy.api.recipe.view.RecipePageView;
|
||||
import app.mealsmadeeasy.api.user.User;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
@ -26,15 +26,9 @@ public class RecipeController {
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<RecipeGetView> getById(@PathVariable long id, @AuthenticationPrincipal User user)
|
||||
public ResponseEntity<RecipePageView> getById(@PathVariable long id, @AuthenticationPrincipal User user)
|
||||
throws RecipeException {
|
||||
final Recipe recipe;
|
||||
if (user != null) {
|
||||
recipe = this.recipeService.getById(id, user);
|
||||
} else {
|
||||
recipe = this.recipeService.getById(id);
|
||||
}
|
||||
return ResponseEntity.ok(new RecipeGetView(recipe.getId(), recipe.getTitle()));
|
||||
return ResponseEntity.ok(this.recipeService.getPageViewById(id, user));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,4 +28,10 @@ public interface RecipeRepository extends JpaRepository<RecipeEntity, Long> {
|
||||
@EntityGraph(attributePaths = { "stars" })
|
||||
Optional<RecipeEntity> findByIdWithStars(long id);
|
||||
|
||||
@Query("SELECT size(r.stars) FROM Recipe r WHERE r.id = ?1")
|
||||
int getStarCount(long recipeId);
|
||||
|
||||
@Query("SELECT size(r.viewers) FROM Recipe r WHERE r.id = ?1")
|
||||
int getViewerCount(long recipeId);
|
||||
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
package app.mealsmadeeasy.api.recipe;
|
||||
|
||||
import app.mealsmadeeasy.api.user.User;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface RecipeSecurity {
|
||||
boolean isOwner(Recipe recipe, User user);
|
||||
boolean isOwner(long recipeId, User user) throws RecipeException;
|
||||
boolean isViewableBy(Recipe recipe, User user);
|
||||
boolean isViewableBy(Recipe recipe, @Nullable User user);
|
||||
boolean isViewableBy(long recipeId, @Nullable User user) throws RecipeException;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package app.mealsmadeeasy.api.recipe;
|
||||
|
||||
import app.mealsmadeeasy.api.user.User;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Objects;
|
||||
@ -29,10 +30,18 @@ public class RecipeSecurityImpl implements RecipeSecurity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isViewableBy(Recipe recipe, User user) {
|
||||
if (Objects.equals(recipe.getOwner().getId(), user.getId())) {
|
||||
public boolean isViewableBy(Recipe recipe, @Nullable User user) {
|
||||
if (recipe.isPublic()) {
|
||||
// public recipe
|
||||
return true;
|
||||
} else if (user == null) {
|
||||
// a non-public recipe with no principal
|
||||
return false;
|
||||
} else if (Objects.equals(recipe.getOwner().getId(), user.getId())) {
|
||||
// is owner
|
||||
return true;
|
||||
} else {
|
||||
// check if viewer
|
||||
final RecipeEntity withViewers = this.recipeRepository.getByIdWithViewers(recipe.getId());
|
||||
for (final User viewer : withViewers.getViewers()) {
|
||||
if (viewer.getId() != null && viewer.getId().equals(user.getId())) {
|
||||
@ -40,7 +49,17 @@ public class RecipeSecurityImpl implements RecipeSecurity {
|
||||
}
|
||||
}
|
||||
}
|
||||
// non-public recipe and not viewer
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isViewableBy(long recipeId, @Nullable User user) throws RecipeException {
|
||||
final Recipe recipe = this.recipeRepository.findById(recipeId).orElseThrow(() -> new RecipeException(
|
||||
RecipeException.Type.INVALID_ID,
|
||||
"No such Recipe with id " + recipeId
|
||||
));
|
||||
return this.isViewableBy(recipe, user);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,7 +2,9 @@ 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.RecipePageView;
|
||||
import app.mealsmadeeasy.api.user.User;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -17,6 +19,8 @@ public interface RecipeService {
|
||||
Recipe getByIdWithStars(long id) throws RecipeException;
|
||||
Recipe getByIdWithStars(long id, User viewer) throws RecipeException;
|
||||
|
||||
RecipePageView getPageViewById(long id, @Nullable User viewer) throws RecipeException;
|
||||
|
||||
List<Recipe> getByMinimumStars(long minimumStars);
|
||||
List<Recipe> getByMinimumStars(long minimumStars, User viewer);
|
||||
|
||||
@ -33,12 +37,14 @@ public interface RecipeService {
|
||||
RecipeStar addStar(Recipe recipe, User giver) throws RecipeException;
|
||||
void deleteStarByUser(Recipe recipe, User giver) throws RecipeException;
|
||||
void deleteStar(RecipeStar recipeStar);
|
||||
int getStarCount(Recipe recipe, @Nullable User viewer);
|
||||
|
||||
Recipe setPublic(Recipe recipe, User owner, boolean isPublic);
|
||||
|
||||
Recipe addViewer(Recipe recipe, User user);
|
||||
Recipe removeViewer(Recipe recipe, User user);
|
||||
Recipe clearViewers(Recipe recipe);
|
||||
int getViewerCount(Recipe recipe, @Nullable User viewer);
|
||||
|
||||
RecipeComment getCommentById(long id) throws RecipeException;
|
||||
RecipeComment addComment(Recipe recipe, String rawCommentText, User commenter);
|
||||
|
@ -6,11 +6,13 @@ 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.RecipePageView;
|
||||
import app.mealsmadeeasy.api.user.User;
|
||||
import app.mealsmadeeasy.api.user.UserEntity;
|
||||
import app.mealsmadeeasy.api.user.UserRepository;
|
||||
import org.commonmark.parser.Parser;
|
||||
import org.commonmark.renderer.html.HtmlRenderer;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.safety.Safelist;
|
||||
import org.springframework.security.access.prepost.PostAuthorize;
|
||||
@ -82,7 +84,7 @@ public class RecipeServiceImpl implements RecipeService {
|
||||
}
|
||||
|
||||
@Override
|
||||
@PostAuthorize("returnObject.isPublic || @recipeSecurity.isViewableBy(returnObject, #viewer)")
|
||||
@PostAuthorize("@recipeSecurity.isViewableBy(returnObject, #viewer)")
|
||||
public Recipe getById(long id, User viewer) throws RecipeException {
|
||||
return this.recipeRepository.findById(id).orElseThrow(() -> new RecipeException(
|
||||
RecipeException.Type.INVALID_ID,
|
||||
@ -100,7 +102,7 @@ public class RecipeServiceImpl implements RecipeService {
|
||||
}
|
||||
|
||||
@Override
|
||||
@PostAuthorize("returnObject.isPublic || @recipeSecurity.isViewableBy(returnObject, #viewer)")
|
||||
@PostAuthorize("@recipeSecurity.isViewableBy(returnObject, #viewer)")
|
||||
public Recipe getByIdWithStars(long id, User viewer) throws RecipeException {
|
||||
return this.recipeRepository.findByIdWithStars(id).orElseThrow(() -> new RecipeException(
|
||||
RecipeException.Type.INVALID_ID,
|
||||
@ -108,6 +110,23 @@ public class RecipeServiceImpl implements RecipeService {
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
@PostAuthorize("@recipeSecurity.isViewableBy(#id, #viewer)")
|
||||
public RecipePageView getPageViewById(long id, @Nullable User viewer) throws RecipeException {
|
||||
final Recipe recipe = this.recipeRepository.getReferenceById(id);
|
||||
final RecipePageView view = new RecipePageView();
|
||||
view.setId(recipe.getId());
|
||||
view.setCreated(recipe.getCreated());
|
||||
view.setModified(recipe.getModified());
|
||||
view.setTitle(recipe.getTitle());
|
||||
view.setText(this.getRenderedMarkdown(recipe, viewer));
|
||||
view.setOwnerId(recipe.getOwner().getId());
|
||||
view.setOwnerUsername(recipe.getOwner().getUsername());
|
||||
view.setStarCount(this.getStarCount(recipe, viewer));
|
||||
view.setViewerCount(this.getViewerCount(recipe, viewer));
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Recipe> getByMinimumStars(long minimumStars) {
|
||||
return List.copyOf(this.recipeRepository.findAllPublicByStarsGreaterThanEqual(minimumStars));
|
||||
@ -136,7 +155,7 @@ public class RecipeServiceImpl implements RecipeService {
|
||||
}
|
||||
|
||||
@Override
|
||||
@PreAuthorize("#recipe.isPublic || @recipeSecurity.isViewableBy(#recipe, #viewer)")
|
||||
@PreAuthorize("@recipeSecurity.isViewableBy(#recipe, #viewer)")
|
||||
public String getRenderedMarkdown(Recipe recipe, User viewer) {
|
||||
RecipeEntity entity = (RecipeEntity) recipe;
|
||||
if (entity.getCachedRenderedText() == null) {
|
||||
@ -164,7 +183,7 @@ public class RecipeServiceImpl implements RecipeService {
|
||||
}
|
||||
|
||||
@Override
|
||||
@PreAuthorize("#recipe.isPublic || @recipeSecurity.isViewableBy(#recipe, #giver)")
|
||||
@PreAuthorize("@recipeSecurity.isViewableBy(#recipe, #giver)")
|
||||
public RecipeStar addStar(Recipe recipe, User giver) {
|
||||
final RecipeStarEntity star = new RecipeStarEntity();
|
||||
star.setOwner((UserEntity) giver);
|
||||
@ -189,6 +208,12 @@ public class RecipeServiceImpl implements RecipeService {
|
||||
this.recipeStarRepository.delete(star);
|
||||
}
|
||||
|
||||
@Override
|
||||
@PreAuthorize("@recipeSecurity.isViewableBy(#recipe, #viewer)")
|
||||
public int getStarCount(Recipe recipe, @Nullable User viewer) {
|
||||
return this.recipeRepository.getStarCount(recipe.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
@PreAuthorize("@recipeSecurity.isOwner(#recipe, #owner)")
|
||||
public Recipe setPublic(Recipe recipe, User owner, boolean isPublic) {
|
||||
@ -222,6 +247,12 @@ public class RecipeServiceImpl implements RecipeService {
|
||||
return this.recipeRepository.save(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@PreAuthorize("@recipeSecurity.isViewableBy(#recipe, #viewer)")
|
||||
public int getViewerCount(Recipe recipe, User viewer) {
|
||||
return this.recipeRepository.getViewerCount(recipe.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecipeComment getCommentById(long id) throws RecipeException {
|
||||
return this.recipeCommentRepository.findById(id)
|
||||
|
@ -0,0 +1,91 @@
|
||||
package app.mealsmadeeasy.api.recipe.view;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class RecipePageView {
|
||||
|
||||
private long id;
|
||||
private LocalDateTime created;
|
||||
private LocalDateTime modified;
|
||||
private String title;
|
||||
private String text;
|
||||
private long ownerId;
|
||||
private String ownerUsername;
|
||||
private int starCount;
|
||||
private int viewerCount;
|
||||
|
||||
public long getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreated() {
|
||||
return this.created;
|
||||
}
|
||||
|
||||
public void setCreated(LocalDateTime created) {
|
||||
this.created = created;
|
||||
}
|
||||
|
||||
public LocalDateTime getModified() {
|
||||
return this.modified;
|
||||
}
|
||||
|
||||
public void setModified(LocalDateTime modified) {
|
||||
this.modified = modified;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return this.title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public @Nullable String getText() {
|
||||
return this.text;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
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 int getStarCount() {
|
||||
return this.starCount;
|
||||
}
|
||||
|
||||
public void setStarCount(int starCount) {
|
||||
this.starCount = starCount;
|
||||
}
|
||||
|
||||
public int getViewerCount() {
|
||||
return this.viewerCount;
|
||||
}
|
||||
|
||||
public void setViewerCount(int viewerCount) {
|
||||
this.viewerCount = viewerCount;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user