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

Commit

Permalink
[BE] feat: 글 순서 및 카테고리 순서 수정 기능 구현 (#158)
Browse files Browse the repository at this point in the history
* feat: 글을 업로드 할 때 순서 처리 로직 추가
- Writing 엔티티에 순서를 나타내기 위한 nextWriting 필드 추가
- 글 업로드 시 해당 카테고리의 제일 마지막으로 업로드 되는 로직 구현

* feat: 글 순서 재정렬 기능 구현

* refactor: 리팩토링
- Response, Request DTO 정적 팩토리 메서드 추가
- WritingService, CategoryService 메서드 분리

* feat: 카테고리 순서 수정 기능 구현

* refactor: 메서드 분리 및 코드 컨벤션 적용

---------

Co-authored-by: ezzanzzan <[email protected]>
  • Loading branch information
HubCreator and ezzanzzan authored Aug 2, 2023
1 parent 29327ce commit 62c5b81
Show file tree
Hide file tree
Showing 24 changed files with 438 additions and 110 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,25 @@

import org.donggle.backend.domain.writing.Writing;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;
import java.util.Optional;

public interface WritingRepository extends JpaRepository<Writing, Long> {
List<Writing> findAllByCategoryId(final Long categoryId);

int countByCategoryId(Long id);

int countByNextWritingId(Long nextWritingId);

@Query("select w from Writing w " +
"where w.category.id = :categoryId and " +
"w.nextWriting is null")
Optional<Writing> findLastWritingByCategoryId(@Param("categoryId") final Long categoryId);

@Query("select w from Writing w " +
"where w.nextWriting.id = :writingId")
Optional<Writing> findPreWritingByWritingId(@Param("writingId") final Long writingId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,28 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Service
@Transactional
@RequiredArgsConstructor
public class CategoryService {
private static final int LAST_WRITING_FLAG = -1;
private static final int FIRST_WRITING_INDEX = 0;

private final MemberRepository memberRepository;
private final CategoryRepository categoryRepository;
private final WritingRepository writingRepository;

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 Category lastCategory = categoryRepository.findLastCategoryByMemberId(memberId)
.orElseThrow(IllegalStateException::new);
final Category category = Category.of(new CategoryName(request.categoryName()), findMember);
final Category lastCategory = findLastCategoryByMemberId(memberId);
final Category savedCategory = categoryRepository.save(category);
lastCategory.changeNextCategory(savedCategory);
return savedCategory.getId();
Expand All @@ -47,24 +51,64 @@ public Long addCategory(final Long memberId, final CategoryAddRequest request) {
public CategoryListResponse findAll(final Long memberId) {
//TODO: member checking
final List<Category> categories = categoryRepository.findAllByMemberId(memberId);
final List<CategoryResponse> categoryResponses = categories.stream()
.map(category -> new CategoryResponse(category.getId(), category.getCategoryNameValue()))
final List<Category> sortedCategories = sortCategory(categories, findBasicCategoryByMemberId(memberId));
final List<CategoryResponse> categoryResponses = sortedCategories.stream()
.map(CategoryResponse::of)
.toList();
return new CategoryListResponse(categoryResponses);
return CategoryListResponse.from(categoryResponses);
}

private List<Category> sortCategory(final List<Category> categories, Category targetCategory) {
final Map<Category, Category> categoryMap = new LinkedHashMap<>();
for (final Category category : categories) {
categoryMap.put(category, category.getNextCategory());
}
final List<Category> sortedCategories = new ArrayList<>();
sortedCategories.add(targetCategory);
while (Objects.nonNull(targetCategory.getNextCategory())) {
targetCategory = categoryMap.get(targetCategory);
sortedCategories.add(targetCategory);
}
return sortedCategories;
}

@Transactional(readOnly = true)
public CategoryWritingsResponse findAllWritings(final Long memberId, final Long categoryId) {
//TODO: member checking
final Category findCategory = findCategory(categoryId);
final List<Writing> findWritings = writingRepository.findAllByCategoryId(findCategory.getId());
final List<WritingSimpleResponse> writingSimpleResponses = findWritings.stream()
.map(writing -> new WritingSimpleResponse(writing.getId(), writing.getTitleValue()))
final Writing firstWriting = findFirstWriting(findWritings);
final List<Writing> sortedWriting = sortWriting(findWritings, firstWriting);
final List<WritingSimpleResponse> writingSimpleResponses = sortedWriting.stream()
.map(WritingSimpleResponse::from)
.toList();
return new CategoryWritingsResponse(findCategory.getId(), findCategory.getCategoryNameValue(), writingSimpleResponses);
return CategoryWritingsResponse.of(findCategory, writingSimpleResponses);
}

public void modifyCategory(final Long memberId, final Long categoryId, final CategoryModifyRequest request) {
private Writing findFirstWriting(final List<Writing> findWritings) {
final List<Writing> copy = new ArrayList<>(findWritings);
final List<Writing> nextWritings = findWritings.stream()
.map(Writing::getNextWriting)
.toList();
copy.removeAll(nextWritings);
return copy.get(FIRST_WRITING_INDEX);
}

private List<Writing> sortWriting(final List<Writing> findWritings, Writing targetWriting) {
final Map<Writing, Writing> writingMap = new LinkedHashMap<>();
for (final Writing findWriting : findWritings) {
writingMap.put(findWriting, findWriting.getNextWriting());
}
final List<Writing> sortedWriting = new ArrayList<>();
sortedWriting.add(targetWriting);
while (Objects.nonNull(targetWriting.getNextWriting())) {
targetWriting = writingMap.get(targetWriting);
sortedWriting.add(targetWriting);
}
return sortedWriting;
}

public void modifyCategoryName(final Long memberId, final Long categoryId, final CategoryModifyRequest request) {
//TODO: member checking
final Category findCategory = findCategory(categoryId);
validateBasicCategory(findCategory);
Expand All @@ -75,19 +119,55 @@ public void removeCategory(final Long memberId, final Long categoryId) {
//TODO: member checking
final Category findCategory = findCategory(categoryId);
validateBasicCategory(findCategory);
transferToBasicCategory(memberId, findCategory);
deleteCategory(findCategory);
}

private void transferToBasicCategory(final Long memberId, final Category findCategory) {
final Category basicCategory = findBasicCategoryByMemberId(memberId);
writingRepository.findAllByCategoryId(findCategory.getId())
.forEach(writing -> writing.changeCategory(basicCategory));
final List<Writing> writings = writingRepository.findAllByCategoryId(findCategory.getId());
final Writing firstWritingInCategory = findFirstWriting(writings);
final Writing lastWriting = findLastWritingInCategory(findCategory);
lastWriting.changeNextWriting(firstWritingInCategory);
writings.forEach(writing -> writing.changeCategory(basicCategory));
}

private void deleteCategory(final Category findCategory) {
final Category nextCategory = findCategory.getNextCategory();
final Category preCategory = findPreCategoryByCategoryId(findCategory.getId());
findCategory.changeNextCategory(null);
final Category preCategory = findPreCategory(findCategory.getId());
findCategory.changeNextCategoryNull();
categoryRepository.flush();
preCategory.changeNextCategory(nextCategory);
categoryRepository.delete(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);
deleteCategoryOrder(source);
addCategoryOrder(nextCategoryId, source, memberId);
}

//TODO: 글 순서 추가 후 글 순서 변경 로직 추가
private void deleteCategoryOrder(final Category category) {
final Category nextCategory = category.getNextCategory();
category.changeNextCategoryNull();
final Category preCategory = findPreCategory(category.getId());
preCategory.changeNextCategory(nextCategory);
}

private void addCategoryOrder(final Long nextCategoryId, final Category category, final Long memberId) {
final Category preCategory;
if (nextCategoryId == LAST_WRITING_FLAG) {
preCategory = findLastCategoryByMemberId(memberId);
} else {
preCategory = findPreCategory(nextCategoryId);
}
preCategory.changeNextCategory(category);
if (nextCategoryId != LAST_WRITING_FLAG) {
final Category nextCategory = findCategory(nextCategoryId);
category.changeNextCategory(nextCategory);
}
}

private void validateBasicCategory(final Category category) {
Expand All @@ -96,16 +176,26 @@ private void validateBasicCategory(final Category category) {
}
}

private Category findLastCategoryByMemberId(final Long memberId) {
return categoryRepository.findLastCategoryByMemberId(memberId)
.orElseThrow(IllegalStateException::new);
}

private Category findBasicCategoryByMemberId(final Long memberId) {
return categoryRepository.findFirstByMemberId(memberId)
.orElseThrow(IllegalStateException::new);
}

private Category findPreCategoryByCategoryId(final Long categoryId) {
private Category findPreCategory(final Long categoryId) {
return categoryRepository.findPreCategoryByCategoryId(categoryId)
.orElseThrow(() -> new CategoryNotFoundException(categoryId));
}

private Writing findLastWritingInCategory(final Category findCategory) {
return writingRepository.findLastWritingByCategoryId(findCategory.getId())
.orElseThrow(IllegalStateException::new);
}

private Member findMember(final Long memberId) {
return memberRepository.findById(memberId)
.orElseThrow(() -> new MemberNotFoundException(memberId));
Expand Down
Loading

0 comments on commit 62c5b81

Please sign in to comment.