Skip to content

Commit

Permalink
Merge pull request #165 from Media-XI/ART-186-be-카테고리-수정-api-이슈
Browse files Browse the repository at this point in the history
fix : 카테고리 수정 문제 해결
  • Loading branch information
haroya01 authored May 10, 2024
2 parents 9d703cf + 8a19e94 commit 7ee11e6
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public ResponseEntity deleteCategory(@PathVariable Long categoryId) {
return new ResponseEntity(HttpStatus.NO_CONTENT);
}

@PutMapping("/{categoryId}")
@PatchMapping("/{categoryId}")
@AdminOnly
public ResponseEntity updateCategory(@PathVariable Long categoryId, @RequestBody @Valid MagazineCategoryRequest.Update request) {
MagazineCategoryResponse.Get category = magazineCategoryService.updateCategory(categoryId, request);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.Where;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -62,7 +63,7 @@ public static MagazineCategory toEntity(String name, String slug, MagazineCatego
.parent(parent)
.build();

if(parent != null)
if (parent != null)
parent.getChildren().add(magazineCategory);

return magazineCategory;
Expand Down Expand Up @@ -90,17 +91,19 @@ public void checkDepth() {
}
}

public void update(MagazineCategoryRequest.Update request) {
public void update(MagazineCategoryRequest.Update request, MagazineCategory newParent) {
Optional.ofNullable(request.getName())
.ifPresent(name -> this.name = name);

Optional.ofNullable(request.getSlug())
.ifPresent(slug -> this.slug = slug);

this.changeParentCategory(newParent);

this.updatedTime = LocalDateTime.now();
}

public void changeParentCategory(MagazineCategory newParent) {
private void changeParentCategory(MagazineCategory newParent) {
if (this.parent != null) {
this.parent.getChildren().remove(this);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,8 @@ public interface MagazineCategoryRepository extends JpaRepository<MagazineCatego
boolean existsBySlug(String slug);

Optional<MagazineCategory> findBySlug(String slug);

boolean existsByNameAndParentAndIdNot(String name, MagazineCategory parentCategory, Long id);

boolean existsBySlugAndIdNot(String slug, Long id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.example.codebase.domain.magazine.entity.MagazineCategory;
import com.example.codebase.domain.magazine.repository.MagazineCategoryRepository;
import com.example.codebase.exception.NotFoundException;
import io.micrometer.common.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand Down Expand Up @@ -35,6 +36,7 @@ public MagazineCategoryResponse.Create createCategory(MagazineCategoryRequest.Cr
return MagazineCategoryResponse.Create.from(category);
}

@Nullable
private MagazineCategory findParentCategory(Long parentId) throws NotFoundException {
if (parentId == null) {
return null;
Expand Down Expand Up @@ -90,26 +92,33 @@ public MagazineCategoryResponse.Get updateCategory(Long categoryId, MagazineCate

MagazineCategory parentCategory = findParentCategory(request.getParentId());

if (parentCategory != null) {
parentCategory.checkDepth();
}

checkCategoryExists(request, parentCategory);
category.changeParentCategory(parentCategory);
validateParentCategory(category, parentCategory);
checkCategoryExists(request, category, parentCategory);

category.update(request);
category.update(request, parentCategory);
magazineCategoryRepository.save(category);
return MagazineCategoryResponse.Get.from(category);
}

private void checkCategoryExists(MagazineCategoryRequest.Update request, MagazineCategory parentCategory) {
boolean exists = magazineCategoryRepository.existsByNameAndParent(request.getName(), parentCategory);
private void validateParentCategory(MagazineCategory category, MagazineCategory parentCategory) {
if (parentCategory != null) {
if (parentCategory.equals(category)) {
throw new RuntimeException("부모 카테고리를 해당 카테고리로 설정할 수 없습니다.");
}

parentCategory.checkDepth();
}
}

private void checkCategoryExists(MagazineCategoryRequest.Update request, MagazineCategory category, MagazineCategory parentCategory) {
boolean exists = magazineCategoryRepository.existsByNameAndParentAndIdNot(request.getName(), parentCategory, category.getId());
if (exists) {
throw new RuntimeException("해당 부모 카테고리 산하 이름이 같은 카테고리가 존재합니다.");
throw new RuntimeException("해당 부모 카테고리 산하에 같은 이름을 가진 다른 카테고리가 존재합니다.");
}
boolean existsSlug = magazineCategoryRepository.existsBySlug(request.getSlug());
boolean existsSlug = magazineCategoryRepository.existsBySlugAndIdNot(request.getSlug(), category.getId());
if (existsSlug) {
throw new RuntimeException("슬러그가 중복되는 카테고리가 존재합니다.");
throw new RuntimeException("슬러그가 중복되는 다른 카테고리가 존재합니다.");
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import static org.junit.jupiter.api.Assertions.*;
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

Expand Down Expand Up @@ -259,7 +260,7 @@ public void updateCategory() throws Exception {

// when
String response = mockMvc.perform(
put("/api/magazine-category/" + childCategory.getId())
patch("/api/magazine-category/" + childCategory.getId())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(updateRequest))
)
Expand Down Expand Up @@ -329,7 +330,7 @@ public void updateCategory() throws Exception {

// when
mockMvc.perform(
put("/api/magazine-category/" + updateCategoryBefore.getId())
patch("/api/magazine-category/" + updateCategoryBefore.getId())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(updateRequest))
)
Expand Down Expand Up @@ -365,7 +366,7 @@ public void updateCategory() throws Exception {
@Test
public void 슬러그가_같은_카테고리_수정시_중복() throws Exception {
// given
MagazineCategoryResponse.Create existingCategory = magazineCategoryService.createCategory(
magazineCategoryService.createCategory(
new MagazineCategoryRequest.Create("비교카테고리", "category", null)
);

Expand All @@ -377,13 +378,13 @@ public void updateCategory() throws Exception {

// when
mockMvc.perform(
put("/api/magazine-category/" + updateCategoryBefore.getId())
patch("/api/magazine-category/" + updateCategoryBefore.getId())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(updateRequest))
)
.andDo(print())
.andExpect(status().isBadRequest())
.andExpect(result -> assertEquals("슬러그가 중복되는 카테고리가 존재합니다.", result.getResolvedException().getMessage()));
.andExpect(result -> assertEquals("슬러그가 중복되는 다른 카테고리가 존재합니다.", result.getResolvedException().getMessage()));
}

@WithMockCustomUser(username = "admin", role = "ADMIN")
Expand Down Expand Up @@ -451,13 +452,13 @@ public void updateCategory() throws Exception {

// when
mockMvc.perform(
put("/api/magazine-category/" + changeCategory.getId())
patch("/api/magazine-category/" + changeCategory.getId())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(updateRequest))
)
.andDo(print())
.andExpect(status().isBadRequest())
.andExpect(result -> assertEquals("해당 부모 카테고리 산하 이름이 같은 카테고리가 존재합니다.", result.getResolvedException().getMessage()));
.andExpect(result -> assertEquals("해당 부모 카테고리 산하에 같은 이름을 가진 다른 카테고리가 존재합니다.", result.getResolvedException().getMessage()));
}

@WithMockCustomUser(username = "admin", role = "ADMIN")
Expand All @@ -480,6 +481,85 @@ public void updateCategory() throws Exception {
.andExpect(result -> assertEquals("해당 카테고리에 속한 매거진이 존재합니다.", result.getResolvedException().getMessage()));
}

@WithMockCustomUser(username = "admin", role = "ADMIN")
@DisplayName("매거진 카테고리를 수정시 자기 자신을 부모 카테고리로 둘수 없다.")
@Test
public void updateCategoryParentIsNotMe() throws Exception {
// given
MagazineCategory parentCategoryBefore = createCategoryAndLoad();

// 부모 카테고리를 자기 자신을 참조하도록 변경
MagazineCategoryResponse.Create childCategory = magazineCategoryService.createCategory(
new MagazineCategoryRequest.Create("수정된카테고리", "changeCategory", parentCategoryBefore.getId())
);

MagazineCategoryRequest.Update updateRequest = new MagazineCategoryRequest.Update("수정된 글", "updated-word", childCategory.getId());

// when
mockMvc.perform(
patch("/api/magazine-category/" + childCategory.getId())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(updateRequest))
)
.andDo(print())
.andExpect(status().isBadRequest())
// then
.andExpect(result -> assertEquals("부모 카테고리를 해당 카테고리로 설정할 수 없습니다.", result.getResolvedException().getMessage()));

}

@WithMockCustomUser(username = "admin", role = "ADMIN")
@DisplayName("매거진 카테고리를 수정시 자기 자신의 슬러그 중복은 제외한다")
@Test
public void updateCategorySameSlug() throws Exception {
// given
MagazineCategoryResponse.Create category = magazineCategoryService.createCategory(
new MagazineCategoryRequest.Create("카테고리", "category", null));

MagazineCategoryRequest.Update updateRequest = new MagazineCategoryRequest.Update("수정된 글", "category", null);

// when
String response = mockMvc.perform(
patch("/api/magazine-category/" + category.getId())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(updateRequest))
)
.andDo(print())
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(StandardCharsets.UTF_8);

// then
MagazineCategoryResponse.Get updatedCategory = objectMapper.readValue(response, MagazineCategoryResponse.Get.class);
assertEquals(updateRequest.getName(), updatedCategory.getName());
assertEquals(updateRequest.getSlug(), updatedCategory.getSlug());
assertEquals(updateRequest.getParentId(), updatedCategory.getParentCategory());
}

@WithMockCustomUser(username = "admin", role = "ADMIN")
@DisplayName("매거진 카테고리를 수정시 자기 자신의 이름 중복은 제외한다")
@Test
public void updateCategorySameName() throws Exception {
// given
MagazineCategoryResponse.Create category = magazineCategoryService.createCategory(
new MagazineCategoryRequest.Create("카테고리", "category", null));

MagazineCategoryRequest.Update updateRequest = new MagazineCategoryRequest.Update("카테고리", "change-category", null);

// when
String response = mockMvc.perform(
patch("/api/magazine-category/" + category.getId())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(updateRequest))
)
.andDo(print())
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString(StandardCharsets.UTF_8);

// then
MagazineCategoryResponse.Get updatedCategory = objectMapper.readValue(response, MagazineCategoryResponse.Get.class);
assertEquals(updateRequest.getName(), updatedCategory.getName());
assertEquals(updateRequest.getSlug(), updatedCategory.getSlug());
assertEquals(updateRequest.getParentId(), updatedCategory.getParentCategory());
}
}

0 comments on commit 7ee11e6

Please sign in to comment.