MME-34 Add recipe star toggle endpoint, deprecate old star endpoints and service methods.
This commit is contained in:
parent
20865a1b5a
commit
a73dcd1c01
@ -7,18 +7,16 @@ import app.mealsmadeeasy.api.recipe.spec.RecipeCreateSpec;
|
|||||||
import app.mealsmadeeasy.api.user.User;
|
import app.mealsmadeeasy.api.user.User;
|
||||||
import app.mealsmadeeasy.api.user.UserCreateException;
|
import app.mealsmadeeasy.api.user.UserCreateException;
|
||||||
import app.mealsmadeeasy.api.user.UserService;
|
import app.mealsmadeeasy.api.user.UserService;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
@ExtendWith(PostgresTestsExtension.class)
|
@ExtendWith(PostgresTestsExtension.class)
|
||||||
@ -53,55 +51,39 @@ public class RecipeStarServiceTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void createViaUsernameAndSlug() {
|
public void whenToggleCreates_findReturnsPresent() {
|
||||||
final User owner = this.seedUser();
|
final User user = this.seedUser();
|
||||||
final User starer = this.seedUser();
|
final Recipe recipe = this.seedRecipe(user);
|
||||||
final Recipe recipe = this.seedRecipe(owner);
|
this.recipeStarService.toggle(recipe, user);
|
||||||
final RecipeStar star = assertDoesNotThrow(() -> this.recipeStarService.create(
|
assertThat(this.recipeStarService.find(recipe, user).isPresent(), is(true));
|
||||||
recipe.getOwner().getUsername(),
|
|
||||||
recipe.getSlug(),
|
|
||||||
starer
|
|
||||||
));
|
|
||||||
assertThat(star.getTimestamp(), is(notNullValue()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void createViaId() {
|
public void whenToggleDeletes_findReturnsEmpty() {
|
||||||
final User owner = this.seedUser();
|
final User user = this.seedUser();
|
||||||
final User starer = this.seedUser();
|
final Recipe recipe = this.seedRecipe(user);
|
||||||
final Recipe recipe = this.seedRecipe(owner);
|
this.recipeStarService.toggle(recipe, user); // create
|
||||||
final RecipeStar star = assertDoesNotThrow(() -> this.recipeStarService.create(
|
assertThat(this.recipeStarService.find(recipe, user).isPresent(), is(true));
|
||||||
recipe.getId(),
|
this.recipeStarService.toggle(recipe, user); // delete
|
||||||
starer.getId()
|
assertThat(this.recipeStarService.find(recipe, user).isEmpty(), is(true));
|
||||||
));
|
|
||||||
assertThat(star.getTimestamp(), is(notNullValue()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void find() {
|
public void whenNotStarred_toggleReturnsPresent() {
|
||||||
final User owner = this.seedUser();
|
final User user = this.seedUser();
|
||||||
final User starer = this.seedUser();
|
final Recipe recipe = this.seedRecipe(user);
|
||||||
final Recipe recipe = this.seedRecipe(owner);
|
final Optional<RecipeStar> maybeRecipeStar = this.recipeStarService.toggle(recipe, user);
|
||||||
this.recipeStarService.create(recipe.getId(), starer.getId());
|
assertThat(maybeRecipeStar.isPresent(), is(true));
|
||||||
final @Nullable RecipeStar star = this.recipeStarService.find(
|
|
||||||
recipe.getOwner().getUsername(),
|
|
||||||
recipe.getSlug(),
|
|
||||||
starer
|
|
||||||
).orElse(null);
|
|
||||||
assertThat(star, is(notNullValue()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void deleteViaUsernameAndSlug() {
|
public void whenStarred_toggleReturnsEmpty() {
|
||||||
final User owner = this.seedUser();
|
final User user = this.seedUser();
|
||||||
final User starer = this.seedUser();
|
final Recipe recipe = this.seedRecipe(user);
|
||||||
final Recipe recipe = this.seedRecipe(owner);
|
this.recipeStarService.toggle(recipe, user); // create
|
||||||
this.recipeStarService.create(recipe.getId(), starer.getId());
|
assertThat(this.recipeStarService.find(recipe, user).isPresent(), is(true)); // check that it's there
|
||||||
assertDoesNotThrow(() -> this.recipeStarService.delete(
|
final Optional<RecipeStar> maybeRecipeStar = this.recipeStarService.toggle(recipe, user); // get rid
|
||||||
recipe.getOwner().getUsername(),
|
assertThat(maybeRecipeStar.isEmpty(), is(true));
|
||||||
recipe.getSlug(),
|
|
||||||
starer
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,6 +31,7 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/recipes")
|
@RequestMapping("/recipes")
|
||||||
@ -141,6 +142,7 @@ public class RecipesController {
|
|||||||
return ResponseEntity.noContent().build();
|
return ResponseEntity.noContent().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
@PostMapping("/{username}/{slug}/star")
|
@PostMapping("/{username}/{slug}/star")
|
||||||
public ResponseEntity<RecipeStar> addStar(
|
public ResponseEntity<RecipeStar> addStar(
|
||||||
@PathVariable String username,
|
@PathVariable String username,
|
||||||
@ -150,6 +152,24 @@ public class RecipesController {
|
|||||||
return ResponseEntity.status(HttpStatus.CREATED).body(this.recipeStarService.create(username, slug, principal));
|
return ResponseEntity.status(HttpStatus.CREATED).body(this.recipeStarService.create(username, slug, principal));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{username}/{slug}/star/toggle")
|
||||||
|
public ResponseEntity<Object> toggleStar(
|
||||||
|
@PathVariable String username,
|
||||||
|
@PathVariable String slug,
|
||||||
|
@AuthenticationPrincipal User principal
|
||||||
|
) {
|
||||||
|
final Optional<RecipeStar> maybeStar = this.recipeStarService.toggle(
|
||||||
|
this.recipeService.getByUsernameAndSlug(username, slug, principal),
|
||||||
|
principal
|
||||||
|
);
|
||||||
|
if (maybeStar.isPresent()) {
|
||||||
|
return ResponseEntity.status(HttpStatus.CREATED).body(maybeStar.get());
|
||||||
|
} else {
|
||||||
|
return ResponseEntity.noContent().build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
@GetMapping("/{username}/{slug}/star")
|
@GetMapping("/{username}/{slug}/star")
|
||||||
public ResponseEntity<Map<String, Object>> getStar(
|
public ResponseEntity<Map<String, Object>> getStar(
|
||||||
@PathVariable String username,
|
@PathVariable String username,
|
||||||
@ -164,6 +184,7 @@ public class RecipesController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
@DeleteMapping("/{username}/{slug}/star")
|
@DeleteMapping("/{username}/{slug}/star")
|
||||||
public ResponseEntity<Object> removeStar(
|
public ResponseEntity<Object> removeStar(
|
||||||
@PathVariable String username,
|
@PathVariable String username,
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
package app.mealsmadeeasy.api.recipe.star;
|
package app.mealsmadeeasy.api.recipe.star;
|
||||||
|
|
||||||
|
import app.mealsmadeeasy.api.recipe.Recipe;
|
||||||
|
import app.mealsmadeeasy.api.user.User;
|
||||||
import jakarta.transaction.Transactional;
|
import jakarta.transaction.Transactional;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.data.jpa.repository.Query;
|
import org.springframework.data.jpa.repository.Query;
|
||||||
@ -9,6 +11,7 @@ import java.util.Optional;
|
|||||||
public interface RecipeStarRepository extends JpaRepository<RecipeStar, Long> {
|
public interface RecipeStarRepository extends JpaRepository<RecipeStar, Long> {
|
||||||
|
|
||||||
Optional<RecipeStar> findByRecipeIdAndOwnerId(Integer recipeId, Integer ownerId);
|
Optional<RecipeStar> findByRecipeIdAndOwnerId(Integer recipeId, Integer ownerId);
|
||||||
|
Optional<RecipeStar> findByRecipeAndOwner(Recipe recipe, User owner);
|
||||||
|
|
||||||
@Query("SELECT count(rs) > 0 FROM RecipeStar rs, Recipe r WHERE r.owner.username = ?1 AND r.slug = ?2 AND r.id = rs.recipe.id AND rs.owner.id = ?3")
|
@Query("SELECT count(rs) > 0 FROM RecipeStar rs, Recipe r WHERE r.owner.username = ?1 AND r.slug = ?2 AND r.id = rs.recipe.id AND rs.owner.id = ?3")
|
||||||
boolean isStarer(String ownerUsername, String slug, Integer viewerId);
|
boolean isStarer(String ownerUsername, String slug, Integer viewerId);
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import app.mealsmadeeasy.api.user.User;
|
|||||||
import app.mealsmadeeasy.api.user.UserRepository;
|
import app.mealsmadeeasy.api.user.UserRepository;
|
||||||
import app.mealsmadeeasy.api.util.NoSuchEntityWithIdException;
|
import app.mealsmadeeasy.api.util.NoSuchEntityWithIdException;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -20,6 +21,7 @@ public class RecipeStarService {
|
|||||||
private final RecipeRepository recipeRepository;
|
private final RecipeRepository recipeRepository;
|
||||||
private final RecipeService recipeService;
|
private final RecipeService recipeService;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public RecipeStar create(Recipe recipe, User owner) {
|
public RecipeStar create(Recipe recipe, User owner) {
|
||||||
final RecipeStar recipeStar = new RecipeStar();
|
final RecipeStar recipeStar = new RecipeStar();
|
||||||
recipeStar.setOwner(owner);
|
recipeStar.setOwner(owner);
|
||||||
@ -51,15 +53,35 @@ public class RecipeStarService {
|
|||||||
return existing.orElseGet(() -> this.create(recipe, starer));
|
return existing.orElseGet(() -> this.create(recipe, starer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("@recipeSecurity.isViewableBy(#recipe, #starer)")
|
||||||
|
public Optional<RecipeStar> toggle(Recipe recipe, User starer) {
|
||||||
|
final Optional<RecipeStar> existing = this.find(recipe, starer);
|
||||||
|
if (existing.isPresent()) {
|
||||||
|
this.recipeStarRepository.delete(existing.get());
|
||||||
|
return Optional.empty();
|
||||||
|
} else {
|
||||||
|
return Optional.of(this.create(recipe, starer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreAuthorize("@recipeSecurity.isViewableBy(#recipe, #starer)")
|
||||||
|
public Optional<RecipeStar> find(Recipe recipe, User starer) {
|
||||||
|
return this.recipeStarRepository.findByRecipeAndOwner(recipe, starer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
@PreAuthorize("@recipeSecurity.isViewableBy(#recipeOwnerUsername, #recipeSlug, #starer)")
|
||||||
public Optional<RecipeStar> find(String recipeOwnerUsername, String recipeSlug, User starer) {
|
public Optional<RecipeStar> find(String recipeOwnerUsername, String recipeSlug, User starer) {
|
||||||
final Recipe recipe = this.recipeService.getByUsernameAndSlug(recipeOwnerUsername, recipeSlug, starer);
|
final Recipe recipe = this.recipeService.getByUsernameAndSlug(recipeOwnerUsername, recipeSlug, starer);
|
||||||
return this.recipeStarRepository.findByRecipeIdAndOwnerId(recipe.getId(), starer.getId());
|
return this.recipeStarRepository.findByRecipeIdAndOwnerId(recipe.getId(), starer.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void delete(Integer recipeId, Integer ownerId) {
|
public void delete(Integer recipeId, Integer ownerId) {
|
||||||
this.recipeStarRepository.deleteByRecipeIdAndOwnerId(recipeId, ownerId);
|
this.recipeStarRepository.deleteByRecipeIdAndOwnerId(recipeId, ownerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void delete(String recipeOwnerUsername, String recipeSlug, User starer) {
|
public void delete(String recipeOwnerUsername, String recipeSlug, User starer) {
|
||||||
final Recipe recipe = this.recipeService.getByUsernameAndSlug(recipeOwnerUsername, recipeSlug, starer);
|
final Recipe recipe = this.recipeService.getByUsernameAndSlug(recipeOwnerUsername, recipeSlug, starer);
|
||||||
this.delete(recipe.getId(), starer.getId());
|
this.delete(recipe.getId(), starer.getId());
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user