Added data about principal's relation to FullRecipeView and related implementation.
This commit is contained in:
parent
862d30fae9
commit
84596865dd
@ -79,21 +79,23 @@ public class RecipeControllerTests {
|
|||||||
get("/recipes/{username}/{slug}", recipe.getOwner().getUsername(), recipe.getSlug())
|
get("/recipes/{username}/{slug}", recipe.getOwner().getUsername(), recipe.getSlug())
|
||||||
)
|
)
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("$.id").value(1))
|
.andExpect(jsonPath("$.recipe.id").value(1))
|
||||||
.andExpect(jsonPath("$.created").exists()) // TODO: better matching of exact LocalDateTime
|
.andExpect(jsonPath("$.recipe.created").exists()) // TODO: better matching of exact LocalDateTime
|
||||||
.andExpect(jsonPath("$.modified").doesNotExist())
|
.andExpect(jsonPath("$.recipe.modified").doesNotExist())
|
||||||
.andExpect(jsonPath("$.slug").value(recipe.getSlug()))
|
.andExpect(jsonPath("$.recipe.slug").value(recipe.getSlug()))
|
||||||
.andExpect(jsonPath("$.title").value("Test Recipe"))
|
.andExpect(jsonPath("$.recipe.title").value("Test Recipe"))
|
||||||
.andExpect(jsonPath("$.preparationTime").value(recipe.getPreparationTime()))
|
.andExpect(jsonPath("$.recipe.preparationTime").value(recipe.getPreparationTime()))
|
||||||
.andExpect(jsonPath("$.cookingTime").value(recipe.getCookingTime()))
|
.andExpect(jsonPath("$.recipe.cookingTime").value(recipe.getCookingTime()))
|
||||||
.andExpect(jsonPath("$.totalTime").value(recipe.getTotalTime()))
|
.andExpect(jsonPath("$.recipe.totalTime").value(recipe.getTotalTime()))
|
||||||
.andExpect(jsonPath("$.text").value("<h1>Hello, World!</h1>"))
|
.andExpect(jsonPath("$.recipe.text").value("<h1>Hello, World!</h1>"))
|
||||||
.andExpect(jsonPath("$.owner.id").value(owner.getId()))
|
.andExpect(jsonPath("$.recipe.owner.id").value(owner.getId()))
|
||||||
.andExpect(jsonPath("$.owner.username").value(owner.getUsername()))
|
.andExpect(jsonPath("$.recipe.owner.username").value(owner.getUsername()))
|
||||||
.andExpect(jsonPath("$.starCount").value(0))
|
.andExpect(jsonPath("$.recipe.starCount").value(0))
|
||||||
|
.andExpect(jsonPath("$.recipe.viewerCount").value(0))
|
||||||
|
.andExpect(jsonPath("$.recipe.isPublic").value(true))
|
||||||
.andExpect(jsonPath("$.isStarred").value(nullValue()))
|
.andExpect(jsonPath("$.isStarred").value(nullValue()))
|
||||||
.andExpect(jsonPath("$.viewerCount").value(0))
|
.andExpect(jsonPath("$.isOwner").value(nullValue()));
|
||||||
.andExpect(jsonPath("$.isPublic").value(true));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -4,7 +4,6 @@ import app.mealsmadeeasy.api.recipe.spec.RecipeCreateSpec;
|
|||||||
import app.mealsmadeeasy.api.recipe.spec.RecipeUpdateSpec;
|
import app.mealsmadeeasy.api.recipe.spec.RecipeUpdateSpec;
|
||||||
import app.mealsmadeeasy.api.recipe.star.RecipeStar;
|
import app.mealsmadeeasy.api.recipe.star.RecipeStar;
|
||||||
import app.mealsmadeeasy.api.recipe.star.RecipeStarService;
|
import app.mealsmadeeasy.api.recipe.star.RecipeStarService;
|
||||||
import app.mealsmadeeasy.api.recipe.view.FullRecipeView;
|
|
||||||
import app.mealsmadeeasy.api.recipe.view.RecipeInfoView;
|
import app.mealsmadeeasy.api.recipe.view.RecipeInfoView;
|
||||||
import app.mealsmadeeasy.api.user.User;
|
import app.mealsmadeeasy.api.user.User;
|
||||||
import app.mealsmadeeasy.api.user.UserEntity;
|
import app.mealsmadeeasy.api.user.UserEntity;
|
||||||
@ -24,7 +23,6 @@ import static app.mealsmadeeasy.api.recipe.ContainsRecipeInfoViewsForRecipesMatc
|
|||||||
import static app.mealsmadeeasy.api.recipe.ContainsRecipesMatcher.containsRecipes;
|
import static app.mealsmadeeasy.api.recipe.ContainsRecipesMatcher.containsRecipes;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.hamcrest.Matchers.nullValue;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
@ -352,44 +350,4 @@ public class RecipeServiceTests {
|
|||||||
assertThrows(AccessDeniedException.class, () -> this.recipeService.deleteRecipe(toDelete.getId(), notOwner));
|
assertThrows(AccessDeniedException.class, () -> this.recipeService.deleteRecipe(toDelete.getId(), notOwner));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
@DirtiesContext
|
|
||||||
public void getFullViewByUsernameAndSlugIncludesStarredFalseWhenViewerNotNullButNotStarer() throws RecipeException {
|
|
||||||
final User owner = this.createTestUser("recipeOwner");
|
|
||||||
final Recipe recipe = this.createTestRecipe(owner);
|
|
||||||
final FullRecipeView view = this.recipeService.getFullViewByUsernameAndSlug(
|
|
||||||
owner.getUsername(),
|
|
||||||
recipe.getSlug(),
|
|
||||||
owner
|
|
||||||
);
|
|
||||||
assertThat(view.getIsStarred(), is(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@DirtiesContext
|
|
||||||
public void getFullViewByUsernameAndSlugIncludesStarredTrueWhenViewerNotNullAndStarer() throws RecipeException {
|
|
||||||
final User owner = this.createTestUser("recipeOwner");
|
|
||||||
final Recipe recipe = this.createTestRecipe(owner);
|
|
||||||
this.recipeStarService.create(recipe.getId(), owner.getUsername());
|
|
||||||
final FullRecipeView view = this.recipeService.getFullViewByUsernameAndSlug(
|
|
||||||
owner.getUsername(),
|
|
||||||
recipe.getSlug(),
|
|
||||||
owner
|
|
||||||
);
|
|
||||||
assertThat(view.getIsStarred(), is(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@DirtiesContext
|
|
||||||
public void getFullViewByUsernameIncludesStarredNullWhenViewerNull() throws RecipeException {
|
|
||||||
final User owner = this.createTestUser("recipeOwner");
|
|
||||||
final Recipe recipe = this.createTestRecipe(owner, true);
|
|
||||||
final FullRecipeView view = this.recipeService.getFullViewByUsernameAndSlug(
|
|
||||||
owner.getUsername(),
|
|
||||||
recipe.getSlug(),
|
|
||||||
null
|
|
||||||
);
|
|
||||||
assertThat(view.getIsStarred(), is(nullValue()));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,14 @@ public class RecipeStarRepositoryTests {
|
|||||||
starDraft.setId(starId);
|
starDraft.setId(starId);
|
||||||
this.recipeStarRepository.save(starDraft);
|
this.recipeStarRepository.save(starDraft);
|
||||||
|
|
||||||
assertThat(this.recipeStarRepository.isStarer(recipe.getId(), owner.getUsername()), is(true));
|
assertThat(
|
||||||
|
this.recipeStarRepository.isStarer(
|
||||||
|
recipe.getOwner().getUsername(),
|
||||||
|
recipe.getSlug(),
|
||||||
|
owner.getUsername()
|
||||||
|
),
|
||||||
|
is(true)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -65,7 +72,14 @@ public class RecipeStarRepositoryTests {
|
|||||||
public void returnsFalseIfNotStarer() {
|
public void returnsFalseIfNotStarer() {
|
||||||
final UserEntity owner = this.getOwnerUser();
|
final UserEntity owner = this.getOwnerUser();
|
||||||
final RecipeEntity recipe = this.getTestRecipe(owner);
|
final RecipeEntity recipe = this.getTestRecipe(owner);
|
||||||
assertThat(this.recipeStarRepository.isStarer(recipe.getId(), owner.getUsername()), is(false));
|
assertThat(
|
||||||
|
this.recipeStarRepository.isStarer(
|
||||||
|
recipe.getOwner().getUsername(),
|
||||||
|
recipe.getSlug(),
|
||||||
|
owner.getUsername()
|
||||||
|
),
|
||||||
|
is(false)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -43,13 +43,17 @@ public class RecipeController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{username}/{slug}")
|
@GetMapping("/{username}/{slug}")
|
||||||
public ResponseEntity<FullRecipeView> getById(
|
public ResponseEntity<Map<String, Object>> getByUsernameAndSlug(
|
||||||
@PathVariable String username,
|
@PathVariable String username,
|
||||||
@PathVariable String slug,
|
@PathVariable String slug,
|
||||||
@AuthenticationPrincipal User viewer
|
@AuthenticationPrincipal User viewer
|
||||||
)
|
) throws RecipeException {
|
||||||
throws RecipeException {
|
final FullRecipeView recipe = this.recipeService.getFullViewByUsernameAndSlug(username, slug, viewer);
|
||||||
return ResponseEntity.ok(this.recipeService.getFullViewByUsernameAndSlug(username, slug, viewer));
|
final Map<String, Object> body = new HashMap<>();
|
||||||
|
body.put("recipe", recipe);
|
||||||
|
body.put("isStarred", this.recipeService.isStarer(username, slug, viewer));
|
||||||
|
body.put("isOwner", this.recipeService.isOwner(username, slug, viewer));
|
||||||
|
return ResponseEntity.ok(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
|
@ -5,6 +5,7 @@ import app.mealsmadeeasy.api.recipe.spec.RecipeUpdateSpec;
|
|||||||
import app.mealsmadeeasy.api.recipe.view.FullRecipeView;
|
import app.mealsmadeeasy.api.recipe.view.FullRecipeView;
|
||||||
import app.mealsmadeeasy.api.recipe.view.RecipeInfoView;
|
import app.mealsmadeeasy.api.recipe.view.RecipeInfoView;
|
||||||
import app.mealsmadeeasy.api.user.User;
|
import app.mealsmadeeasy.api.user.User;
|
||||||
|
import org.jetbrains.annotations.Contract;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.domain.Slice;
|
import org.springframework.data.domain.Slice;
|
||||||
@ -36,4 +37,10 @@ public interface RecipeService {
|
|||||||
|
|
||||||
void deleteRecipe(long id, User modifier);
|
void deleteRecipe(long id, User modifier);
|
||||||
|
|
||||||
|
@Contract("_, _, null -> null")
|
||||||
|
@Nullable Boolean isStarer(String username, String slug, @Nullable User viewer);
|
||||||
|
|
||||||
|
@Contract("_, _, null -> null")
|
||||||
|
@Nullable Boolean isOwner(String username, String slug, @Nullable User viewer);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -130,9 +130,6 @@ public class RecipeServiceImpl implements RecipeService {
|
|||||||
recipe,
|
recipe,
|
||||||
this.getRenderedMarkdown(recipe),
|
this.getRenderedMarkdown(recipe),
|
||||||
this.getStarCount(recipe),
|
this.getStarCount(recipe),
|
||||||
viewer != null
|
|
||||||
? this.recipeStarRepository.isStarer(recipe.getId(), viewer.getUsername())
|
|
||||||
: null,
|
|
||||||
this.getViewerCount(recipe.getId()),
|
this.getViewerCount(recipe.getId()),
|
||||||
this.getImageView(recipe.getMainImage(), viewer)
|
this.getImageView(recipe.getMainImage(), viewer)
|
||||||
);
|
);
|
||||||
@ -274,4 +271,24 @@ public class RecipeServiceImpl implements RecipeService {
|
|||||||
this.recipeRepository.deleteById(id);
|
this.recipeRepository.deleteById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@PreAuthorize("@recipeSecurity.isViewableBy(#username, #slug, #viewer)")
|
||||||
|
@Contract("_, _, null -> null")
|
||||||
|
public @Nullable Boolean isStarer(String username, String slug, @Nullable User viewer) {
|
||||||
|
if (viewer == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return this.recipeStarRepository.isStarer(username, slug, viewer.getUsername());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@PreAuthorize("@recipeSecurity.isViewableBy(#username, #slug, #viewer)")
|
||||||
|
@Contract("_, _, null -> null")
|
||||||
|
public @Nullable Boolean isOwner(String username, String slug, @Nullable User viewer) {
|
||||||
|
if (viewer == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return viewer.getUsername().equals(username);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,8 @@ public interface RecipeStarRepository extends JpaRepository<RecipeStarEntity, Lo
|
|||||||
@Query("SELECT star FROM RecipeStar star WHERE star.id.recipeId = ?1 AND star.id.ownerUsername = ?2")
|
@Query("SELECT star FROM RecipeStar star WHERE star.id.recipeId = ?1 AND star.id.ownerUsername = ?2")
|
||||||
Optional<RecipeStarEntity> findByRecipeIdAndOwnerUsername(Long recipeId, String username);
|
Optional<RecipeStarEntity> findByRecipeIdAndOwnerUsername(Long recipeId, String username);
|
||||||
|
|
||||||
@Query("SELECT count(rs) > 0 FROM RecipeStar rs WHERE rs.id.recipeId = ?1 AND rs.id.ownerUsername = ?2")
|
@Query("SELECT count(rs) > 0 FROM RecipeStar rs, Recipe r WHERE r.owner.username = ?1 AND r.slug = ?2 AND r.id = rs.id.recipeId AND rs.id.ownerUsername = ?3")
|
||||||
boolean isStarer(long recipeId, String username);
|
boolean isStarer(String ownerUsername, String slug, String viewerUsername);
|
||||||
|
|
||||||
@Modifying
|
@Modifying
|
||||||
@Transactional
|
@Transactional
|
||||||
|
@ -13,7 +13,6 @@ public class FullRecipeView {
|
|||||||
Recipe recipe,
|
Recipe recipe,
|
||||||
String renderedText,
|
String renderedText,
|
||||||
int starCount,
|
int starCount,
|
||||||
Boolean starred,
|
|
||||||
int viewerCount,
|
int viewerCount,
|
||||||
ImageView mainImage
|
ImageView mainImage
|
||||||
) {
|
) {
|
||||||
@ -29,7 +28,6 @@ public class FullRecipeView {
|
|||||||
view.setText(renderedText);
|
view.setText(renderedText);
|
||||||
view.setOwner(UserInfoView.from(recipe.getOwner()));
|
view.setOwner(UserInfoView.from(recipe.getOwner()));
|
||||||
view.setStarCount(starCount);
|
view.setStarCount(starCount);
|
||||||
view.setIsStarred(starred);
|
|
||||||
view.setViewerCount(viewerCount);
|
view.setViewerCount(viewerCount);
|
||||||
view.setMainImage(mainImage);
|
view.setMainImage(mainImage);
|
||||||
view.setIsPublic(recipe.isPublic());
|
view.setIsPublic(recipe.isPublic());
|
||||||
@ -47,7 +45,6 @@ public class FullRecipeView {
|
|||||||
private String text;
|
private String text;
|
||||||
private UserInfoView owner;
|
private UserInfoView owner;
|
||||||
private int starCount;
|
private int starCount;
|
||||||
private @Nullable Boolean starred;
|
|
||||||
private int viewerCount;
|
private int viewerCount;
|
||||||
private ImageView mainImage;
|
private ImageView mainImage;
|
||||||
private boolean isPublic;
|
private boolean isPublic;
|
||||||
@ -140,14 +137,6 @@ public class FullRecipeView {
|
|||||||
this.starCount = starCount;
|
this.starCount = starCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable Boolean getIsStarred() {
|
|
||||||
return this.starred;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIsStarred(@Nullable Boolean starred) {
|
|
||||||
this.starred = starred;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getViewerCount() {
|
public int getViewerCount() {
|
||||||
return this.viewerCount;
|
return this.viewerCount;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user