Skip to content
Merged
10 changes: 10 additions & 0 deletions src/main/java/com/somemore/community/domain/CommunityComment.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,14 @@ public boolean isWriter(UUID writerId) {
public void updateWith(CommunityCommentUpdateRequestDto dto) {
this.content = dto.content();
}

@Override
public void markAsDeleted() {
super.markAsDeleted();
this.content = "삭제된 댓글입니다";
}

public boolean isDeleted() {
return this.getDeleted();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import com.somemore.community.domain.CommunityBoardView;
import com.somemore.community.repository.mapper.CommunityBoardView;

import java.time.LocalDateTime;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.somemore.community.dto.response;

import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import com.somemore.community.repository.mapper.CommunityCommentView;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public record CommunityCommentResponseDto(
Long id,
String writerNickname,
String content,
LocalDateTime updatedAt,
List<CommunityCommentResponseDto> replies
) {
public CommunityCommentResponseDto {
replies = replies == null ? new ArrayList<>() : replies;
}

public static CommunityCommentResponseDto fromView(CommunityCommentView comment) {
return new CommunityCommentResponseDto(
comment.communityComment().getId(),
comment.writerNickname(),
comment.communityComment().getContent(),
comment.communityComment().getUpdatedAt(),
new ArrayList<>()
);
}

public void addReply(CommunityCommentResponseDto reply) {
this.replies.add(reply);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.somemore.community.repository.board;

import com.somemore.community.domain.CommunityBoard;
import com.somemore.community.domain.CommunityBoardView;
import com.somemore.community.repository.mapper.CommunityBoardView;

import java.util.List;
import java.util.Optional;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.somemore.community.domain.CommunityBoard;
import com.somemore.community.domain.CommunityBoardView;
import com.somemore.community.repository.mapper.CommunityBoardView;
import com.somemore.community.domain.QCommunityBoard;
import com.somemore.volunteer.domain.QVolunteer;
import lombok.RequiredArgsConstructor;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package com.somemore.community.repository.comment;

import com.somemore.community.domain.CommunityComment;
import com.somemore.community.repository.mapper.CommunityCommentView;

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

public interface CommunityCommentRepository {
CommunityComment save(CommunityComment communityComment);
Optional<CommunityComment> findById(Long id);
List<CommunityCommentView> findCommentsByBoardId(Long boardId);
boolean existsById(Long id);
default boolean doesNotExistById(Long id) {
return !existsById(id);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package com.somemore.community.repository.comment;

import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.somemore.community.domain.CommunityComment;
import com.somemore.community.domain.QCommunityComment;
import com.somemore.community.repository.mapper.CommunityCommentView;
import com.somemore.volunteer.domain.QVolunteer;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

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

@RequiredArgsConstructor
Expand All @@ -31,6 +35,21 @@ public Optional<CommunityComment> findById(Long id) {
.fetchOne());
}

public List<CommunityCommentView> findCommentsByBoardId(Long boardId) {
QCommunityComment communityComment = QCommunityComment.communityComment;
QVolunteer volunteer = QVolunteer.volunteer;

return queryFactory
.select(Projections.constructor(CommunityCommentView.class,
communityComment,
volunteer.nickname))
.from(communityComment)
.join(volunteer).on(communityComment.writerId.eq(volunteer.id))
.where(communityComment.communityBoardId.eq(boardId))
.orderBy(communityComment.parentCommentId.asc().nullsFirst(), communityComment.createdAt.asc())
.fetch();
}

@Override
public boolean existsById(Long id) {
QCommunityComment communityComment = QCommunityComment.communityComment;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
package com.somemore.community.domain;
package com.somemore.community.repository.mapper;

import com.somemore.community.domain.CommunityBoard;

public record CommunityBoardView(
CommunityBoard communityBoard,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.somemore.community.repository.mapper;

import com.somemore.community.domain.CommunityComment;
import lombok.Builder;

@Builder
public record CommunityCommentView(
CommunityComment communityComment,
String writerNickname
) {
public CommunityCommentView replaceWriterNickname(CommunityCommentView communityCommentView) {
return CommunityCommentView.builder()
.communityComment(communityCommentView.communityComment)
.writerNickname("").build();
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.somemore.community.service.board;

import com.somemore.community.domain.CommunityBoard;
import com.somemore.community.domain.CommunityBoardView;
import com.somemore.community.repository.mapper.CommunityBoardView;
import com.somemore.community.dto.response.CommunityBoardGetDetailResponseDto;
import com.somemore.community.dto.response.CommunityBoardGetResponseDto;
import com.somemore.community.repository.board.CommunityBoardRepository;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package com.somemore.community.service.comment;

import com.somemore.community.domain.CommunityComment;
import com.somemore.community.dto.response.CommunityCommentResponseDto;
import com.somemore.community.repository.comment.CommunityCommentRepository;
import com.somemore.community.repository.mapper.CommunityCommentView;
import com.somemore.community.usecase.comment.CommunityCommentQueryUseCase;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@RequiredArgsConstructor
@Transactional(readOnly = true)
@Service
public class CommunityCommentQueryService implements CommunityCommentQueryUseCase {

private final CommunityCommentRepository communityCommentRepository;

@Override
public List<CommunityCommentResponseDto> getCommunityCommentsByBoardId(Long boardId) {
List<CommunityCommentView> allComments = communityCommentRepository.findCommentsByBoardId(boardId);
List<CommunityCommentView> filteredComments = filterValidComments(allComments);
return createCommentHierarchy(filteredComments);
}

private List<CommunityCommentView> filterValidComments(List<CommunityCommentView> comments) {
List<Long> parentCommentIds = findParentCommentIds(comments);

return comments.stream()
.flatMap(comment -> processDeletedComment(parentCommentIds, comment).stream())
.toList();
}

private List<Long> findParentCommentIds(List<CommunityCommentView> comments) {
return comments.stream()
.filter(comment -> !comment.communityComment().getDeleted())
.map(comment -> comment.communityComment().getParentCommentId())
.filter(Objects::nonNull)
.toList();
}

private Optional<CommunityCommentView> processDeletedComment(List<Long> parentCommentIds, CommunityCommentView commentView) {
CommunityComment comment = commentView.communityComment();

if (comment.isDeleted()) {
if (parentCommentIds.contains(comment.getId())) {
return Optional.of(commentView.replaceWriterNickname(commentView));
}
return Optional.empty();
}

return Optional.of(commentView);
}

private List<CommunityCommentResponseDto> createCommentHierarchy(List<CommunityCommentView> comments) {

Map<Long, CommunityCommentResponseDto> commentMap = new HashMap<>();
List<CommunityCommentResponseDto> rootComments = new ArrayList<>();

for (CommunityCommentView comment : comments) {
CommunityCommentResponseDto dto = CommunityCommentResponseDto.fromView(comment);
commentMap.put(dto.id(), dto);

Long parentCommentId = comment.communityComment().getParentCommentId();

if (parentCommentId == null) {
rootComments.add(dto);
} else {
commentMap.get(parentCommentId).addReply(dto);
}
}

return rootComments;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.somemore.community.usecase.comment;

import com.somemore.community.dto.response.CommunityCommentResponseDto;

import java.util.List;

public interface CommunityCommentQueryUseCase {
List<CommunityCommentResponseDto> getCommunityCommentsByBoardId(Long boardId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import com.somemore.IntegrationTestSupport;
import com.somemore.auth.oauth.OAuthProvider;
import com.somemore.community.domain.CommunityBoard;
import com.somemore.community.domain.CommunityBoardView;
import com.somemore.community.repository.mapper.CommunityBoardView;
import com.somemore.community.repository.board.CommunityBoardRepository;
import com.somemore.volunteer.domain.Volunteer;
import com.somemore.volunteer.repository.VolunteerRepository;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
package com.somemore.community.repository;

import com.somemore.IntegrationTestSupport;
import com.somemore.auth.oauth.OAuthProvider;
import com.somemore.community.domain.CommunityBoard;
import com.somemore.community.domain.CommunityComment;
import com.somemore.community.repository.board.CommunityBoardRepository;
import com.somemore.community.repository.comment.CommunityCommentRepository;
import com.somemore.community.repository.mapper.CommunityCommentView;
import com.somemore.volunteer.domain.Volunteer;
import com.somemore.volunteer.repository.VolunteerRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

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

Expand All @@ -23,26 +28,32 @@ class CommunityCommentRepositoryTest extends IntegrationTestSupport {
CommunityCommentRepository communityCommentRepository;
@Autowired
CommunityBoardRepository communityBoardRepository;
@Autowired
VolunteerRepository volunteerRepository;

private Long boardId;
private UUID writerId;
private CommunityComment savedComment;

@BeforeEach
void setUp() {
String oAuthId = "example-oauth-id";
Volunteer volunteer = Volunteer.createDefault(OAuthProvider.NAVER, oAuthId);
volunteerRepository.save(volunteer);

writerId = volunteer.getId();

CommunityBoard communityBoard = CommunityBoard.builder()
.title("테스트 커뮤니티 게시글 제목")
.content("테스트 커뮤니티 게시글 내용")
.imgUrl("http://community.example.com/123")
.writerId(UUID.randomUUID())
.writerId(writerId)
.build();

communityBoardRepository.save(communityBoard);

boardId = communityBoard.getId();

writerId = UUID.randomUUID();

CommunityComment communityComment = CommunityComment.builder()
.communityBoardId(boardId)
.writerId(writerId)
Expand Down Expand Up @@ -74,7 +85,7 @@ void createCommunityCommentReply() {
.communityBoardId(boardId)
.writerId(writerId)
.content("커뮤니티 댓글 테스트 내용")
.parentCommentId(1L)
.parentCommentId(savedComment.getId())
.build();

//when
Expand All @@ -83,7 +94,7 @@ void createCommunityCommentReply() {
//then
assertThat(savedCommentReply.getWriterId()).isEqualTo(writerId);
assertThat(savedCommentReply.getContent()).isEqualTo("커뮤니티 댓글 테스트 내용");
assertThat(savedCommentReply.getParentCommentId()).isEqualTo(1L);
assertThat(savedCommentReply.getParentCommentId()).isEqualTo(savedComment.getId());
}

@DisplayName("댓글을 id로 조회할 수 있다. (Repository)")
Expand Down Expand Up @@ -112,4 +123,27 @@ void existsById() {
//then
assertThat(isExist).isTrue();
}

@DisplayName("게시글 id로 게시글에 달린 댓글을 조회할 수 있다. (Repository)")
@Test
void findCommunityCommentByBoardId() {

//given
CommunityComment communityCommentReply = CommunityComment.builder()
.communityBoardId(boardId)
.writerId(writerId)
.content("커뮤니티 댓글 테스트 내용")
.parentCommentId(savedComment.getId())
.build();

CommunityComment savedCommentReply = communityCommentRepository.save(communityCommentReply);

//when
List<CommunityCommentView> comments = communityCommentRepository.findCommentsByBoardId(boardId);

//then
assertThat(comments).hasSize(2);
assertThat(comments.getFirst().communityComment().getId()).isEqualTo(savedComment.getId());
assertThat(comments.getLast().communityComment().getId()).isEqualTo(savedCommentReply.getId());
}
}
Loading