Skip to content
This repository has been archived by the owner on Jul 29, 2024. It is now read-only.

Commit

Permalink
[BE] feat: 카테고리 관련 오류 수정 (#273)
Browse files Browse the repository at this point in the history
* fix: 카테고리 이름 중복 문제 해결

* fix: '기본' 카테고리 이름 삭제 버그 수정 -> isDefault 필드 추가

'기본'이라는 이름의 카테고리를 기본으로 정의하여 '기본' 이름의 카테고리가 삭제되지 않았었다.

그래서 '기본'이라는 이름을 기본이라고 하지 않고, 기본인 필드값이 있을 경우 기본이라고 판단하는게 나아보여서 추가했다.

* fix: 카테고리 이름과 관련된 서비스 예외 처리 추가

카테고리 이름의 경우 대부분 유저에게 넘어오는 값이기 때문에 서비스 계층에서 예외를 검증해주었다.

* refactor: Basic 카테고리 이름 통일

* refactor: isBasic 필드 제거 및 리뷰 반영
  • Loading branch information
echo724 authored Aug 15, 2023
1 parent e79b244 commit 40b1c2d
Show file tree
Hide file tree
Showing 10 changed files with 209 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.donggle.backend.application.repository;

import org.donggle.backend.domain.category.Category;
import org.donggle.backend.domain.category.CategoryName;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
Expand All @@ -18,6 +19,8 @@ public interface CategoryRepository extends JpaRepository<Category, Long> {

Optional<Category> findFirstByMemberId(final Long memberId);

boolean existsByCategoryName(final CategoryName categoryName);

@Query("select c from Category c " +
"where c.nextCategory.id = :categoryId")
Optional<Category> findPreCategoryByCategoryId(@Param("categoryId") final Long categoryId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
import org.donggle.backend.domain.category.CategoryName;
import org.donggle.backend.domain.member.Member;
import org.donggle.backend.domain.writing.Writing;
import org.donggle.backend.exception.business.DuplicateCategoryNameException;
import org.donggle.backend.exception.business.EmptyCategoryNameException;
import org.donggle.backend.exception.business.InvalidBasicCategoryException;
import org.donggle.backend.exception.business.OverLengthCategoryNameException;
import org.donggle.backend.exception.notfound.CategoryNotFoundException;
import org.donggle.backend.exception.notfound.MemberNotFoundException;
import org.donggle.backend.ui.response.CategoryListResponse;
Expand Down Expand Up @@ -41,13 +44,27 @@ public class CategoryService {
public Long addCategory(final Long memberId, final CategoryAddRequest request) {
//TODO: member checking
final Member findMember = findMember(memberId);
final Category category = Category.of(new CategoryName(request.categoryName()), findMember);
final CategoryName categoryName = new CategoryName(request.categoryName());
validateCategoryName(categoryName);
final Category category = Category.of(categoryName, findMember);
final Category lastCategory = findLastCategoryByMemberId(memberId);
final Category savedCategory = categoryRepository.save(category);
lastCategory.changeNextCategory(savedCategory);
return savedCategory.getId();
}

private void validateCategoryName(final CategoryName categoryName) {
if (categoryRepository.existsByCategoryName(categoryName)) {
throw new DuplicateCategoryNameException(categoryName.getName());
}
if (categoryName.isBlank()) {
throw new EmptyCategoryNameException();
}
if (categoryName.isOverLength()) {
throw new OverLengthCategoryNameException();
}
}

@Transactional(readOnly = true)
public CategoryListResponse findAll(final Long memberId) {
//TODO: member checking
Expand Down Expand Up @@ -115,14 +132,18 @@ private List<Writing> sortWriting(final List<Writing> findWritings, Writing targ
public void modifyCategoryName(final Long memberId, final Long categoryId, final CategoryModifyRequest request) {
//TODO: member checking
final Category findCategory = findCategory(categoryId);
validateBasicCategory(findCategory);
findCategory.changeName(new CategoryName(request.categoryName()));
validateBasicCategory(memberId, findCategory);

final CategoryName categoryName = new CategoryName(request.categoryName());
validateCategoryName(categoryName);

findCategory.changeName(categoryName);
}

public void removeCategory(final Long memberId, final Long categoryId) {
//TODO: member checking
final Category findCategory = findCategory(categoryId);
validateBasicCategory(findCategory);
validateBasicCategory(memberId, findCategory);
transferToBasicCategory(memberId, findCategory);
deleteCategory(findCategory);
}
Expand Down Expand Up @@ -156,7 +177,7 @@ private void deleteCategory(final Category findCategory) {
public void modifyCategoryOrder(final Long memberId, final Long categoryId, final CategoryModifyRequest request) {
final Long nextCategoryId = request.nextCategoryId();
final Category source = findCategory(categoryId);
validateBasicCategory(source);
validateBasicCategory(memberId, source);
deleteCategoryOrder(source);
addCategoryOrder(nextCategoryId, source, memberId);
}
Expand All @@ -182,8 +203,10 @@ private void addCategoryOrder(final Long nextCategoryId, final Category category
}
}

private void validateBasicCategory(final Category category) {
if (category.isBasic()) {
private void validateBasicCategory(final Long memberId, final Category category) {
final Category basicCategory = categoryRepository.findFirstByMemberId(memberId)
.orElseThrow(IllegalStateException::new);
if (basicCategory.equals(category)) {
throw new InvalidBasicCategoryException(category.getId());
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package org.donggle.backend.application.service.request;

import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.NotBlank;

public record CategoryAddRequest(
@NotNull(message = "카테고리 이름을 입력해주세요.")
@NotBlank(message = "카테고리 이름을 입력해주세요.")
String categoryName
) {
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
package org.donggle.backend.application.service.request;

public record CategoryModifyRequest(String categoryName, Long nextCategoryId) {
public record CategoryModifyRequest(
String categoryName,
Long nextCategoryId) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,6 @@ public static Category of(final CategoryName categoryName, final Member member)
return new Category(categoryName, null, member);
}

public boolean isBasic() {
return this.categoryName.equals(BASIC_CATEGORY_NAME);
}

public String getCategoryNameValue() {
return categoryName.getName();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ public CategoryName(final String name) {
this.name = name;
}

public boolean isBlank() {
return name.isBlank();
}

public boolean isOverLength() {
return name.length() > 30;
}

@Override
public boolean equals(final Object o) {
if (this == o) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.donggle.backend.exception.business;

import org.springframework.http.HttpStatus;

public class DuplicateCategoryNameException extends BusinessException {
private static final String MESSAGE = "이미 존재하는 카테고리 이름입니다.";
private final String categoryName;

public DuplicateCategoryNameException(final String categoryName) {
super(MESSAGE);
this.categoryName = categoryName;
}

public DuplicateCategoryNameException(final String categoryName, final Throwable cause) {
super(MESSAGE, cause);
this.categoryName = categoryName;
}

@Override
public String getHint() {
return "이미 존재하는 카테고리 이름입니다. 입력한 이름: " + categoryName;
}

@Override
public int getErrorCode() {
return HttpStatus.BAD_REQUEST.value();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.donggle.backend.exception.business;

import org.springframework.http.HttpStatus;

public class EmptyCategoryNameException extends BusinessException {
private static final String MESSAGE = "카테고리 이름은 빈 값이 될 수 없습니다.";

public EmptyCategoryNameException() {
super(MESSAGE);
}

public EmptyCategoryNameException(final Throwable cause) {
super(MESSAGE, cause);
}

@Override
public String getHint() {
return "카테고리 이름은 빈 값이 될 수 없습니다.";
}

@Override
public int getErrorCode() {
return HttpStatus.BAD_REQUEST.value();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.donggle.backend.exception.business;

import org.springframework.http.HttpStatus;

public class OverLengthCategoryNameException extends BusinessException {
private static final String MESSAGE = "카테고리 이름은 30자를 넘을 수 없습니다.";

public OverLengthCategoryNameException() {
super(MESSAGE);
}

public OverLengthCategoryNameException(final Throwable cause) {
super(MESSAGE, cause);
}

@Override
public String getHint() {
return "카테고리 이름은 30자를 넘을 수 없습니다.";
}

@Override
public int getErrorCode() {
return HttpStatus.BAD_REQUEST.value();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
import org.donggle.backend.domain.category.Category;
import org.donggle.backend.domain.category.CategoryName;
import org.donggle.backend.domain.writing.Writing;
import org.donggle.backend.exception.business.DuplicateCategoryNameException;
import org.donggle.backend.exception.business.EmptyCategoryNameException;
import org.donggle.backend.exception.business.InvalidBasicCategoryException;
import org.donggle.backend.exception.business.OverLengthCategoryNameException;
import org.donggle.backend.ui.response.CategoryListResponse;
import org.donggle.backend.ui.response.CategoryResponse;
import org.donggle.backend.ui.response.CategoryWritingsResponse;
Expand Down Expand Up @@ -164,7 +167,7 @@ void findAllWritingsById() {
//given
//when
final CategoryWritingsResponse response = categoryService.findAllWritings(1L, 1L);
Writing findWriting = writingRepository.findById(1L).get();
final Writing findWriting = writingRepository.findById(1L).get();

//then
assertAll(
Expand Down Expand Up @@ -203,7 +206,7 @@ void modifyCategoryOrder() {
categoryService.modifyCategoryOrder(1L, thirdId, new CategoryModifyRequest(null, secondId));

//then
CategoryListResponse response = categoryService.findAll(1L);
final CategoryListResponse response = categoryService.findAll(1L);
assertAll(
() -> assertThat(response.categories()).hasSize(3),
() -> assertThat(response.categories()).containsExactly(
Expand All @@ -213,4 +216,84 @@ void modifyCategoryOrder() {
)
);
}

@Test
@DisplayName("카테고리 이름 중복 예외")
void duplicateCategoryName() {
//given
categoryService.addCategory(1L, new CategoryAddRequest("기본 카테고리"));

//when

//then
assertThatThrownBy(() -> categoryService.addCategory(1L, new CategoryAddRequest("기본 카테고리")))
.isInstanceOf(DuplicateCategoryNameException.class)
.hasMessage("이미 존재하는 카테고리 이름입니다.");
}

@Test
@DisplayName("카테고리 빈 이름 예외")
void emptyCategoryName() {
//given

//when

//then
assertThatThrownBy(() -> categoryService.addCategory(1L, new CategoryAddRequest("")))
.isInstanceOf(EmptyCategoryNameException.class)
.hasMessage("카테고리 이름은 빈 값이 될 수 없습니다.");
}

@Test
@DisplayName("카테고리 공백 이름 예외")
void blankCategoryName() {
//given

//when

//then
assertThatThrownBy(() -> categoryService.addCategory(1L, new CategoryAddRequest(" ")))
.isInstanceOf(EmptyCategoryNameException.class)
.hasMessage("카테고리 이름은 빈 값이 될 수 없습니다.");
}

@Test
@DisplayName("카테고리 이름 빈 이름 수정 예외")
void modifyCategoryNameWithEmptyName() {
//given
final Long secondId = categoryService.addCategory(1L, new CategoryAddRequest("두 번째 카테고리"));

//when

//then
assertThatThrownBy(() -> categoryService.modifyCategoryName(1L, secondId, new CategoryModifyRequest("", null)))
.isInstanceOf(EmptyCategoryNameException.class)
.hasMessage("카테고리 이름은 빈 값이 될 수 없습니다.");
}

@Test
@DisplayName("카테고리 긴 이름 예외")
void longCategoryName() {
//given

//when

//then
assertThatThrownBy(() -> categoryService.addCategory(1L, new CategoryAddRequest("123456789012345678901234567890123456789012345678901234567890")))
.isInstanceOf(OverLengthCategoryNameException.class)
.hasMessage("카테고리 이름은 30자를 넘을 수 없습니다.");
}

@Test
@DisplayName("기본 카테고리 삭제 예외")
void removeDefaultCategory() {
//given

//when

//then
assertThatThrownBy(() -> categoryService.removeCategory(1L, 1L))
.isInstanceOf(InvalidBasicCategoryException.class)
.hasMessage("기본 카테고리는 변경이 불가합니다.");
}
}

0 comments on commit 40b1c2d

Please sign in to comment.