diff --git a/src/integrationTest/java/app/mealsmadeeasy/api/recipe/RecipeControllerTests.java b/src/integrationTest/java/app/mealsmadeeasy/api/recipe/RecipeControllerTests.java index 05bef73..1039e57 100644 --- a/src/integrationTest/java/app/mealsmadeeasy/api/recipe/RecipeControllerTests.java +++ b/src/integrationTest/java/app/mealsmadeeasy/api/recipe/RecipeControllerTests.java @@ -2,7 +2,9 @@ package app.mealsmadeeasy.api.recipe; import app.mealsmadeeasy.api.auth.AuthService; import app.mealsmadeeasy.api.auth.LoginDetails; +import app.mealsmadeeasy.api.auth.LoginException; import app.mealsmadeeasy.api.recipe.spec.RecipeCreateSpec; +import app.mealsmadeeasy.api.recipe.star.RecipeStarService; import app.mealsmadeeasy.api.user.User; import app.mealsmadeeasy.api.user.UserCreateException; import app.mealsmadeeasy.api.user.UserService; @@ -14,8 +16,7 @@ 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.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -29,6 +30,9 @@ public class RecipeControllerTests { @Autowired private RecipeService recipeService; + @Autowired + private RecipeStarService recipeStarService; + @Autowired private UserService userService; @@ -59,6 +63,12 @@ public class RecipeControllerTests { return this.createTestRecipe(owner, isPublic, "test-recipe"); } + private String getAccessToken(User user) throws LoginException { + return this.authService.login(user.getUsername(), "test") + .getAccessToken() + .getToken(); + } + @Test @DirtiesContext public void getRecipePageViewByIdPublicRecipeNoPrincipal() throws Exception { @@ -132,15 +142,26 @@ public class RecipeControllerTests { final User owner = this.createTestUser("recipe-owner"); final User starer = this.createTestUser("recipe-starer"); final Recipe recipe = this.createTestRecipe(owner, true); - final String accessToken = this.authService.login(starer.getUsername(), "test") - .getAccessToken() - .getToken(); this.mockMvc.perform( post("/recipes/{username}/{slug}/stars", recipe.getOwner().getUsername(), recipe.getSlug()) - .header("Authorization", "Bearer " + accessToken) + .header("Authorization", "Bearer " + this.getAccessToken(starer)) ) .andExpect(status().isCreated()) .andExpect(jsonPath("$.date").exists()); } + @Test + @DirtiesContext + public void deleteStarFromRecipe() throws Exception { + final User owner = this.createTestUser("recipe-owner"); + final User starer = this.createTestUser("recipe-starer"); + final Recipe recipe = this.createTestRecipe(owner, true); + this.recipeStarService.create(recipe.getId(), starer.getUsername()); + this.mockMvc.perform( + delete("/recipes/{username}/{slug}/stars", recipe.getOwner().getUsername(), recipe.getSlug()) + .header("Authorization", "Bearer " + this.getAccessToken(starer)) + ) + .andExpect(status().isNoContent()); + } + } diff --git a/src/integrationTest/java/app/mealsmadeeasy/api/recipe/star/RecipeStarServiceTests.java b/src/integrationTest/java/app/mealsmadeeasy/api/recipe/star/RecipeStarServiceTests.java index 70d3a64..77513be 100644 --- a/src/integrationTest/java/app/mealsmadeeasy/api/recipe/star/RecipeStarServiceTests.java +++ b/src/integrationTest/java/app/mealsmadeeasy/api/recipe/star/RecipeStarServiceTests.java @@ -72,4 +72,18 @@ public class RecipeStarServiceTests { assertThat(star.getDate(), is(notNullValue())); } + @Test + @DirtiesContext + public void deleteViaUsernameAndSlug() { + final User owner = this.getTestUser("recipe-owner"); + final User starer = this.getTestUser("recipe-starer"); + final Recipe recipe = this.getTestRecipe(owner, "test-recipe", true); + this.recipeStarService.create(recipe.getId(), starer.getUsername()); + assertDoesNotThrow(() -> this.recipeStarService.delete( + recipe.getOwner().getUsername(), + recipe.getSlug(), + starer + )); + } + } diff --git a/src/main/java/app/mealsmadeeasy/api/recipe/RecipeController.java b/src/main/java/app/mealsmadeeasy/api/recipe/RecipeController.java index caa4f6e..5bf3770 100644 --- a/src/main/java/app/mealsmadeeasy/api/recipe/RecipeController.java +++ b/src/main/java/app/mealsmadeeasy/api/recipe/RecipeController.java @@ -74,4 +74,14 @@ public class RecipeController { return ResponseEntity.status(HttpStatus.CREATED).body(this.recipeStarService.create(username, slug, principal)); } + @DeleteMapping("/{username}/{slug}/stars") + public ResponseEntity removeStar( + @PathVariable String username, + @PathVariable String slug, + @AuthenticationPrincipal User principal + ) throws RecipeException { + this.recipeStarService.delete(username, slug, principal); + return ResponseEntity.noContent().build(); + } + } diff --git a/src/main/java/app/mealsmadeeasy/api/recipe/star/RecipeStarRepository.java b/src/main/java/app/mealsmadeeasy/api/recipe/star/RecipeStarRepository.java index e699be8..884cad1 100644 --- a/src/main/java/app/mealsmadeeasy/api/recipe/star/RecipeStarRepository.java +++ b/src/main/java/app/mealsmadeeasy/api/recipe/star/RecipeStarRepository.java @@ -1,6 +1,8 @@ package app.mealsmadeeasy.api.recipe.star; +import jakarta.transaction.Transactional; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import java.util.Optional; @@ -10,6 +12,8 @@ public interface RecipeStarRepository extends JpaRepository findByRecipeIdAndOwnerUsername(Long recipeId, String username); + @Modifying + @Transactional @Query("DELETE FROM RecipeStar star WHERE star.id.recipeId = ?1 AND star.id.ownerUsername = ?2") void deleteByRecipeIdAndOwnerUsername(Long recipeId, String username); diff --git a/src/main/java/app/mealsmadeeasy/api/recipe/star/RecipeStarService.java b/src/main/java/app/mealsmadeeasy/api/recipe/star/RecipeStarService.java index a7a7afc..bf04e54 100644 --- a/src/main/java/app/mealsmadeeasy/api/recipe/star/RecipeStarService.java +++ b/src/main/java/app/mealsmadeeasy/api/recipe/star/RecipeStarService.java @@ -8,4 +8,5 @@ public interface RecipeStarService { RecipeStar create(String recipeOwnerUsername, String recipeSlug, User starer) throws RecipeException; RecipeStar get(long recipeId, String ownerUsername) throws RecipeException; void delete(long recipeId, String ownerUsername); + void delete(String recipeOwnerUsername, String recipeSlug, User starer) throws RecipeException; } diff --git a/src/main/java/app/mealsmadeeasy/api/recipe/star/RecipeStarServiceImpl.java b/src/main/java/app/mealsmadeeasy/api/recipe/star/RecipeStarServiceImpl.java index f7d4931..bdbe84a 100644 --- a/src/main/java/app/mealsmadeeasy/api/recipe/star/RecipeStarServiceImpl.java +++ b/src/main/java/app/mealsmadeeasy/api/recipe/star/RecipeStarServiceImpl.java @@ -59,4 +59,10 @@ public class RecipeStarServiceImpl implements RecipeStarService { this.recipeStarRepository.deleteByRecipeIdAndOwnerUsername(recipeId, ownerUsername); } + @Override + public void delete(String recipeOwnerUsername, String recipeSlug, User starer) throws RecipeException { + final Recipe recipe = this.recipeService.getByUsernameAndSlug(recipeOwnerUsername, recipeSlug, starer); + this.delete(recipe.getId(), starer.getUsername()); + } + }