diff --git a/src/main/java/com/dreamypatisiel/devdevdev/domain/entity/AnonymousMember.java b/src/main/java/com/dreamypatisiel/devdevdev/domain/entity/AnonymousMember.java index 1a833999..b7cef6b2 100644 --- a/src/main/java/com/dreamypatisiel/devdevdev/domain/entity/AnonymousMember.java +++ b/src/main/java/com/dreamypatisiel/devdevdev/domain/entity/AnonymousMember.java @@ -53,4 +53,8 @@ public boolean hasNickName() { public void changeNickname(String nickname) { this.nickname = nickname; } + + public boolean isEqualsId(Long id) { + return this.id.equals(id); + } } diff --git a/src/main/java/com/dreamypatisiel/devdevdev/domain/entity/PickComment.java b/src/main/java/com/dreamypatisiel/devdevdev/domain/entity/PickComment.java index f5909d32..c00c3446 100644 --- a/src/main/java/com/dreamypatisiel/devdevdev/domain/entity/PickComment.java +++ b/src/main/java/com/dreamypatisiel/devdevdev/domain/entity/PickComment.java @@ -235,11 +235,11 @@ public boolean isDeleted() { } public boolean isDeletedByMember() { - return this.deletedBy != null; + return this.deletedBy != null && this.deletedAnonymousBy == null; } public boolean isDeletedByAnonymousMember() { - return this.deletedAnonymousBy != null; + return this.deletedBy == null && this.deletedAnonymousBy != null; } public boolean isEqualsId(Long id) { @@ -273,4 +273,12 @@ public boolean isCreatedAnonymousMember() { public boolean isCreatedMember() { return this.createdBy != null && this.createdAnonymousBy == null; } + + public boolean isDeletedMemberByMySelf() { + return this.createdBy.isEqualsId(this.deletedBy.getId()); + } + + public boolean isDeletedAnonymousMemberByMySelf() { + return this.createdAnonymousBy.isEqualsId(this.deletedAnonymousBy.getId()); + } } diff --git a/src/main/java/com/dreamypatisiel/devdevdev/domain/entity/TechComment.java b/src/main/java/com/dreamypatisiel/devdevdev/domain/entity/TechComment.java index 8fdd6499..ede50c29 100644 --- a/src/main/java/com/dreamypatisiel/devdevdev/domain/entity/TechComment.java +++ b/src/main/java/com/dreamypatisiel/devdevdev/domain/entity/TechComment.java @@ -2,12 +2,23 @@ import com.dreamypatisiel.devdevdev.domain.entity.embedded.CommentContents; import com.dreamypatisiel.devdevdev.domain.entity.embedded.Count; -import jakarta.persistence.*; - +import jakarta.persistence.AttributeOverride; +import jakarta.persistence.Column; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.ForeignKey; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Index; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; - import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -53,23 +64,31 @@ public class TechComment extends BasicTime { private LocalDateTime contentsLastModifiedAt; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "parent_id", referencedColumnName = "id") + @JoinColumn(name = "parent_id", referencedColumnName = "id", foreignKey = @ForeignKey(name = "fk_tech_comment_01")) private TechComment parent; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "origin_parent_id", referencedColumnName = "id") + @JoinColumn(name = "origin_parent_id", referencedColumnName = "id", foreignKey = @ForeignKey(name = "fk_tech_comment_02")) private TechComment originParent; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "created_by", nullable = false) + @JoinColumn(name = "created_by", foreignKey = @ForeignKey(name = "fk_tech_comment_03")) private Member createdBy; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "deleted_by") + @JoinColumn(name = "deleted_by", foreignKey = @ForeignKey(name = "fk_tech_comment_04")) private Member deletedBy; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "tech_article_id", nullable = false) + @JoinColumn(name = "created_anonymous_by", foreignKey = @ForeignKey(name = "fk_tech_comment_05")) + private AnonymousMember createdAnonymousBy; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "deleted_anonymous_by", foreignKey = @ForeignKey(name = "fk_tech_comment_06")) + private AnonymousMember deletedAnonymousBy; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "tech_article_id", nullable = false, foreignKey = @ForeignKey(name = "fk_tech_comment_07")) private TechArticle techArticle; @OneToMany(mappedBy = "techComment") @@ -78,7 +97,8 @@ public class TechComment extends BasicTime { @Builder private TechComment(CommentContents contents, Count blameTotalCount, Count recommendTotalCount, Count replyTotalCount, TechComment parent, TechComment originParent, Member createdBy, Member deletedBy, - TechArticle techArticle, LocalDateTime deletedAt) { + AnonymousMember createdAnonymousBy, AnonymousMember deletedAnonymousBy, TechArticle techArticle, + LocalDateTime deletedAt) { this.contents = contents; this.blameTotalCount = blameTotalCount; this.recommendTotalCount = recommendTotalCount; @@ -87,6 +107,8 @@ private TechComment(CommentContents contents, Count blameTotalCount, Count recom this.originParent = originParent; this.createdBy = createdBy; this.deletedBy = deletedBy; + this.createdAnonymousBy = createdAnonymousBy; + this.deletedAnonymousBy = deletedAnonymousBy; this.techArticle = techArticle; this.deletedAt = deletedAt; } @@ -159,4 +181,12 @@ public void incrementBlameTotalCount() { public boolean isEqualsId(Long id) { return this.id.equals(id); } + + public boolean isCreatedAnonymousMember() { + return this.createdBy == null && this.createdAnonymousBy != null; + } + + public boolean isCreatedMember() { + return this.createdBy != null && this.createdAnonymousBy == null; + } } diff --git a/src/main/java/com/dreamypatisiel/devdevdev/domain/repository/techArticle/TechCommentRepository.java b/src/main/java/com/dreamypatisiel/devdevdev/domain/repository/techArticle/TechCommentRepository.java index ef20d71c..620bd09c 100644 --- a/src/main/java/com/dreamypatisiel/devdevdev/domain/repository/techArticle/TechCommentRepository.java +++ b/src/main/java/com/dreamypatisiel/devdevdev/domain/repository/techArticle/TechCommentRepository.java @@ -18,9 +18,8 @@ Optional findByIdAndTechArticleIdAndCreatedByIdAndDeletedAtIsNull(L Optional findByIdAndTechArticleIdAndDeletedAtIsNull(Long id, Long techArticleId); - @EntityGraph(attributePaths = {"createdBy", "deletedBy", "techArticle"}) - List findWithMemberWithTechArticleByOriginParentIdInAndParentIsNotNullAndOriginParentIsNotNull( - Set originParentIds); + @EntityGraph(attributePaths = {"createdBy", "deletedBy", "createdAnonymousBy", "deletedAnonymousBy", "techArticle"}) + List findWithDetailsByOriginParentIdInAndParentIsNotNullAndOriginParentIsNotNull(Set originParentIds); Long countByTechArticleIdAndOriginParentIsNullAndParentIsNullAndDeletedAtIsNull(Long techArticleId); diff --git a/src/main/java/com/dreamypatisiel/devdevdev/domain/repository/techArticle/custom/TechCommentRepositoryImpl.java b/src/main/java/com/dreamypatisiel/devdevdev/domain/repository/techArticle/custom/TechCommentRepositoryImpl.java index 581eed00..5d09c48c 100644 --- a/src/main/java/com/dreamypatisiel/devdevdev/domain/repository/techArticle/custom/TechCommentRepositoryImpl.java +++ b/src/main/java/com/dreamypatisiel/devdevdev/domain/repository/techArticle/custom/TechCommentRepositoryImpl.java @@ -1,5 +1,6 @@ package com.dreamypatisiel.devdevdev.domain.repository.techArticle.custom; +import static com.dreamypatisiel.devdevdev.domain.entity.QAnonymousMember.anonymousMember; import static com.dreamypatisiel.devdevdev.domain.entity.QMember.member; import static com.dreamypatisiel.devdevdev.domain.entity.QTechArticle.techArticle; import static com.dreamypatisiel.devdevdev.domain.entity.QTechComment.techComment; @@ -34,7 +35,8 @@ public Slice findOriginParentTechCommentsByCursor(Long techArticleI TechCommentSort techCommentSort, Pageable pageable) { List contents = query.selectFrom(techComment) .innerJoin(techComment.techArticle, techArticle).on(techArticle.id.eq(techArticleId)) - .innerJoin(techComment.createdBy, member).fetchJoin() + .leftJoin(techComment.createdBy, member).fetchJoin() + .leftJoin(techComment.createdAnonymousBy, anonymousMember).fetchJoin() .where(techComment.parent.isNull() .and(techComment.originParent.isNull()) .and(getCursorCondition(techCommentSort, techCommentId)) @@ -51,7 +53,8 @@ public List findOriginParentTechBestCommentsByTechArticleIdAndOffse return query.selectFrom(techComment) .innerJoin(techComment.techArticle, techArticle).on(techArticle.id.eq(techArticleId)) - .innerJoin(techComment.createdBy, member).fetchJoin() + .leftJoin(techComment.createdBy, member).fetchJoin() + .leftJoin(techComment.createdAnonymousBy, anonymousMember).fetchJoin() .where(techComment.parent.isNull() .and(techComment.originParent.isNull()) .and(techComment.deletedAt.isNull()) diff --git a/src/main/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/techComment/GuestTechCommentService.java b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/techComment/GuestTechCommentService.java index 93f2d7cb..185a4f92 100644 --- a/src/main/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/techComment/GuestTechCommentService.java +++ b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/techComment/GuestTechCommentService.java @@ -5,9 +5,9 @@ import com.dreamypatisiel.devdevdev.domain.policy.TechBestCommentsPolicy; import com.dreamypatisiel.devdevdev.domain.repository.techArticle.TechCommentRepository; import com.dreamypatisiel.devdevdev.domain.repository.techArticle.TechCommentSort; +import com.dreamypatisiel.devdevdev.domain.service.member.AnonymousMemberService; import com.dreamypatisiel.devdevdev.global.utils.AuthenticationMemberUtils; import com.dreamypatisiel.devdevdev.web.dto.SliceCommentCustom; -import com.dreamypatisiel.devdevdev.web.dto.SliceCustom; import com.dreamypatisiel.devdevdev.web.dto.request.techArticle.ModifyTechCommentRequest; import com.dreamypatisiel.devdevdev.web.dto.request.techArticle.RegisterTechCommentRequest; import com.dreamypatisiel.devdevdev.web.dto.response.techArticle.TechCommentRecommendResponse; @@ -24,9 +24,13 @@ @Transactional(readOnly = true) public class GuestTechCommentService extends TechCommentCommonService implements TechCommentService { + private final AnonymousMemberService anonymousMemberService; + public GuestTechCommentService(TechCommentRepository techCommentRepository, - TechBestCommentsPolicy techBestCommentsPolicy) { + TechBestCommentsPolicy techBestCommentsPolicy, + AnonymousMemberService anonymousMemberService) { super(techCommentRepository, techBestCommentsPolicy); + this.anonymousMemberService = anonymousMemberService; } @Override @@ -60,12 +64,12 @@ public TechCommentResponse deleteTechComment(Long techArticleId, Long techCommen @Override public SliceCommentCustom getTechComments(Long techArticleId, Long techCommentId, TechCommentSort techCommentSort, Pageable pageable, - Authentication authentication) { + String anonymousMemberId, Authentication authentication) { // 익명 회원인지 검증 AuthenticationMemberUtils.validateAnonymousMethodCall(authentication); // 기술블로그 댓글/답글 조회 - return super.getTechComments(techArticleId, techCommentId, techCommentSort, pageable, null); + return super.getTechComments(techArticleId, techCommentId, techCommentSort, pageable, null, null); } @Override @@ -80,12 +84,12 @@ public TechCommentRecommendResponse recommendTechComment(Long techArticleId, Lon * @Since: 2024.10.27 */ @Override - public List findTechBestComments(int size, Long techArticleId, + public List findTechBestComments(int size, Long techArticleId, String anonymousMemberId, Authentication authentication) { // 익명 회원인지 검증 AuthenticationMemberUtils.validateAnonymousMethodCall(authentication); - return super.findTechBestComments(size, techArticleId, null); + return super.findTechBestComments(size, techArticleId, null, null); } } diff --git a/src/main/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/techComment/GuestTechCommentServiceV2.java b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/techComment/GuestTechCommentServiceV2.java new file mode 100644 index 00000000..1af1098f --- /dev/null +++ b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/techComment/GuestTechCommentServiceV2.java @@ -0,0 +1,108 @@ +package com.dreamypatisiel.devdevdev.domain.service.techArticle.techComment; + +import static com.dreamypatisiel.devdevdev.domain.exception.GuestExceptionMessage.INVALID_ANONYMOUS_CAN_NOT_USE_THIS_FUNCTION_MESSAGE; + +import com.dreamypatisiel.devdevdev.domain.entity.AnonymousMember; +import com.dreamypatisiel.devdevdev.domain.policy.TechBestCommentsPolicy; +import com.dreamypatisiel.devdevdev.domain.repository.techArticle.TechCommentRepository; +import com.dreamypatisiel.devdevdev.domain.repository.techArticle.TechCommentSort; +import com.dreamypatisiel.devdevdev.domain.service.member.AnonymousMemberService; +import com.dreamypatisiel.devdevdev.global.utils.AuthenticationMemberUtils; +import com.dreamypatisiel.devdevdev.web.dto.SliceCommentCustom; +import com.dreamypatisiel.devdevdev.web.dto.request.techArticle.ModifyTechCommentRequest; +import com.dreamypatisiel.devdevdev.web.dto.request.techArticle.RegisterTechCommentRequest; +import com.dreamypatisiel.devdevdev.web.dto.response.techArticle.TechCommentRecommendResponse; +import com.dreamypatisiel.devdevdev.web.dto.response.techArticle.TechCommentResponse; +import com.dreamypatisiel.devdevdev.web.dto.response.techArticle.TechCommentsResponse; +import java.util.List; +import org.springframework.data.domain.Pageable; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +public class GuestTechCommentServiceV2 extends TechCommentCommonService implements TechCommentService { + + private final AnonymousMemberService anonymousMemberService; + + public GuestTechCommentServiceV2(TechCommentRepository techCommentRepository, + TechBestCommentsPolicy techBestCommentsPolicy, + AnonymousMemberService anonymousMemberService) { + super(techCommentRepository, techBestCommentsPolicy); + this.anonymousMemberService = anonymousMemberService; + } + + @Override + public TechCommentResponse registerMainTechComment(Long techArticleId, + RegisterTechCommentRequest registerTechCommentRequest, + Authentication authentication) { + throw new AccessDeniedException(INVALID_ANONYMOUS_CAN_NOT_USE_THIS_FUNCTION_MESSAGE); + } + + @Override + public TechCommentResponse registerRepliedTechComment(Long techArticleId, Long originParentTechCommentId, + Long parentTechCommentId, + RegisterTechCommentRequest registerRepliedTechCommentRequest, + Authentication authentication) { + throw new AccessDeniedException(INVALID_ANONYMOUS_CAN_NOT_USE_THIS_FUNCTION_MESSAGE); + } + + @Override + public TechCommentResponse modifyTechComment(Long techArticleId, Long techCommentId, + ModifyTechCommentRequest modifyTechCommentRequest, + Authentication authentication) { + throw new AccessDeniedException(INVALID_ANONYMOUS_CAN_NOT_USE_THIS_FUNCTION_MESSAGE); + } + + @Override + public TechCommentResponse deleteTechComment(Long techArticleId, Long techCommentId, + Authentication authentication) { + throw new AccessDeniedException(INVALID_ANONYMOUS_CAN_NOT_USE_THIS_FUNCTION_MESSAGE); + } + + /** + * @Note: 익명 회원이 기술블로그 댓글/답글을 조회한다. + * @Author: 장세웅 + * @Since: 2025.07.20 + */ + @Override + public SliceCommentCustom getTechComments(Long techArticleId, Long techCommentId, + TechCommentSort techCommentSort, Pageable pageable, + String anonymousMemberId, + Authentication authentication) { + // 익명 회원인지 검증 + AuthenticationMemberUtils.validateAnonymousMethodCall(authentication); + + // 익명회원 추출 + AnonymousMember anonymousMember = anonymousMemberService.findOrCreateAnonymousMember(anonymousMemberId); + + // 기술블로그 댓글/답글 조회 + return super.getTechComments(techArticleId, techCommentId, techCommentSort, pageable, null, anonymousMember); + } + + @Override + public TechCommentRecommendResponse recommendTechComment(Long techArticleId, Long techCommentId, + Authentication authentication) { + throw new AccessDeniedException(INVALID_ANONYMOUS_CAN_NOT_USE_THIS_FUNCTION_MESSAGE); + } + + /** + * @Note: 익명 회원이 기술블로그 베스트 댓글을 조회한다. + * @Author: 장세웅 + * @Since: 2025.07.20 + */ + @Override + public List findTechBestComments(int size, Long techArticleId, + String anonymousMemberId, Authentication authentication) { + + // 익명 회원인지 검증 + AuthenticationMemberUtils.validateAnonymousMethodCall(authentication); + + // 익명회원 추출 + AnonymousMember anonymousMember = anonymousMemberService.findOrCreateAnonymousMember(anonymousMemberId); + + return super.findTechBestComments(size, techArticleId, null, anonymousMember); + } +} diff --git a/src/main/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/techComment/MemberTechCommentService.java b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/techComment/MemberTechCommentService.java index 5edff37d..569b69f4 100644 --- a/src/main/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/techComment/MemberTechCommentService.java +++ b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/techComment/MemberTechCommentService.java @@ -1,5 +1,10 @@ package com.dreamypatisiel.devdevdev.domain.service.techArticle.techComment; +import static com.dreamypatisiel.devdevdev.domain.exception.TechArticleExceptionMessage.INVALID_CAN_NOT_RECOMMEND_DELETED_TECH_COMMENT_MESSAGE; +import static com.dreamypatisiel.devdevdev.domain.exception.TechArticleExceptionMessage.INVALID_CAN_NOT_REPLY_DELETED_TECH_COMMENT_MESSAGE; +import static com.dreamypatisiel.devdevdev.domain.exception.TechArticleExceptionMessage.INVALID_NOT_FOUND_TECH_COMMENT_MESSAGE; +import static com.dreamypatisiel.devdevdev.domain.service.techArticle.techArticle.TechArticleCommonService.validateIsDeletedTechComment; + import com.dreamypatisiel.devdevdev.domain.entity.Member; import com.dreamypatisiel.devdevdev.domain.entity.TechArticle; import com.dreamypatisiel.devdevdev.domain.entity.TechComment; @@ -20,17 +25,13 @@ import com.dreamypatisiel.devdevdev.web.dto.response.techArticle.TechCommentRecommendResponse; import com.dreamypatisiel.devdevdev.web.dto.response.techArticle.TechCommentResponse; import com.dreamypatisiel.devdevdev.web.dto.response.techArticle.TechCommentsResponse; +import java.util.List; +import java.util.Optional; import org.springframework.data.domain.Pageable; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; -import java.util.Optional; - -import static com.dreamypatisiel.devdevdev.domain.exception.TechArticleExceptionMessage.*; -import static com.dreamypatisiel.devdevdev.domain.service.techArticle.techArticle.TechArticleCommonService.validateIsDeletedTechComment; - @Service @Transactional(readOnly = true) public class MemberTechCommentService extends TechCommentCommonService implements TechCommentService { @@ -224,12 +225,13 @@ public TechCommentResponse deleteTechComment(Long techArticleId, Long techCommen */ public SliceCommentCustom getTechComments(Long techArticleId, Long techCommentId, TechCommentSort techCommentSort, Pageable pageable, + String anonymousMemberId, Authentication authentication) { // 회원 조회 Member findMember = memberProvider.getMemberByAuthentication(authentication); // 기술블로그 댓글/답글 조회 - return super.getTechComments(techArticleId, techCommentId, techCommentSort, pageable, findMember); + return super.getTechComments(techArticleId, techCommentId, techCommentSort, pageable, findMember, null); } /** @@ -263,12 +265,12 @@ public TechCommentRecommendResponse recommendTechComment(Long techArticleId, Lon */ @Override public List findTechBestComments(int size, Long techArticleId, - Authentication authentication) { + String anonymousMemberId, Authentication authentication) { // 회원 조회 Member findMember = memberProvider.getMemberByAuthentication(authentication); - return super.findTechBestComments(size, techArticleId, findMember); + return super.findTechBestComments(size, techArticleId, findMember, null); } private TechCommentRecommendResponse toggleTechCommentRecommend(TechComment techComment, Member member) { diff --git a/src/main/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/techComment/TechCommentCommonService.java b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/techComment/TechCommentCommonService.java index 95eb83e6..f06d8df5 100644 --- a/src/main/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/techComment/TechCommentCommonService.java +++ b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/techComment/TechCommentCommonService.java @@ -1,5 +1,6 @@ package com.dreamypatisiel.devdevdev.domain.service.techArticle.techComment; +import com.dreamypatisiel.devdevdev.domain.entity.AnonymousMember; import com.dreamypatisiel.devdevdev.domain.entity.BasicTime; import com.dreamypatisiel.devdevdev.domain.entity.Member; import com.dreamypatisiel.devdevdev.domain.entity.TechComment; @@ -37,8 +38,9 @@ public class TechCommentCommonService { * @Since: 2024.09.05 */ public SliceCommentCustom getTechComments(Long techArticleId, Long techCommentId, - TechCommentSort techCommentSort, Pageable pageable, - @Nullable Member member) { + TechCommentSort techCommentSort, Pageable pageable, + @Nullable Member member, + @Nullable AnonymousMember anonymousMember) { // 기술블로그 최상위 댓글 조회 Slice findOriginParentTechComments = techCommentRepository.findOriginParentTechCommentsByCursor( techArticleId, techCommentId, techCommentSort, pageable); @@ -51,13 +53,13 @@ public SliceCommentCustom getTechComments(Long techArticle // 최상위 댓글 아이디들의 댓글 답글 조회(최상위 댓글의 아이디가 key) Map> techCommentReplies = techCommentRepository - .findWithMemberWithTechArticleByOriginParentIdInAndParentIsNotNullAndOriginParentIsNotNull( + .findWithDetailsByOriginParentIdInAndParentIsNotNullAndOriginParentIsNotNull( originParentIds).stream() .collect(Collectors.groupingBy(techCommentReply -> techCommentReply.getOriginParent().getId())); // 기술블로그 댓글/답글 응답 생성 List techCommentsResponse = originParentTechComments.stream() - .map(originParentTechComment -> getTechCommentsResponse(member, originParentTechComment, + .map(originParentTechComment -> getTechCommentsResponse(member, anonymousMember, originParentTechComment, techCommentReplies)) .toList(); @@ -75,14 +77,17 @@ public SliceCommentCustom getTechComments(Long techArticle long originTechCommentTotalCount = firstTechComment.getTechArticle().getCommentTotalCount().getCount(); // 기술블로그 부모 댓글 개수 추출 - long originParentTechCommentTotalCount = techCommentRepository.countByTechArticleIdAndOriginParentIsNullAndParentIsNullAndDeletedAtIsNull(techArticleId); + long originParentTechCommentTotalCount = techCommentRepository.countByTechArticleIdAndOriginParentIsNullAndParentIsNullAndDeletedAtIsNull( + techArticleId); // 데이터 가공 return new SliceCommentCustom<>(techCommentsResponse, pageable, findOriginParentTechComments.hasNext(), originTechCommentTotalCount, originParentTechCommentTotalCount); } - private TechCommentsResponse getTechCommentsResponse(@Nullable Member member, TechComment originParentTechComment, + private TechCommentsResponse getTechCommentsResponse(@Nullable Member member, + @Nullable AnonymousMember anonymousMember, + TechComment originParentTechComment, Map> techCommentReplies) { // 최상위 댓글의 아이디 추출 Long originParentTechCommentId = originParentTechComment.getId(); @@ -92,18 +97,19 @@ private TechCommentsResponse getTechCommentsResponse(@Nullable Member member, Te // 답글이 없을 경우 if (ObjectUtils.isEmpty(replies)) { - return TechCommentsResponse.of(member, originParentTechComment, Collections.emptyList()); + return TechCommentsResponse.of(member, anonymousMember, originParentTechComment, Collections.emptyList()); } // 답글 응답 만들기 - List techRepliedComments = getTechRepliedComments(member, replies); - return TechCommentsResponse.of(member, originParentTechComment, techRepliedComments); + List techRepliedComments = getTechRepliedComments(member, anonymousMember, replies); + return TechCommentsResponse.of(member, anonymousMember, originParentTechComment, techRepliedComments); } - private List getTechRepliedComments(Member member, List replies) { + private List getTechRepliedComments(Member member, AnonymousMember anonymousMember, + List replies) { return replies.stream() .sorted(Comparator.comparing(BasicTime::getCreatedAt)) - .map(repliedTechComment -> TechRepliedCommentsResponse.of(member, repliedTechComment)) + .map(repliedTechComment -> TechRepliedCommentsResponse.of(member, anonymousMember, repliedTechComment)) .toList(); } @@ -112,7 +118,8 @@ private List getTechRepliedComments(Member member, * @Author: 장세웅 * @Since: 2024.10.27 */ - protected List findTechBestComments(int size, Long techArticleId, @Nullable Member member) { + protected List findTechBestComments(int size, Long techArticleId, @Nullable Member member, + @Nullable AnonymousMember anonymousMember) { // 베스트 댓글 offset 정책 적용 int offset = techBestCommentsPolicy.applySize(size); @@ -127,13 +134,13 @@ protected List findTechBestComments(int size, Long techArt .collect(Collectors.toSet()); // 베스트 댓글의 답글 조회(베스트 댓글의 아이디가 key) - Map> techBestCommentReplies = techCommentRepository.findWithMemberWithTechArticleByOriginParentIdInAndParentIsNotNullAndOriginParentIsNotNull( + Map> techBestCommentReplies = techCommentRepository.findWithDetailsByOriginParentIdInAndParentIsNotNullAndOriginParentIsNotNull( originParentIds).stream() .collect(Collectors.groupingBy(techCommentReply -> techCommentReply.getOriginParent().getId())); // 기술블로그 댓글/답글 응답 생성 return findOriginTechBestComments.stream() - .map(originParentTechComment -> getTechCommentsResponse(member, originParentTechComment, + .map(originParentTechComment -> getTechCommentsResponse(member, anonymousMember, originParentTechComment, techBestCommentReplies)) .toList(); } diff --git a/src/main/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/techComment/TechCommentService.java b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/techComment/TechCommentService.java index 7ca722c4..a6ac42bf 100644 --- a/src/main/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/techComment/TechCommentService.java +++ b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/techComment/TechCommentService.java @@ -2,7 +2,6 @@ import com.dreamypatisiel.devdevdev.domain.repository.techArticle.TechCommentSort; import com.dreamypatisiel.devdevdev.web.dto.SliceCommentCustom; -import com.dreamypatisiel.devdevdev.web.dto.SliceCustom; import com.dreamypatisiel.devdevdev.web.dto.request.techArticle.ModifyTechCommentRequest; import com.dreamypatisiel.devdevdev.web.dto.request.techArticle.RegisterTechCommentRequest; import com.dreamypatisiel.devdevdev.web.dto.response.techArticle.TechCommentRecommendResponse; @@ -32,10 +31,12 @@ TechCommentResponse modifyTechComment(Long techArticleId, Long techCommentId, SliceCommentCustom getTechComments(Long techArticleId, Long techCommentId, TechCommentSort techCommentSort, Pageable pageable, + String anonymousMemberId, Authentication authentication); TechCommentRecommendResponse recommendTechComment(Long techArticleId, Long techCommentId, Authentication authentication); - List findTechBestComments(int size, Long techArticleId, Authentication authentication); + List findTechBestComments(int size, Long techArticleId, String anonymousMemberId, + Authentication authentication); } diff --git a/src/main/java/com/dreamypatisiel/devdevdev/redis/sub/RedisNotificationSubscriber.java b/src/main/java/com/dreamypatisiel/devdevdev/redis/sub/RedisNotificationSubscriber.java index 8550ba3f..b982357f 100644 --- a/src/main/java/com/dreamypatisiel/devdevdev/redis/sub/RedisNotificationSubscriber.java +++ b/src/main/java/com/dreamypatisiel/devdevdev/redis/sub/RedisNotificationSubscriber.java @@ -31,7 +31,7 @@ public void onMessage(@Nullable Message message, byte[] pattern) { try { // 채널 파싱 String channel = new String(pattern, StandardCharsets.UTF_8); - + // 구독 채널인 경우 if (channel.equals(NotificationType.SUBSCRIPTION.name())) { ObjectMapper om = new ObjectMapper(); diff --git a/src/main/java/com/dreamypatisiel/devdevdev/web/controller/techArticle/TechArticleCommentController.java b/src/main/java/com/dreamypatisiel/devdevdev/web/controller/techArticle/TechArticleCommentController.java index dce201c3..7e5e8a43 100644 --- a/src/main/java/com/dreamypatisiel/devdevdev/web/controller/techArticle/TechArticleCommentController.java +++ b/src/main/java/com/dreamypatisiel/devdevdev/web/controller/techArticle/TechArticleCommentController.java @@ -1,9 +1,12 @@ package com.dreamypatisiel.devdevdev.web.controller.techArticle; +import static com.dreamypatisiel.devdevdev.web.WebConstant.HEADER_ANONYMOUS_MEMBER_ID; + import com.dreamypatisiel.devdevdev.domain.repository.techArticle.TechCommentSort; import com.dreamypatisiel.devdevdev.domain.service.techArticle.TechArticleServiceStrategy; import com.dreamypatisiel.devdevdev.domain.service.techArticle.techComment.TechCommentService; import com.dreamypatisiel.devdevdev.global.utils.AuthenticationMemberUtils; +import com.dreamypatisiel.devdevdev.global.utils.HttpRequestUtils; import com.dreamypatisiel.devdevdev.web.dto.SliceCustom; import com.dreamypatisiel.devdevdev.web.dto.request.techArticle.ModifyTechCommentRequest; import com.dreamypatisiel.devdevdev.web.dto.request.techArticle.RegisterTechCommentRequest; @@ -102,20 +105,20 @@ public ResponseEntity> deleteTechComment( return ResponseEntity.ok(BasicResponse.success(response)); } - @Operation(summary = "기술블로그 댓글/답글 조회") + @Operation(summary = "기술블로그 댓글/답글 조회", description = "기술블로그 댓글/답글을 조회할 수 있습니다.") @GetMapping("/articles/{techArticleId}/comments") public ResponseEntity>> getTechComments( @PageableDefault(size = 5) Pageable pageable, @PathVariable Long techArticleId, @RequestParam(required = false) TechCommentSort techCommentSort, - @RequestParam(required = false) Long techCommentId - ) { + @RequestParam(required = false) Long techCommentId) { Authentication authentication = AuthenticationMemberUtils.getAuthentication(); + String anonymousMemberId = HttpRequestUtils.getHeaderValue(HEADER_ANONYMOUS_MEMBER_ID); TechCommentService techCommentService = techArticleServiceStrategy.getTechCommentService(); SliceCustom response = techCommentService.getTechComments(techArticleId, techCommentId, - techCommentSort, pageable, authentication); + techCommentSort, pageable, anonymousMemberId, authentication); return ResponseEntity.ok(BasicResponse.success(response)); } @@ -143,10 +146,11 @@ public ResponseEntity> getTechBestComments( @PathVariable Long techArticleId) { Authentication authentication = AuthenticationMemberUtils.getAuthentication(); + String anonymousMemberId = HttpRequestUtils.getHeaderValue(HEADER_ANONYMOUS_MEMBER_ID); TechCommentService techCommentService = techArticleServiceStrategy.getTechCommentService(); List techCommentsResponse = techCommentService.findTechBestComments(size, techArticleId, - authentication); + anonymousMemberId, authentication); return ResponseEntity.ok(BasicResponse.success(techCommentsResponse)); } diff --git a/src/main/java/com/dreamypatisiel/devdevdev/web/dto/response/pick/PickRepliedCommentsResponse.java b/src/main/java/com/dreamypatisiel/devdevdev/web/dto/response/pick/PickRepliedCommentsResponse.java index 60c203b8..96c05599 100644 --- a/src/main/java/com/dreamypatisiel/devdevdev/web/dto/response/pick/PickRepliedCommentsResponse.java +++ b/src/main/java/com/dreamypatisiel/devdevdev/web/dto/response/pick/PickRepliedCommentsResponse.java @@ -70,47 +70,39 @@ public static PickRepliedCommentsResponse of(@Nullable Member member, @Nullable // 부모 댓글 PickComment parentPickComment = repliedPickComment.getParent(); - Member parentCreatedBy = parentPickComment.getCreatedBy(); - AnonymousMember parentCreatedAnonymousBy = parentPickComment.getCreatedAnonymousBy(); - - // 댓글 - Member repliedCreatedBy = repliedPickComment.getCreatedBy(); - AnonymousMember repliedCreatedAnonymousBy = repliedPickComment.getCreatedAnonymousBy(); // 부모 댓글/답글 익명회원이 작성한 경우 if (parentPickComment.isCreatedAnonymousMember() && repliedPickComment.isCreatedAnonymousMember()) { - return createResponseForAnonymousReplyToAnonymous(member, anonymousMember, repliedPickComment, - repliedCreatedAnonymousBy, parentCreatedAnonymousBy, parentPickComment); + return createResponseForAnonymousReplyToAnonymous(member, anonymousMember, repliedPickComment, parentPickComment); } // 부모 댓글은 익명회원이 작성하고 답글은 회원이 작성한 경우 if (parentPickComment.isCreatedAnonymousMember() && repliedPickComment.isCreatedMember()) { - return createResponseForMemberReplyToAnonymous(member, anonymousMember, repliedPickComment, repliedCreatedBy, - parentCreatedAnonymousBy, parentPickComment); + return createResponseForMemberReplyToAnonymous(member, anonymousMember, repliedPickComment, parentPickComment); } // 부모 댓글은 회원이 작성하고 답글은 익명회원이 작성한 경우 if (parentPickComment.isCreatedMember() && repliedPickComment.isCreatedAnonymousMember()) { - return createResponseForAnonymousReplyToMember(member, anonymousMember, repliedPickComment, - repliedCreatedAnonymousBy, parentCreatedBy, parentPickComment); + return createResponseForAnonymousReplyToMember(member, anonymousMember, repliedPickComment, parentPickComment); } // 부모 댓글/답글 회원이 작성한 경우 - return createResponseForMemberReplyToMember(member, anonymousMember, repliedPickComment, repliedCreatedBy, - parentPickComment); + return createResponseForMemberReplyToMember(member, anonymousMember, repliedPickComment, parentPickComment); } private static PickRepliedCommentsResponse createResponseForMemberReplyToMember(Member member, AnonymousMember anonymousMember, PickComment repliedPickComment, - Member repliedCreatedBy, PickComment parentPickComment) { + Member parentCreatedBy = parentPickComment.getCreatedBy(); + Member repliedCreatedBy = repliedPickComment.getCreatedBy(); + return PickRepliedCommentsResponse.builder() .pickCommentId(repliedPickComment.getId()) .memberId(repliedCreatedBy.getId()) - .pickParentCommentMemberId(parentPickComment.getCreatedBy().getId()) + .pickParentCommentMemberId(parentCreatedBy.getId()) .author(repliedCreatedBy.getNickname().getNickname()) - .pickParentCommentAuthor(parentPickComment.getCreatedBy().getNicknameAsString()) + .pickParentCommentAuthor(parentCreatedBy.getNicknameAsString()) .pickParentCommentId(parentPickComment.getId()) .pickOriginParentCommentId(repliedPickComment.getOriginParent().getId()) .createdAt(repliedPickComment.getCreatedAt()) @@ -128,9 +120,11 @@ private static PickRepliedCommentsResponse createResponseForMemberReplyToMember( private static PickRepliedCommentsResponse createResponseForMemberReplyToAnonymous(Member member, AnonymousMember anonymousMember, PickComment repliedPickComment, - Member repliedCreatedBy, - AnonymousMember parentCreatedAnonymousBy, PickComment parentPickComment) { + + AnonymousMember parentCreatedAnonymousBy = parentPickComment.getCreatedAnonymousBy(); + Member repliedCreatedBy = repliedPickComment.getCreatedBy(); + return PickRepliedCommentsResponse.builder() .pickCommentId(repliedPickComment.getId()) .memberId(repliedCreatedBy.getId()) @@ -154,9 +148,11 @@ private static PickRepliedCommentsResponse createResponseForMemberReplyToAnonymo private static PickRepliedCommentsResponse createResponseForAnonymousReplyToMember(Member member, AnonymousMember anonymousMember, PickComment repliedPickComment, - AnonymousMember repliedCreatedAnonymousBy, - Member parentCreatedBy, PickComment parentPickComment) { + + Member parentCreatedBy = parentPickComment.getCreatedBy(); + AnonymousMember repliedCreatedAnonymousBy = repliedPickComment.getCreatedAnonymousBy(); + return PickRepliedCommentsResponse.builder() .pickCommentId(repliedPickComment.getId()) .anonymousMemberId(repliedCreatedAnonymousBy.getId()) @@ -179,9 +175,11 @@ private static PickRepliedCommentsResponse createResponseForAnonymousReplyToMemb private static PickRepliedCommentsResponse createResponseForAnonymousReplyToAnonymous(Member member, AnonymousMember anonymousMember, PickComment repliedPickComment, - AnonymousMember repliedCreatedAnonymousBy, - AnonymousMember parentCreatedAnonymousBy, PickComment parentPickComment) { + + AnonymousMember parentCreatedAnonymousBy = parentPickComment.getCreatedAnonymousBy(); + AnonymousMember repliedCreatedAnonymousBy = repliedPickComment.getCreatedAnonymousBy(); + return PickRepliedCommentsResponse.builder() .pickCommentId(repliedPickComment.getId()) .anonymousMemberId(repliedCreatedAnonymousBy.getId()) diff --git a/src/main/java/com/dreamypatisiel/devdevdev/web/dto/response/techArticle/TechCommentsResponse.java b/src/main/java/com/dreamypatisiel/devdevdev/web/dto/response/techArticle/TechCommentsResponse.java index b2d90017..ddab7215 100644 --- a/src/main/java/com/dreamypatisiel/devdevdev/web/dto/response/techArticle/TechCommentsResponse.java +++ b/src/main/java/com/dreamypatisiel/devdevdev/web/dto/response/techArticle/TechCommentsResponse.java @@ -1,22 +1,23 @@ package com.dreamypatisiel.devdevdev.web.dto.response.techArticle; +import com.dreamypatisiel.devdevdev.domain.entity.AnonymousMember; import com.dreamypatisiel.devdevdev.domain.entity.Member; import com.dreamypatisiel.devdevdev.domain.entity.TechComment; import com.dreamypatisiel.devdevdev.global.common.TimeProvider; import com.dreamypatisiel.devdevdev.web.dto.util.CommentResponseUtil; import com.dreamypatisiel.devdevdev.web.dto.util.CommonResponseUtil; import com.fasterxml.jackson.annotation.JsonFormat; -import lombok.Builder; -import lombok.Data; - -import javax.annotation.Nullable; import java.time.LocalDateTime; import java.util.List; +import javax.annotation.Nullable; +import lombok.Builder; +import lombok.Data; @Data public class TechCommentsResponse { private Long techCommentId; private Long memberId; + private Long anonymousMemberId; private String author; private String maskedEmail; private String contents; @@ -32,12 +33,13 @@ public class TechCommentsResponse { private LocalDateTime createdAt; @Builder - public TechCommentsResponse(Long techCommentId, Long memberId, String author, String maskedEmail, String contents, - Long replyTotalCount, Long recommendTotalCount, Boolean isDeleted, Boolean isCommentAuthor, - Boolean isModified, Boolean isRecommended, List replies, - LocalDateTime createdAt) { + public TechCommentsResponse(Long techCommentId, Long memberId, Long anonymousMemberId, String author, String maskedEmail, + String contents, Long replyTotalCount, Long recommendTotalCount, Boolean isDeleted, + Boolean isCommentAuthor, Boolean isModified, Boolean isRecommended, + List replies, LocalDateTime createdAt) { this.techCommentId = techCommentId; this.memberId = memberId; + this.anonymousMemberId = anonymousMemberId; this.author = author; this.maskedEmail = maskedEmail; this.contents = contents; @@ -51,11 +53,48 @@ public TechCommentsResponse(Long techCommentId, Long memberId, String author, St this.createdAt = createdAt; } - public static TechCommentsResponse of(@Nullable Member member, - TechComment originParentTechComment, - List replies) { + public static TechCommentsResponse of(@Nullable Member member, @Nullable AnonymousMember anonymousMember, + TechComment originParentTechComment, List replies) { + Member createdBy = originParentTechComment.getCreatedBy(); + AnonymousMember createdAnonymousBy = originParentTechComment.getCreatedAnonymousBy(); + + // 회원이 작성한 댓글 응답 + if (originParentTechComment.isCreatedMember()) { + return createTechCommentsResponseByCreatedMember(member, anonymousMember, originParentTechComment, replies, + createdBy); + } + + // 익명회원이 작성한 댓글 응답 + return createTechCommentsResponseByCreatedAnonymousMember(member, anonymousMember, originParentTechComment, replies, + createdAnonymousBy); + } + + private static TechCommentsResponse createTechCommentsResponseByCreatedAnonymousMember(Member member, + AnonymousMember anonymousMember, + TechComment originParentTechComment, + List replies, + AnonymousMember createdAnonymousBy) { + return TechCommentsResponse.builder() + .techCommentId(originParentTechComment.getId()) + .anonymousMemberId(createdAnonymousBy.getId()) + .author(createdAnonymousBy.getNickname()) + .contents(CommentResponseUtil.getCommentByTechCommentStatus(originParentTechComment)) + .replyTotalCount(originParentTechComment.getReplyTotalCount().getCount()) + .recommendTotalCount(originParentTechComment.getRecommendTotalCount().getCount()) + .isDeleted(originParentTechComment.isDeleted()) + .isModified(originParentTechComment.isModified()) + .isRecommended(CommentResponseUtil.isTechCommentRecommendedByMember(member, originParentTechComment)) + .createdAt(originParentTechComment.getCreatedAt()) + .isCommentAuthor(CommentResponseUtil.isTechCommentAuthor(member, anonymousMember, originParentTechComment)) + .replies(replies) + .build(); + } + private static TechCommentsResponse createTechCommentsResponseByCreatedMember(Member member, AnonymousMember anonymousMember, + TechComment originParentTechComment, + List replies, + Member createdBy) { return TechCommentsResponse.builder() .techCommentId(originParentTechComment.getId()) .memberId(createdBy.getId()) @@ -68,7 +107,7 @@ public static TechCommentsResponse of(@Nullable Member member, .isModified(originParentTechComment.isModified()) .isRecommended(CommentResponseUtil.isTechCommentRecommendedByMember(member, originParentTechComment)) .createdAt(originParentTechComment.getCreatedAt()) - .isCommentAuthor(CommentResponseUtil.isTechCommentAuthor(member, originParentTechComment)) + .isCommentAuthor(CommentResponseUtil.isTechCommentAuthor(member, anonymousMember, originParentTechComment)) .replies(replies) .build(); } diff --git a/src/main/java/com/dreamypatisiel/devdevdev/web/dto/response/techArticle/TechRepliedCommentsResponse.java b/src/main/java/com/dreamypatisiel/devdevdev/web/dto/response/techArticle/TechRepliedCommentsResponse.java index c84eecd1..4cb59073 100644 --- a/src/main/java/com/dreamypatisiel/devdevdev/web/dto/response/techArticle/TechRepliedCommentsResponse.java +++ b/src/main/java/com/dreamypatisiel/devdevdev/web/dto/response/techArticle/TechRepliedCommentsResponse.java @@ -1,5 +1,6 @@ package com.dreamypatisiel.devdevdev.web.dto.response.techArticle; +import com.dreamypatisiel.devdevdev.domain.entity.AnonymousMember; import com.dreamypatisiel.devdevdev.domain.entity.Member; import com.dreamypatisiel.devdevdev.domain.entity.TechComment; import com.dreamypatisiel.devdevdev.global.common.TimeProvider; @@ -16,7 +17,9 @@ public class TechRepliedCommentsResponse { private Long techCommentId; private Long memberId; + private Long anonymousMemberId; private Long techParentCommentMemberId; + private Long techParentCommentAnonymousMemberId; // 부모 댓글의 작성자 익명회원 아이디 private Long techParentCommentId; private Long techOriginParentCommentId; @@ -35,15 +38,16 @@ public class TechRepliedCommentsResponse { private LocalDateTime createdAt; @Builder - public TechRepliedCommentsResponse(Long techCommentId, Long memberId, Long techParentCommentMemberId, - Long techParentCommentId, Long techOriginParentCommentId, - Boolean isCommentAuthor, - Boolean isRecommended, String techParentCommentAuthor, String author, - String maskedEmail, String contents, Long recommendTotalCount, Boolean isDeleted, - Boolean isModified, LocalDateTime createdAt) { + public TechRepliedCommentsResponse(Long techCommentId, Long memberId, Long anonymousMemberId, Long techParentCommentMemberId, + Long techParentCommentAnonymousMemberId, Long techParentCommentId, + Long techOriginParentCommentId, Boolean isCommentAuthor, Boolean isRecommended, + String techParentCommentAuthor, String author, String maskedEmail, String contents, + Long recommendTotalCount, Boolean isDeleted, Boolean isModified, LocalDateTime createdAt) { this.techCommentId = techCommentId; this.memberId = memberId; + this.anonymousMemberId = anonymousMemberId; this.techParentCommentMemberId = techParentCommentMemberId; + this.techParentCommentAnonymousMemberId = techParentCommentAnonymousMemberId; this.techParentCommentId = techParentCommentId; this.techOriginParentCommentId = techOriginParentCommentId; this.isCommentAuthor = isCommentAuthor; @@ -58,22 +62,129 @@ public TechRepliedCommentsResponse(Long techCommentId, Long memberId, Long techP this.createdAt = createdAt; } - public static TechRepliedCommentsResponse of(@Nullable Member member, TechComment repliedTechComment) { + public static TechRepliedCommentsResponse of(@Nullable Member member, @Nullable AnonymousMember anonymousMember, + TechComment repliedTechComment) { - Member createdBy = repliedTechComment.getCreatedBy(); - TechComment techParentComment = repliedTechComment.getParent(); + // 부모 댓글 + TechComment parentTechComment = repliedTechComment.getParent(); + + // 부모 댓글/답글 익명회원이 작성한 경우 + if (parentTechComment.isCreatedAnonymousMember() && repliedTechComment.isCreatedAnonymousMember()) { + return createResponseForAnonymousReplyToAnonymous(member, anonymousMember, repliedTechComment, parentTechComment); + } + + // 부모 댓글은 익명회원이 작성하고 답글은 회원이 작성한 경우 + if (parentTechComment.isCreatedAnonymousMember() && repliedTechComment.isCreatedMember()) { + return createResponseForMemberReplyToAnonymous(member, anonymousMember, repliedTechComment, parentTechComment); + } + + // 부모 댓글은 회원이 작성하고 답글은 익명회원이 작성한 경우 + if (parentTechComment.isCreatedMember() && repliedTechComment.isCreatedAnonymousMember()) { + return createResponseForAnonymousReplyToMember(member, anonymousMember, repliedTechComment, parentTechComment); + } + + // 부모 댓글/답글 회원이 작성한 경우 + return createResponseForMemberReplyToMember(member, anonymousMember, repliedTechComment, parentTechComment); + } + + private static TechRepliedCommentsResponse createResponseForAnonymousReplyToAnonymous(Member member, + AnonymousMember anonymousMember, + TechComment repliedTechComment, + TechComment parentTechComment) { + + AnonymousMember parentCreatedAnonymousBy = parentTechComment.getCreatedAnonymousBy(); + AnonymousMember repliedCreatedAnonymousBy = repliedTechComment.getCreatedAnonymousBy(); + + return TechRepliedCommentsResponse.builder() + .techCommentId(repliedTechComment.getId()) + .anonymousMemberId(repliedCreatedAnonymousBy.getId()) + .author(repliedCreatedAnonymousBy.getNickname()) + .techParentCommentAnonymousMemberId(parentCreatedAnonymousBy.getId()) + .techParentCommentAuthor(parentCreatedAnonymousBy.getNickname()) + .techParentCommentId(repliedTechComment.getParent().getId()) + .techOriginParentCommentId(repliedTechComment.getOriginParent().getId()) + .createdAt(repliedTechComment.getCreatedAt()) + .isCommentAuthor(CommentResponseUtil.isTechCommentAuthor(member, anonymousMember, repliedTechComment)) + .contents(CommentResponseUtil.getCommentByTechCommentStatus(repliedTechComment)) + .recommendTotalCount(repliedTechComment.getRecommendTotalCount().getCount()) + .isRecommended(CommentResponseUtil.isTechCommentRecommendedByMember(member, repliedTechComment)) + .isDeleted(repliedTechComment.isDeleted()) + .isModified(repliedTechComment.isModified()) + .build(); + } + + private static TechRepliedCommentsResponse createResponseForMemberReplyToAnonymous(Member member, + AnonymousMember anonymousMember, + TechComment repliedTechComment, + TechComment parentTechComment) { + + AnonymousMember parentCreatedAnonymousBy = parentTechComment.getCreatedAnonymousBy(); + Member repliedCreatedBy = repliedTechComment.getCreatedBy(); + + return TechRepliedCommentsResponse.builder() + .techCommentId(repliedTechComment.getId()) + .memberId(repliedCreatedBy.getId()) + .author(repliedCreatedBy.getNickname().getNickname()) + .techParentCommentAnonymousMemberId(parentCreatedAnonymousBy.getId()) + .techParentCommentAuthor(parentCreatedAnonymousBy.getNickname()) + .techParentCommentId(repliedTechComment.getParent().getId()) + .techOriginParentCommentId(repliedTechComment.getOriginParent().getId()) + .createdAt(repliedTechComment.getCreatedAt()) + .isCommentAuthor(CommentResponseUtil.isTechCommentAuthor(member, anonymousMember, repliedTechComment)) + .maskedEmail(CommonResponseUtil.sliceAndMaskEmail(repliedCreatedBy.getEmail().getEmail())) + .contents(CommentResponseUtil.getCommentByTechCommentStatus(repliedTechComment)) + .recommendTotalCount(repliedTechComment.getRecommendTotalCount().getCount()) + .isRecommended(CommentResponseUtil.isTechCommentRecommendedByMember(member, repliedTechComment)) + .isDeleted(repliedTechComment.isDeleted()) + .isModified(repliedTechComment.isModified()) + .build(); + } + + private static TechRepliedCommentsResponse createResponseForMemberReplyToMember(Member member, + AnonymousMember anonymousMember, + TechComment repliedTechComment, + TechComment parentTechComment) { + + Member parentCreatedBy = parentTechComment.getCreatedBy(); + Member repliedCreatedBy = repliedTechComment.getCreatedBy(); + + return TechRepliedCommentsResponse.builder() + .techCommentId(repliedTechComment.getId()) + .memberId(repliedCreatedBy.getId()) + .author(repliedCreatedBy.getNickname().getNickname()) + .techParentCommentMemberId(parentCreatedBy.getId()) + .techParentCommentAuthor(parentCreatedBy.getNicknameAsString()) + .techParentCommentId(repliedTechComment.getParent().getId()) + .techOriginParentCommentId(repliedTechComment.getOriginParent().getId()) + .createdAt(repliedTechComment.getCreatedAt()) + .isCommentAuthor(CommentResponseUtil.isTechCommentAuthor(member, anonymousMember, repliedTechComment)) + .maskedEmail(CommonResponseUtil.sliceAndMaskEmail(repliedCreatedBy.getEmail().getEmail())) + .contents(CommentResponseUtil.getCommentByTechCommentStatus(repliedTechComment)) + .recommendTotalCount(repliedTechComment.getRecommendTotalCount().getCount()) + .isRecommended(CommentResponseUtil.isTechCommentRecommendedByMember(member, repliedTechComment)) + .isDeleted(repliedTechComment.isDeleted()) + .isModified(repliedTechComment.isModified()) + .build(); + } + + private static TechRepliedCommentsResponse createResponseForAnonymousReplyToMember(Member member, + AnonymousMember anonymousMember, + TechComment repliedTechComment, + TechComment parentTechComment) { + + Member parentCreatedBy = parentTechComment.getCreatedBy(); + AnonymousMember repliedCreatedAnonymousBy = repliedTechComment.getCreatedAnonymousBy(); return TechRepliedCommentsResponse.builder() .techCommentId(repliedTechComment.getId()) - .memberId(createdBy.getId()) - .author(createdBy.getNickname().getNickname()) - .techParentCommentMemberId(techParentComment.getCreatedBy().getId()) - .techParentCommentAuthor(techParentComment.getCreatedBy().getNicknameAsString()) + .anonymousMemberId(repliedCreatedAnonymousBy.getId()) + .author(repliedCreatedAnonymousBy.getNickname()) + .techParentCommentMemberId(parentCreatedBy.getId()) + .techParentCommentAuthor(parentCreatedBy.getNicknameAsString()) .techParentCommentId(repliedTechComment.getParent().getId()) .techOriginParentCommentId(repliedTechComment.getOriginParent().getId()) .createdAt(repliedTechComment.getCreatedAt()) - .isCommentAuthor(CommentResponseUtil.isTechCommentAuthor(member, repliedTechComment)) - .maskedEmail(CommonResponseUtil.sliceAndMaskEmail(createdBy.getEmail().getEmail())) + .isCommentAuthor(CommentResponseUtil.isTechCommentAuthor(member, anonymousMember, repliedTechComment)) .contents(CommentResponseUtil.getCommentByTechCommentStatus(repliedTechComment)) .recommendTotalCount(repliedTechComment.getRecommendTotalCount().getCount()) .isRecommended(CommentResponseUtil.isTechCommentRecommendedByMember(member, repliedTechComment)) diff --git a/src/main/java/com/dreamypatisiel/devdevdev/web/dto/util/CommentResponseUtil.java b/src/main/java/com/dreamypatisiel/devdevdev/web/dto/util/CommentResponseUtil.java index 741ed7f7..16a79668 100644 --- a/src/main/java/com/dreamypatisiel/devdevdev/web/dto/util/CommentResponseUtil.java +++ b/src/main/java/com/dreamypatisiel/devdevdev/web/dto/util/CommentResponseUtil.java @@ -14,37 +14,45 @@ public class CommentResponseUtil { public static final String DELETE_COMMENT_MESSAGE = "댓글 작성자에 의해 삭제된 댓글입니다."; public static final String DELETE_INVALID_COMMUNITY_POLICY_COMMENT_MESSAGE = "커뮤니티 정책을 위반하여 삭제된 댓글입니다."; + public static final String CONTACT_ADMIN_MESSAGE = "오류가 발생 했습니다. 관리자에게 문의 하세요."; public static String getCommentByPickCommentStatus(PickComment pickComment) { - if (pickComment.isDeleted()) { - // 익명회원 작성자에 의해 삭제된 경우 - if (pickComment.isDeletedByAnonymousMember()) { - AnonymousMember createdAnonymousBy = pickComment.getCreatedAnonymousBy(); - AnonymousMember deletedAnonymousBy = pickComment.getDeletedAnonymousBy(); - if (deletedAnonymousBy.isEqualAnonymousMemberId(createdAnonymousBy.getId())) { - return DELETE_COMMENT_MESSAGE; - } - } + if (!pickComment.isDeleted()) { + return pickComment.getContents().getCommentContents(); + } - // 회원 작성자에 의해 삭제된 경우 - Member createdBy = pickComment.getCreatedBy(); - Member deletedBy = pickComment.getDeletedBy(); + // 익명회원이 작성한 댓글인 경우 + if (pickComment.isCreatedAnonymousMember()) { + // 자기자신이 삭제한 경우 + if (pickComment.isDeletedByAnonymousMember()) { + return DELETE_COMMENT_MESSAGE; + } - // 익명회원이 작성한 댓글인 경우 - if (createdBy == null) { - // 어드민이 삭제함 + // 어드민이 삭제한 경우 + if (pickComment.getDeletedBy().isAdmin()) { return DELETE_INVALID_COMMUNITY_POLICY_COMMENT_MESSAGE; } - if (deletedBy.isEqualsId(createdBy.getId())) { + return CONTACT_ADMIN_MESSAGE; + } + + // 회원이 작성한 댓글인 경우 + if (pickComment.isCreatedMember()) { + // 자기 자신인 경우 + if (pickComment.isDeletedMemberByMySelf()) { return DELETE_COMMENT_MESSAGE; } - return DELETE_INVALID_COMMUNITY_POLICY_COMMENT_MESSAGE; + // 어드민이 삭제한 경우 + if (pickComment.getDeletedBy().isAdmin()) { + return DELETE_INVALID_COMMUNITY_POLICY_COMMENT_MESSAGE; + } + + return CONTACT_ADMIN_MESSAGE; } - return pickComment.getContents().getCommentContents(); + return CONTACT_ADMIN_MESSAGE; } public static String getCommentByTechCommentStatus(TechComment techComment) { @@ -76,26 +84,15 @@ public static boolean isPickAuthor(@Nullable Member member, Pick pick) { public static boolean isPickCommentAuthor(@Nullable Member member, @Nullable AnonymousMember anonymousMember, PickComment pickComment) { - // 회원이 조회한 경우 - if (member != null) { - Member createdBy = pickComment.getCreatedBy(); - // createdBy가 null인 경우는 익명회원이 작성한 댓글 - if (createdBy == null) { - return false; - } - - return createdBy.isEqualsId(member.getId()); + // 회원이 조회하고 픽픽픽 댓글을 회원이 작성한 경우 + if (member != null && pickComment.isCreatedMember()) { + // 픽픽픽 댓글을 회원이 작성한 경우 + return pickComment.getCreatedBy().isEqualsId(member.getId()); } - // 익명회원이 조회한 경우 - if (anonymousMember != null) { - AnonymousMember createdAnonymousBy = pickComment.getCreatedAnonymousBy(); - // createdAnonymousBy 가 null인 경우는 회원이 작성한 댓글 - if (createdAnonymousBy == null) { - return false; - } - - return createdAnonymousBy.isEqualAnonymousMemberId(anonymousMember.getId()); + // 익명회원이 조회하고 픽픽픽 댓글을 익명회원이 작성한 경우 + if (anonymousMember != null && pickComment.isCreatedAnonymousMember()) { + return pickComment.getCreatedAnonymousBy().isEqualAnonymousMemberId(anonymousMember.getId()); } return false; @@ -112,12 +109,19 @@ public static boolean isPickCommentRecommended(@Nullable Member member, PickComm .anyMatch(pickCommentRecommend -> pickCommentRecommend.getMember().isEqualsId(member.getId())); } - public static boolean isTechCommentAuthor(Member member, TechComment techComment) { - // member 가 null 인 경우 익명회원이 조회한 것 - if (member == null) { - return false; + public static boolean isTechCommentAuthor(@Nullable Member member, @Nullable AnonymousMember anonymousMember, + TechComment techComment) { + // 회원이 조회하고 기술블로그 댓글을 회원이 작성한 경우 + if (member != null && techComment.isCreatedMember()) { + return techComment.getCreatedBy().isEqualsId(member.getId()); + } + + // 익명회원이 조회하고 기술블로그 댓글을 익명회원이 작성한 경우 + if (anonymousMember != null && techComment.isCreatedAnonymousMember()) { + return techComment.getCreatedAnonymousBy().isEqualAnonymousMemberId(anonymousMember.getId()); } - return techComment.getCreatedBy().isEqualsId(member.getId()); + + return false; } public static boolean isTechCommentRecommendedByMember(@Nullable Member member, TechComment techComment) { diff --git a/src/test/java/com/dreamypatisiel/devdevdev/domain/service/pick/GuestPickCommentServiceTest.java b/src/test/java/com/dreamypatisiel/devdevdev/domain/service/pick/GuestPickCommentServiceTest.java index 7851309c..6aa216a5 100644 --- a/src/test/java/com/dreamypatisiel/devdevdev/domain/service/pick/GuestPickCommentServiceTest.java +++ b/src/test/java/com/dreamypatisiel/devdevdev/domain/service/pick/GuestPickCommentServiceTest.java @@ -1,5 +1,12 @@ package com.dreamypatisiel.devdevdev.domain.service.pick; +import static com.dreamypatisiel.devdevdev.domain.service.pick.PickTestUtils.createPick; +import static com.dreamypatisiel.devdevdev.domain.service.pick.PickTestUtils.createPickComment; +import static com.dreamypatisiel.devdevdev.domain.service.pick.PickTestUtils.createPickCommentRecommend; +import static com.dreamypatisiel.devdevdev.domain.service.pick.PickTestUtils.createPickOption; +import static com.dreamypatisiel.devdevdev.domain.service.pick.PickTestUtils.createPickVote; +import static com.dreamypatisiel.devdevdev.domain.service.pick.PickTestUtils.createReplidPickComment; +import static com.dreamypatisiel.devdevdev.domain.service.pick.PickTestUtils.createSocialDto; import static com.dreamypatisiel.devdevdev.global.utils.AuthenticationMemberUtils.INVALID_METHODS_CALL_MESSAGE; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -996,121 +1003,4 @@ void findPickBestComments() { pickReply3.getParent().getCreatedBy().getNicknameAsString()) ); } - - private PickVote createPickVote(Member member, PickOption pickOption, Pick pick) { - PickVote pickVote = PickVote.builder() - .member(member) - .build(); - - pickVote.changePickOption(pickOption); - pickVote.changePick(pick); - - return pickVote; - } - - private Pick createPick(Title title, ContentStatus contentStatus, Count viewTotalCount, Count voteTotalCount, - Count commentTotalCount, Count popularScore, Member member) { - return Pick.builder() - .title(title) - .contentStatus(contentStatus) - .viewTotalCount(viewTotalCount) - .voteTotalCount(voteTotalCount) - .commentTotalCount(commentTotalCount) - .popularScore(popularScore) - .member(member) - .build(); - } - - private PickComment createPickComment(CommentContents contents, Boolean isPublic, Count recommendTotalCount, - Member member, Pick pick) { - PickComment pickComment = PickComment.builder() - .contents(contents) - .isPublic(isPublic) - .createdBy(member) - .recommendTotalCount(recommendTotalCount) - .pick(pick) - .build(); - - pickComment.changePick(pick); - - return pickComment; - } - - private PickCommentRecommend createPickCommentRecommend(PickComment pickComment, Member member, - Boolean recommendedStatus) { - return PickCommentRecommend.builder() - .pickComment(pickComment) - .member(member) - .recommendedStatus(recommendedStatus) - .build(); - } - - private Pick createPick(Title title, ContentStatus contentStatus, Count commentTotalCount, Member member) { - return Pick.builder() - .title(title) - .contentStatus(contentStatus) - .commentTotalCount(commentTotalCount) - .member(member) - .build(); - } - - private PickComment createPickComment(CommentContents contents, Boolean isPublic, Count replyTotalCount, - Count recommendTotalCount, Member member, Pick pick, PickVote pickVote) { - PickComment pickComment = PickComment.builder() - .contents(contents) - .isPublic(isPublic) - .createdBy(member) - .replyTotalCount(replyTotalCount) - .recommendTotalCount(recommendTotalCount) - .pick(pick) - .pickVote(pickVote) - .build(); - - pickComment.changePick(pick); - - return pickComment; - } - - private PickComment createReplidPickComment(CommentContents contents, Member member, Pick pick, - PickComment originParent, PickComment parent) { - PickComment pickComment = PickComment.builder() - .contents(contents) - .createdBy(member) - .pick(pick) - .originParent(originParent) - .isPublic(false) - .parent(parent) - .recommendTotalCount(new Count(0)) - .replyTotalCount(new Count(0)) - .build(); - - pickComment.changePick(pick); - - return pickComment; - } - - private PickOption createPickOption(Title title, Count voteTotalCount, Pick pick, PickOptionType pickOptionType) { - PickOption pickOption = PickOption.builder() - .title(title) - .voteTotalCount(voteTotalCount) - .pickOptionType(pickOptionType) - .build(); - - pickOption.changePick(pick); - - return pickOption; - } - - private SocialMemberDto createSocialDto(String userId, String name, String nickName, String password, String email, - String socialType, String role) { - return SocialMemberDto.builder() - .userId(userId) - .name(name) - .nickname(nickName) - .password(password) - .email(email) - .socialType(SocialType.valueOf(socialType)) - .role(Role.valueOf(role)) - .build(); - } } \ No newline at end of file diff --git a/src/test/java/com/dreamypatisiel/devdevdev/domain/service/pick/MemberPickCommentServiceTest.java b/src/test/java/com/dreamypatisiel/devdevdev/domain/service/pick/MemberPickCommentServiceTest.java index 62f7fbee..b746199d 100644 --- a/src/test/java/com/dreamypatisiel/devdevdev/domain/service/pick/MemberPickCommentServiceTest.java +++ b/src/test/java/com/dreamypatisiel/devdevdev/domain/service/pick/MemberPickCommentServiceTest.java @@ -12,6 +12,14 @@ import static com.dreamypatisiel.devdevdev.domain.service.pick.MemberPickCommentService.MODIFY; import static com.dreamypatisiel.devdevdev.domain.service.pick.MemberPickCommentService.RECOMMEND; import static com.dreamypatisiel.devdevdev.domain.service.pick.MemberPickCommentService.REGISTER; +import static com.dreamypatisiel.devdevdev.domain.service.pick.PickTestUtils.createPick; +import static com.dreamypatisiel.devdevdev.domain.service.pick.PickTestUtils.createPickComment; +import static com.dreamypatisiel.devdevdev.domain.service.pick.PickTestUtils.createPickCommentRecommend; +import static com.dreamypatisiel.devdevdev.domain.service.pick.PickTestUtils.createPickOption; +import static com.dreamypatisiel.devdevdev.domain.service.pick.PickTestUtils.createPickOptionImage; +import static com.dreamypatisiel.devdevdev.domain.service.pick.PickTestUtils.createPickVote; +import static com.dreamypatisiel.devdevdev.domain.service.pick.PickTestUtils.createReplidPickComment; +import static com.dreamypatisiel.devdevdev.domain.service.pick.PickTestUtils.createSocialDto; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertAll; @@ -50,11 +58,7 @@ import com.dreamypatisiel.devdevdev.global.security.oauth2.model.UserPrincipal; import com.dreamypatisiel.devdevdev.web.dto.SliceCustom; import com.dreamypatisiel.devdevdev.web.dto.request.pick.ModifyPickCommentRequest; -import com.dreamypatisiel.devdevdev.web.dto.request.pick.ModifyPickOptionRequest; -import com.dreamypatisiel.devdevdev.web.dto.request.pick.ModifyPickRequest; -import com.dreamypatisiel.devdevdev.web.dto.request.pick.RegisterPickOptionRequest; import com.dreamypatisiel.devdevdev.web.dto.request.pick.RegisterPickRepliedCommentRequest; -import com.dreamypatisiel.devdevdev.web.dto.request.pick.RegisterPickRequest; import com.dreamypatisiel.devdevdev.web.dto.response.pick.PickCommentRecommendResponse; import com.dreamypatisiel.devdevdev.web.dto.response.pick.PickCommentResponse; import com.dreamypatisiel.devdevdev.web.dto.response.pick.PickCommentsResponse; @@ -66,7 +70,6 @@ import java.time.LocalDateTime; import java.util.EnumSet; import java.util.List; -import java.util.Map; import org.assertj.core.groups.Tuple; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -78,8 +81,6 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; -import org.springframework.http.MediaType; -import org.springframework.mock.web.MockMultipartFile; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; @@ -2601,328 +2602,4 @@ void findPickBestComments() { pickReply3.getParent().getCreatedBy().getNicknameAsString()) ); } - - private Pick createPick(Title title, ContentStatus contentStatus, Count viewTotalCount, Count voteTotalCount, - Count commentTotalCount, Count popularScore, Member member) { - return Pick.builder() - .title(title) - .contentStatus(contentStatus) - .viewTotalCount(viewTotalCount) - .voteTotalCount(voteTotalCount) - .commentTotalCount(commentTotalCount) - .popularScore(popularScore) - .member(member) - .build(); - } - - private PickComment createPickComment(CommentContents contents, Boolean isPublic, Count recommendTotalCount, - Member member, Pick pick) { - PickComment pickComment = PickComment.builder() - .contents(contents) - .isPublic(isPublic) - .createdBy(member) - .recommendTotalCount(recommendTotalCount) - .pick(pick) - .build(); - - pickComment.changePick(pick); - - return pickComment; - } - - private PickCommentRecommend createPickCommentRecommend(PickComment pickComment, Member member, - Boolean recommendedStatus) { - PickCommentRecommend pickCommentRecommend = PickCommentRecommend.builder() - .member(member) - .recommendedStatus(recommendedStatus) - .build(); - - pickCommentRecommend.changePickComment(pickComment); - - return pickCommentRecommend; - } - - private Pick createPick(Title title, ContentStatus contentStatus, Count commentTotalCount, Member member) { - return Pick.builder() - .title(title) - .contentStatus(contentStatus) - .commentTotalCount(commentTotalCount) - .member(member) - .build(); - } - - private PickComment createPickComment(CommentContents contents, Boolean isPublic, Count replyTotalCount, - Count recommendTotalCount, Member member, Pick pick, PickVote pickVote) { - PickComment pickComment = PickComment.builder() - .contents(contents) - .isPublic(isPublic) - .createdBy(member) - .replyTotalCount(replyTotalCount) - .recommendTotalCount(recommendTotalCount) - .pick(pick) - .pickVote(pickVote) - .build(); - - pickComment.changePick(pick); - - return pickComment; - } - - private PickComment createReplidPickComment(CommentContents contents, Member member, Pick pick, - PickComment originParent, PickComment parent) { - PickComment pickComment = PickComment.builder() - .contents(contents) - .createdBy(member) - .pick(pick) - .originParent(originParent) - .isPublic(false) - .parent(parent) - .recommendTotalCount(new Count(0)) - .replyTotalCount(new Count(0)) - .build(); - - pickComment.changePick(pick); - - return pickComment; - } - - private PickComment createPickComment(CommentContents contents, Boolean isPublic, Member member, Pick pick) { - PickComment pickComment = PickComment.builder() - .contents(contents) - .isPublic(isPublic) - .createdBy(member) - .replyTotalCount(new Count(0)) - .pick(pick) - .build(); - - pickComment.changePick(pick); - - return pickComment; - } - - private Pick createPick(Title title, ContentStatus contentStatus, Member member) { - return Pick.builder() - .title(title) - .contentStatus(contentStatus) - .member(member) - .build(); - } - - private PickOption createPickOption(Title title, Count voteTotalCount, Pick pick, PickOptionType pickOptionType) { - PickOption pickOption = PickOption.builder() - .title(title) - .voteTotalCount(voteTotalCount) - .pickOptionType(pickOptionType) - .build(); - - pickOption.changePick(pick); - - return pickOption; - } - - private Pick createPick(Title title, Count viewTotalCount, Count commentTotalCount, Count voteTotalCount, - Count poplarScore, Member member, ContentStatus contentStatus) { - return Pick.builder() - .title(title) - .viewTotalCount(viewTotalCount) - .voteTotalCount(voteTotalCount) - .commentTotalCount(commentTotalCount) - .popularScore(poplarScore) - .member(member) - .contentStatus(contentStatus) - .build(); - } - - private ModifyPickRequest createModifyPickRequest(String pickTitle, - Map modifyPickOptionRequests) { - return ModifyPickRequest.builder() - .pickTitle(pickTitle) - .pickOptions(modifyPickOptionRequests) - .build(); - } - - private PickOptionImage createPickOptionImage(String name, String imageUrl, String imageKey) { - return PickOptionImage.builder() - .name(name) - .imageUrl(imageUrl) - .imageKey(imageKey) - .build(); - } - - private PickOptionImage createPickOptionImage(String name) { - return PickOptionImage.builder() - .name(name) - .imageUrl("imageUrl") - .imageKey("imageKey") - .build(); - } - - private PickOptionImage createPickOptionImage(String name, String imageUrl, PickOption pickOption) { - PickOptionImage pickOptionImage = PickOptionImage.builder() - .name(name) - .imageUrl(imageUrl) - .imageKey("imageKey") - .build(); - - pickOptionImage.changePickOption(pickOption); - - return pickOptionImage; - } - - private PickOptionImage createPickOptionImage(String name, PickOption pickOption) { - PickOptionImage pickOptionImage = PickOptionImage.builder() - .name(name) - .imageUrl("imageUrl") - .imageKey("imageKey") - .build(); - - pickOptionImage.changePickOption(pickOption); - - return pickOptionImage; - } - - private RegisterPickRequest createPickRegisterRequest(String pickTitle, - Map pickOptions) { - return RegisterPickRequest.builder() - .pickTitle(pickTitle) - .pickOptions(pickOptions) - .build(); - } - - private RegisterPickOptionRequest createPickOptionRequest(String pickOptionTitle, String pickOptionContent, - List pickOptionImageIds) { - return RegisterPickOptionRequest.builder() - .pickOptionTitle(pickOptionTitle) - .pickOptionContent(pickOptionContent) - .pickOptionImageIds(pickOptionImageIds) - .build(); - } - - private MockMultipartFile createMockMultipartFile(String name, String originalFilename) { - return new MockMultipartFile( - name, - originalFilename, - MediaType.IMAGE_PNG_VALUE, - name.getBytes() - ); - } - - private SocialMemberDto createSocialDto(String userId, String name, String nickName, String password, String email, - String socialType, String role) { - return SocialMemberDto.builder() - .userId(userId) - .name(name) - .nickname(nickName) - .password(password) - .email(email) - .socialType(SocialType.valueOf(socialType)) - .role(Role.valueOf(role)) - .build(); - } - - private Pick createPick(Title title, Member member) { - return Pick.builder() - .title(title) - .member(member) - .build(); - } - - private Pick createPick(Title title, Count pickVoteTotalCount, Count pickViewTotalCount, - Count pickcommentTotalCount, Count pickPopularScore, String thumbnailUrl, - String author, ContentStatus contentStatus - ) { - - return Pick.builder() - .title(title) - .voteTotalCount(pickVoteTotalCount) - .viewTotalCount(pickViewTotalCount) - .commentTotalCount(pickcommentTotalCount) - .popularScore(pickPopularScore) - .thumbnailUrl(thumbnailUrl) - .author(author) - .contentStatus(contentStatus) - .build(); - } - - private Pick createPick(Title title, Count pickVoteTotalCount, Count pickViewTotalCount, - Count pickcommentTotalCount, String thumbnailUrl, String author, - ContentStatus contentStatus, - List pickVotes - ) { - - Pick pick = Pick.builder() - .title(title) - .voteTotalCount(pickVoteTotalCount) - .viewTotalCount(pickViewTotalCount) - .commentTotalCount(pickcommentTotalCount) - .thumbnailUrl(thumbnailUrl) - .author(author) - .contentStatus(contentStatus) - .build(); - - pick.changePickVote(pickVotes); - - return pick; - } - - private PickOption createPickOption(Pick pick, Title title, PickOptionContents pickOptionContents, - Count voteTotalCount, PickOptionType pickOptionType) { - PickOption pickOption = PickOption.builder() - .title(title) - .contents(pickOptionContents) - .voteTotalCount(voteTotalCount) - .pickOptionType(pickOptionType) - .build(); - - pickOption.changePick(pick); - - return pickOption; - } - - private PickOption createPickOption(Pick pick, Title title, PickOptionContents pickOptionContents, - PickOptionType pickOptionType) { - PickOption pickOption = PickOption.builder() - .title(title) - .pickOptionType(pickOptionType) - .contents(pickOptionContents) - .pick(pick) - .build(); - - pickOption.changePick(pick); - - return pickOption; - } - - private PickOption createPickOption(Pick pick, Title title, PickOptionContents pickOptionContents, - Count pickOptionVoteCount) { - PickOption pickOption = PickOption.builder() - .title(title) - .contents(pickOptionContents) - .voteTotalCount(pickOptionVoteCount) - .build(); - - pickOption.changePick(pick); - - return pickOption; - } - - private PickOption createPickOption(Title title, PickOptionContents pickOptionContents, - PickOptionType pickOptionType) { - return PickOption.builder() - .title(title) - .contents(pickOptionContents) - .pickOptionType(pickOptionType) - .build(); - } - - private PickVote createPickVote(Member member, PickOption pickOption, Pick pick) { - PickVote pickVote = PickVote.builder() - .member(member) - .build(); - - pickVote.changePickOption(pickOption); - pickVote.changePick(pick); - - return pickVote; - } } \ No newline at end of file diff --git a/src/test/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/GuestTechCommentServiceTest.java b/src/test/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/GuestTechCommentServiceTest.java index eade4b29..7aaf1e6f 100644 --- a/src/test/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/GuestTechCommentServiceTest.java +++ b/src/test/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/GuestTechCommentServiceTest.java @@ -1,18 +1,28 @@ package com.dreamypatisiel.devdevdev.domain.service.techArticle; +import static com.dreamypatisiel.devdevdev.domain.exception.GuestExceptionMessage.INVALID_ANONYMOUS_CAN_NOT_USE_THIS_FUNCTION_MESSAGE; +import static com.dreamypatisiel.devdevdev.domain.service.techArticle.TechTestUtils.createCompany; +import static com.dreamypatisiel.devdevdev.domain.service.techArticle.TechTestUtils.createMainTechComment; +import static com.dreamypatisiel.devdevdev.domain.service.techArticle.TechTestUtils.createRepliedTechComment; +import static com.dreamypatisiel.devdevdev.domain.service.techArticle.TechTestUtils.createSocialDto; +import static com.dreamypatisiel.devdevdev.domain.service.techArticle.TechTestUtils.createTechCommentRecommend; +import static com.dreamypatisiel.devdevdev.global.utils.AuthenticationMemberUtils.INVALID_METHODS_CALL_MESSAGE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.dreamypatisiel.devdevdev.domain.entity.Company; import com.dreamypatisiel.devdevdev.domain.entity.Member; import com.dreamypatisiel.devdevdev.domain.entity.TechArticle; import com.dreamypatisiel.devdevdev.domain.entity.TechComment; import com.dreamypatisiel.devdevdev.domain.entity.TechCommentRecommend; import com.dreamypatisiel.devdevdev.domain.entity.embedded.CommentContents; -import com.dreamypatisiel.devdevdev.domain.entity.embedded.CompanyName; import com.dreamypatisiel.devdevdev.domain.entity.embedded.Count; import com.dreamypatisiel.devdevdev.domain.entity.embedded.Title; import com.dreamypatisiel.devdevdev.domain.entity.embedded.Url; import com.dreamypatisiel.devdevdev.domain.entity.enums.Role; import com.dreamypatisiel.devdevdev.domain.entity.enums.SocialType; -import static com.dreamypatisiel.devdevdev.domain.exception.GuestExceptionMessage.INVALID_ANONYMOUS_CAN_NOT_USE_THIS_FUNCTION_MESSAGE; import com.dreamypatisiel.devdevdev.domain.repository.CompanyRepository; import com.dreamypatisiel.devdevdev.domain.repository.member.MemberRepository; import com.dreamypatisiel.devdevdev.domain.repository.techArticle.TechArticleRepository; @@ -24,7 +34,6 @@ import com.dreamypatisiel.devdevdev.global.security.oauth2.model.SocialMemberDto; import com.dreamypatisiel.devdevdev.global.security.oauth2.model.UserPrincipal; import com.dreamypatisiel.devdevdev.global.utils.AuthenticationMemberUtils; -import static com.dreamypatisiel.devdevdev.global.utils.AuthenticationMemberUtils.INVALID_METHODS_CALL_MESSAGE; import com.dreamypatisiel.devdevdev.web.dto.SliceCommentCustom; import com.dreamypatisiel.devdevdev.web.dto.request.techArticle.RegisterTechCommentRequest; import com.dreamypatisiel.devdevdev.web.dto.response.techArticle.TechCommentsResponse; @@ -33,13 +42,9 @@ import jakarta.persistence.EntityManager; import java.time.LocalDateTime; import java.util.List; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; import org.assertj.core.groups.Tuple; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.domain.PageRequest; @@ -246,7 +251,7 @@ techArticle, originParentTechComment2, originParentTechComment2, new Count(0L), // when SliceCommentCustom response = guestTechCommentService.getTechComments(techArticleId, - null, TechCommentSort.OLDEST, pageable, authentication); + null, TechCommentSort.OLDEST, pageable, null, authentication); // then assertThat(response.getTotalOriginParentComments()).isEqualTo(6L); @@ -540,7 +545,7 @@ techArticle, originParentTechComment2, originParentTechComment2, new Count(0L), // when SliceCommentCustom response = guestTechCommentService.getTechComments(techArticleId, - null, TechCommentSort.LATEST, pageable, authentication); + null, TechCommentSort.LATEST, pageable, null, authentication); // then assertThat(response.getTotalOriginParentComments()).isEqualTo(6L); @@ -709,7 +714,7 @@ techArticle, originParentTechComment4, originParentTechComment4, new Count(0L), // when SliceCommentCustom response = guestTechCommentService.getTechComments(techArticleId, - null, TechCommentSort.MOST_COMMENTED, pageable, authentication); + null, TechCommentSort.MOST_COMMENTED, pageable, null, authentication); // then assertThat(response.getTotalOriginParentComments()).isEqualTo(6L); @@ -983,7 +988,7 @@ void getTechCommentsSortByMostRecommended() { // when SliceCommentCustom response = guestTechCommentService.getTechComments(techArticleId, - null, TechCommentSort.MOST_LIKED, pageable, authentication); + null, TechCommentSort.MOST_LIKED, pageable, null, authentication); // then assertThat(response.getTotalOriginParentComments()).isEqualTo(6L); @@ -1132,7 +1137,7 @@ void getTechCommentsByCursor() { // when SliceCommentCustom response = guestTechCommentService.getTechComments(techArticleId, - originParentTechComment6.getId(), null, pageable, authentication); + originParentTechComment6.getId(), null, pageable, null, authentication); // then assertThat(response.getTotalOriginParentComments()).isEqualTo(5L); // 삭제된 댓글은 카운트하지 않는다 @@ -1249,7 +1254,7 @@ void findTechBestCommentsNotAnonymousMember() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); // when // then - assertThatThrownBy(() -> guestTechCommentService.findTechBestComments(3, 1L, authentication)) + assertThatThrownBy(() -> guestTechCommentService.findTechBestComments(3, 1L, null, authentication)) .isInstanceOf(IllegalStateException.class) .hasMessage(INVALID_METHODS_CALL_MESSAGE); } @@ -1306,7 +1311,7 @@ techArticle, originParentTechComment1, originParentTechComment1, new Count(0L), Authentication authentication = mock(Authentication.class); when(authentication.getPrincipal()).thenReturn(AuthenticationMemberUtils.ANONYMOUS_USER); - List response = guestTechCommentService.findTechBestComments(3, techArticle.getId(), + List response = guestTechCommentService.findTechBestComments(3, techArticle.getId(), null, authentication); // then @@ -1399,71 +1404,4 @@ techArticle, originParentTechComment1, originParentTechComment1, new Count(0L), ) ); } - - private TechCommentRecommend createTechCommentRecommend(Boolean recommendedStatus, TechComment techComment, - Member member) { - TechCommentRecommend techCommentRecommend = TechCommentRecommend.builder() - .recommendedStatus(recommendedStatus) - .techComment(techComment) - .member(member) - .build(); - - techCommentRecommend.changeTechComment(techComment); - - return techCommentRecommend; - } - - private static TechComment createMainTechComment(CommentContents contents, Member createdBy, - TechArticle techArticle, - Count blameTotalCount, Count recommendTotalCount, - Count replyTotalCount) { - return TechComment.builder() - .contents(contents) - .createdBy(createdBy) - .techArticle(techArticle) - .blameTotalCount(blameTotalCount) - .recommendTotalCount(recommendTotalCount) - .replyTotalCount(replyTotalCount) - .build(); - } - - private static TechComment createRepliedTechComment(CommentContents contents, Member createdBy, - TechArticle techArticle, - TechComment originParent, TechComment parent, - Count blameTotalCount, Count recommendTotalCount, - Count replyTotalCount) { - return TechComment.builder() - .contents(contents) - .createdBy(createdBy) - .techArticle(techArticle) - .blameTotalCount(blameTotalCount) - .recommendTotalCount(recommendTotalCount) - .replyTotalCount(replyTotalCount) - .originParent(originParent) - .parent(parent) - .build(); - } - - private SocialMemberDto createSocialDto(String userId, String name, String nickName, String password, String email, - String socialType, String role) { - return SocialMemberDto.builder() - .userId(userId) - .name(name) - .nickname(nickName) - .password(password) - .email(email) - .socialType(SocialType.valueOf(socialType)) - .role(Role.valueOf(role)) - .build(); - } - - private static Company createCompany(String companyName, String officialImageUrl, String officialUrl, - String careerUrl) { - return Company.builder() - .name(new CompanyName(companyName)) - .officialUrl(new Url(officialUrl)) - .careerUrl(new Url(careerUrl)) - .officialImageUrl(new Url(officialImageUrl)) - .build(); - } } diff --git a/src/test/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/MemberTechCommentServiceTest.java b/src/test/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/MemberTechCommentServiceTest.java index 6b2ed657..7bdbed6d 100644 --- a/src/test/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/MemberTechCommentServiceTest.java +++ b/src/test/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/MemberTechCommentServiceTest.java @@ -5,6 +5,11 @@ import static com.dreamypatisiel.devdevdev.domain.exception.TechArticleExceptionMessage.INVALID_CAN_NOT_REPLY_DELETED_TECH_COMMENT_MESSAGE; import static com.dreamypatisiel.devdevdev.domain.exception.TechArticleExceptionMessage.INVALID_NOT_FOUND_TECH_COMMENT_MESSAGE; import static com.dreamypatisiel.devdevdev.domain.exception.TechArticleExceptionMessage.NOT_FOUND_TECH_ARTICLE_MESSAGE; +import static com.dreamypatisiel.devdevdev.domain.service.techArticle.TechTestUtils.createCompany; +import static com.dreamypatisiel.devdevdev.domain.service.techArticle.TechTestUtils.createMainTechComment; +import static com.dreamypatisiel.devdevdev.domain.service.techArticle.TechTestUtils.createRepliedTechComment; +import static com.dreamypatisiel.devdevdev.domain.service.techArticle.TechTestUtils.createSocialDto; +import static com.dreamypatisiel.devdevdev.domain.service.techArticle.TechTestUtils.createTechCommentRecommend; import static com.dreamypatisiel.devdevdev.global.common.MemberProvider.INVALID_ANONYMOUS_CAN_NOT_USE_THIS_FUNCTION_MESSAGE; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -18,7 +23,6 @@ import com.dreamypatisiel.devdevdev.domain.entity.TechComment; import com.dreamypatisiel.devdevdev.domain.entity.TechCommentRecommend; import com.dreamypatisiel.devdevdev.domain.entity.embedded.CommentContents; -import com.dreamypatisiel.devdevdev.domain.entity.embedded.CompanyName; import com.dreamypatisiel.devdevdev.domain.entity.embedded.Count; import com.dreamypatisiel.devdevdev.domain.entity.embedded.Title; import com.dreamypatisiel.devdevdev.domain.entity.embedded.Url; @@ -894,7 +898,7 @@ techArticle, originParentTechComment2, originParentTechComment2, new Count(0L), // when SliceCommentCustom response = memberTechCommentService.getTechComments(techArticleId, - null, TechCommentSort.OLDEST, pageable, authentication); + null, TechCommentSort.OLDEST, pageable, null, authentication); // then assertThat(response.getTotalOriginParentComments()).isEqualTo(6L); @@ -1191,7 +1195,7 @@ techArticle, originParentTechComment2, originParentTechComment2, new Count(0L), // when SliceCommentCustom response = memberTechCommentService.getTechComments(techArticleId, - null, TechCommentSort.LATEST, pageable, authentication); + null, TechCommentSort.LATEST, pageable, null, authentication); // then assertThat(response.getTotalOriginParentComments()).isEqualTo(6L); @@ -1363,7 +1367,7 @@ techArticle, originParentTechComment4, originParentTechComment4, new Count(0L), // when SliceCommentCustom response = memberTechCommentService.getTechComments(techArticleId, - null, TechCommentSort.MOST_COMMENTED, pageable, authentication); + null, TechCommentSort.MOST_COMMENTED, pageable, null, authentication); // then assertThat(response.getTotalOriginParentComments()).isEqualTo(6L); @@ -1640,7 +1644,7 @@ void getTechCommentsSortByMostRecommended() { // when SliceCommentCustom response = memberTechCommentService.getTechComments(techArticleId, - null, TechCommentSort.MOST_LIKED, pageable, authentication); + null, TechCommentSort.MOST_LIKED, pageable, null, authentication); // then assertThat(response.getTotalOriginParentComments()).isEqualTo(6L); @@ -1793,7 +1797,7 @@ void getTechCommentsByCursor() { // when SliceCommentCustom response = memberTechCommentService.getTechComments(techArticleId, - originParentTechComment6.getId(), null, pageable, authentication); + originParentTechComment6.getId(), null, pageable, null, authentication); // then assertThat(response.getTotalOriginParentComments()).isEqualTo(5L); // 삭제된 댓글은 카운트하지 않는다 @@ -2084,7 +2088,7 @@ void findTechBestCommentsNotAnonymousMember() { when(authentication.getPrincipal()).thenReturn(AuthenticationMemberUtils.ANONYMOUS_USER); // when // then - assertThatThrownBy(() -> memberTechCommentService.findTechBestComments(3, 0L, authentication)) + assertThatThrownBy(() -> memberTechCommentService.findTechBestComments(3, 0L, null, authentication)) .isInstanceOf(IllegalStateException.class) .hasMessage(INVALID_ANONYMOUS_CAN_NOT_USE_THIS_FUNCTION_MESSAGE); } @@ -2145,7 +2149,7 @@ techArticle, originParentTechComment1, originParentTechComment1, new Count(0L), techCommentRepository.save(repliedTechComment); // when - List response = memberTechCommentService.findTechBestComments(3, techArticle.getId(), + List response = memberTechCommentService.findTechBestComments(3, techArticle.getId(), null, authentication); // then @@ -2296,7 +2300,7 @@ techArticle, originParentTechComment1, originParentTechComment1, new Count(0L), // when List response = memberTechCommentService.findTechBestComments(3, techArticle.getId(), - authentication); + null, authentication); // then assertThat(response).hasSize(1) @@ -2364,71 +2368,4 @@ techArticle, originParentTechComment1, originParentTechComment1, new Count(0L), ) ); } - - private TechCommentRecommend createTechCommentRecommend(Boolean recommendedStatus, TechComment techComment, - Member member) { - TechCommentRecommend techCommentRecommend = TechCommentRecommend.builder() - .recommendedStatus(recommendedStatus) - .techComment(techComment) - .member(member) - .build(); - - techCommentRecommend.changeTechComment(techComment); - - return techCommentRecommend; - } - - private static TechComment createMainTechComment(CommentContents contents, Member createdBy, - TechArticle techArticle, - Count blameTotalCount, Count recommendTotalCount, - Count replyTotalCount) { - return TechComment.builder() - .contents(contents) - .createdBy(createdBy) - .techArticle(techArticle) - .blameTotalCount(blameTotalCount) - .recommendTotalCount(recommendTotalCount) - .replyTotalCount(replyTotalCount) - .build(); - } - - private static TechComment createRepliedTechComment(CommentContents contents, Member createdBy, - TechArticle techArticle, - TechComment originParent, TechComment parent, - Count blameTotalCount, Count recommendTotalCount, - Count replyTotalCount) { - return TechComment.builder() - .contents(contents) - .createdBy(createdBy) - .techArticle(techArticle) - .blameTotalCount(blameTotalCount) - .recommendTotalCount(recommendTotalCount) - .replyTotalCount(replyTotalCount) - .originParent(originParent) - .parent(parent) - .build(); - } - - private SocialMemberDto createSocialDto(String userId, String name, String nickName, String password, String email, - String socialType, String role) { - return SocialMemberDto.builder() - .userId(userId) - .name(name) - .nickname(nickName) - .password(password) - .email(email) - .socialType(SocialType.valueOf(socialType)) - .role(Role.valueOf(role)) - .build(); - } - - private static Company createCompany(String companyName, String officialImageUrl, String officialUrl, - String careerUrl) { - return Company.builder() - .name(new CompanyName(companyName)) - .officialUrl(new Url(officialUrl)) - .careerUrl(new Url(careerUrl)) - .officialImageUrl(new Url(officialImageUrl)) - .build(); - } } diff --git a/src/test/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/TechTestUtils.java b/src/test/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/TechTestUtils.java new file mode 100644 index 00000000..09789824 --- /dev/null +++ b/src/test/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/TechTestUtils.java @@ -0,0 +1,112 @@ +package com.dreamypatisiel.devdevdev.domain.service.techArticle; + +import com.dreamypatisiel.devdevdev.domain.entity.AnonymousMember; +import com.dreamypatisiel.devdevdev.domain.entity.Company; +import com.dreamypatisiel.devdevdev.domain.entity.Member; +import com.dreamypatisiel.devdevdev.domain.entity.TechArticle; +import com.dreamypatisiel.devdevdev.domain.entity.TechComment; +import com.dreamypatisiel.devdevdev.domain.entity.TechCommentRecommend; +import com.dreamypatisiel.devdevdev.domain.entity.embedded.CommentContents; +import com.dreamypatisiel.devdevdev.domain.entity.embedded.CompanyName; +import com.dreamypatisiel.devdevdev.domain.entity.embedded.Count; +import com.dreamypatisiel.devdevdev.domain.entity.embedded.Url; +import com.dreamypatisiel.devdevdev.domain.entity.enums.Role; +import com.dreamypatisiel.devdevdev.domain.entity.enums.SocialType; +import com.dreamypatisiel.devdevdev.global.security.oauth2.model.SocialMemberDto; + +public class TechTestUtils { + + public static TechCommentRecommend createTechCommentRecommend(Boolean recommendedStatus, TechComment techComment, + Member member) { + TechCommentRecommend techCommentRecommend = TechCommentRecommend.builder() + .recommendedStatus(recommendedStatus) + .techComment(techComment) + .member(member) + .build(); + + techCommentRecommend.changeTechComment(techComment); + + return techCommentRecommend; + } + + public static TechComment createMainTechComment(CommentContents contents, Member createdBy, TechArticle techArticle, + Count blameTotalCount, Count recommendTotalCount, Count replyTotalCount) { + return TechComment.builder() + .contents(contents) + .createdBy(createdBy) + .techArticle(techArticle) + .blameTotalCount(blameTotalCount) + .recommendTotalCount(recommendTotalCount) + .replyTotalCount(replyTotalCount) + .build(); + } + + public static TechComment createMainTechComment(CommentContents contents, AnonymousMember createdAnonymousBy, + TechArticle techArticle, Count blameTotalCount, Count recommendTotalCount, + Count replyTotalCount) { + return TechComment.builder() + .contents(contents) + .createdAnonymousBy(createdAnonymousBy) + .techArticle(techArticle) + .blameTotalCount(blameTotalCount) + .recommendTotalCount(recommendTotalCount) + .replyTotalCount(replyTotalCount) + .build(); + } + + public static TechComment createRepliedTechComment(CommentContents contents, Member createdBy, + TechArticle techArticle, + TechComment originParent, TechComment parent, + Count blameTotalCount, Count recommendTotalCount, + Count replyTotalCount) { + return TechComment.builder() + .contents(contents) + .createdBy(createdBy) + .techArticle(techArticle) + .blameTotalCount(blameTotalCount) + .recommendTotalCount(recommendTotalCount) + .replyTotalCount(replyTotalCount) + .originParent(originParent) + .parent(parent) + .build(); + } + + public static TechComment createRepliedTechComment(CommentContents contents, AnonymousMember createdAnonymousBy, + TechArticle techArticle, TechComment originParent, TechComment parent, + Count blameTotalCount, Count recommendTotalCount, + Count replyTotalCount) { + return TechComment.builder() + .contents(contents) + .createdAnonymousBy(createdAnonymousBy) + .techArticle(techArticle) + .blameTotalCount(blameTotalCount) + .recommendTotalCount(recommendTotalCount) + .replyTotalCount(replyTotalCount) + .originParent(originParent) + .parent(parent) + .build(); + } + + public static SocialMemberDto createSocialDto(String userId, String name, String nickName, String password, String email, + String socialType, String role) { + return SocialMemberDto.builder() + .userId(userId) + .name(name) + .nickname(nickName) + .password(password) + .email(email) + .socialType(SocialType.valueOf(socialType)) + .role(Role.valueOf(role)) + .build(); + } + + public static Company createCompany(String companyName, String officialImageUrl, String officialUrl, + String careerUrl) { + return Company.builder() + .name(new CompanyName(companyName)) + .officialUrl(new Url(officialUrl)) + .careerUrl(new Url(careerUrl)) + .officialImageUrl(new Url(officialImageUrl)) + .build(); + } +} diff --git a/src/test/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/techComment/GuestTechCommentServiceV2Test.java b/src/test/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/techComment/GuestTechCommentServiceV2Test.java new file mode 100644 index 00000000..b8460ce0 --- /dev/null +++ b/src/test/java/com/dreamypatisiel/devdevdev/domain/service/techArticle/techComment/GuestTechCommentServiceV2Test.java @@ -0,0 +1,1396 @@ +package com.dreamypatisiel.devdevdev.domain.service.techArticle.techComment; + +import static com.dreamypatisiel.devdevdev.domain.service.techArticle.TechTestUtils.createCompany; +import static com.dreamypatisiel.devdevdev.domain.service.techArticle.TechTestUtils.createMainTechComment; +import static com.dreamypatisiel.devdevdev.domain.service.techArticle.TechTestUtils.createRepliedTechComment; +import static com.dreamypatisiel.devdevdev.domain.service.techArticle.TechTestUtils.createSocialDto; +import static com.dreamypatisiel.devdevdev.domain.service.techArticle.TechTestUtils.createTechCommentRecommend; +import static com.dreamypatisiel.devdevdev.global.utils.AuthenticationMemberUtils.INVALID_METHODS_CALL_MESSAGE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.dreamypatisiel.devdevdev.domain.entity.AnonymousMember; +import com.dreamypatisiel.devdevdev.domain.entity.Company; +import com.dreamypatisiel.devdevdev.domain.entity.Member; +import com.dreamypatisiel.devdevdev.domain.entity.TechArticle; +import com.dreamypatisiel.devdevdev.domain.entity.TechComment; +import com.dreamypatisiel.devdevdev.domain.entity.TechCommentRecommend; +import com.dreamypatisiel.devdevdev.domain.entity.embedded.CommentContents; +import com.dreamypatisiel.devdevdev.domain.entity.embedded.Count; +import com.dreamypatisiel.devdevdev.domain.entity.embedded.Title; +import com.dreamypatisiel.devdevdev.domain.entity.embedded.Url; +import com.dreamypatisiel.devdevdev.domain.entity.enums.Role; +import com.dreamypatisiel.devdevdev.domain.entity.enums.SocialType; +import com.dreamypatisiel.devdevdev.domain.repository.CompanyRepository; +import com.dreamypatisiel.devdevdev.domain.repository.member.AnonymousMemberRepository; +import com.dreamypatisiel.devdevdev.domain.repository.member.MemberRepository; +import com.dreamypatisiel.devdevdev.domain.repository.techArticle.TechArticleRepository; +import com.dreamypatisiel.devdevdev.domain.repository.techArticle.TechCommentRecommendRepository; +import com.dreamypatisiel.devdevdev.domain.repository.techArticle.TechCommentRepository; +import com.dreamypatisiel.devdevdev.domain.repository.techArticle.TechCommentSort; +import com.dreamypatisiel.devdevdev.global.common.TimeProvider; +import com.dreamypatisiel.devdevdev.global.security.oauth2.model.SocialMemberDto; +import com.dreamypatisiel.devdevdev.global.security.oauth2.model.UserPrincipal; +import com.dreamypatisiel.devdevdev.global.utils.AuthenticationMemberUtils; +import com.dreamypatisiel.devdevdev.web.dto.SliceCommentCustom; +import com.dreamypatisiel.devdevdev.web.dto.response.techArticle.TechCommentsResponse; +import com.dreamypatisiel.devdevdev.web.dto.response.techArticle.TechRepliedCommentsResponse; +import com.dreamypatisiel.devdevdev.web.dto.util.CommonResponseUtil; +import jakarta.persistence.EntityManager; +import java.time.LocalDateTime; +import java.util.List; +import org.assertj.core.groups.Tuple; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.transaction.annotation.Transactional; + +@SpringBootTest +@Transactional +class GuestTechCommentServiceV2Test { + + @Autowired + GuestTechCommentServiceV2 guestTechCommentServiceV2; + @Autowired + TechArticleRepository techArticleRepository; + @Autowired + TechCommentRepository techCommentRepository; + @Autowired + CompanyRepository companyRepository; + @Autowired + MemberRepository memberRepository; + @Autowired + TechCommentRecommendRepository techCommentRecommendRepository; + @Autowired + AnonymousMemberRepository anonymousMemberRepository; + @Autowired + TimeProvider timeProvider; + @Autowired + EntityManager em; + + String userId = "dreamy5patisiel"; + String name = "꿈빛파티시엘"; + String nickname = "행복한 꿈빛파티시엘"; + String email = "dreamy5patisiel@kakao.com"; + String password = "password"; + String socialType = SocialType.KAKAO.name(); + String role = Role.ROLE_USER.name(); + String author = "운영자"; + + @Test + @DisplayName("익명 회원은 커서 방식으로 기술블로그 댓글/답글을 조회할 수 있다. (등록순)") + void getTechCommentsSortByOLDEST() { + // given + // 회원 생성 + SocialMemberDto socialMemberDto = createSocialDto(userId, name, nickname, password, email, socialType, role); + Member member = Member.createMemberBy(socialMemberDto); + memberRepository.save(member); + + // 익명회원 생성 + AnonymousMember anonymousMember = AnonymousMember.create("anonymousMemberId", "익명으로 개발하는 댑댑이"); + anonymousMemberRepository.save(anonymousMember); + + Authentication authentication = mock(Authentication.class); + when(authentication.getPrincipal()).thenReturn(AuthenticationMemberUtils.ANONYMOUS_USER); + + // 회사 생성 + Company company = createCompany("꿈빛 파티시엘", "https://example.com/company.png", "https://example.com", + "https://example.com"); + companyRepository.save(company); + + // 기술블로그 생성 + TechArticle techArticle = TechArticle.createTechArticle(new Title("기술블로그 제목"), new Url("https://example.com"), + new Count(1L), new Count(1L), new Count(12L), new Count(1L), null, company); + techArticleRepository.save(techArticle); + Long techArticleId = techArticle.getId(); + + TechComment originParentTechComment1 = createMainTechComment(new CommentContents("최상위 댓글1"), anonymousMember, techArticle, + new Count(0L), new Count(0L), new Count(0L)); + TechComment originParentTechComment2 = createMainTechComment(new CommentContents("최상위 댓글2"), member, techArticle, + new Count(0L), new Count(0L), new Count(0L)); + TechComment originParentTechComment3 = createMainTechComment(new CommentContents("최상위 댓글3"), member, techArticle, + new Count(0L), new Count(0L), new Count(0L)); + TechComment originParentTechComment4 = createMainTechComment(new CommentContents("최상위 댓글4"), member, techArticle, + new Count(0L), new Count(0L), new Count(0L)); + TechComment originParentTechComment5 = createMainTechComment(new CommentContents("최상위 댓글5"), member, techArticle, + new Count(0L), new Count(0L), new Count(0L)); + TechComment originParentTechComment6 = createMainTechComment(new CommentContents("최상위 댓글6"), member, techArticle, + new Count(0L), new Count(0L), new Count(0L)); + + TechComment parentTechComment1 = createRepliedTechComment(new CommentContents("최상위 댓글1의 답글1"), anonymousMember, + techArticle, originParentTechComment1, originParentTechComment1, new Count(0L), new Count(0L), new Count(0L)); + TechComment parentTechComment2 = createRepliedTechComment(new CommentContents("최상위 댓글1의 답글2"), member, + techArticle, originParentTechComment1, originParentTechComment1, new Count(0L), new Count(0L), new Count(0L)); + TechComment parentTechComment3 = createRepliedTechComment(new CommentContents("최상위 댓글2의 답글1"), member, + techArticle, originParentTechComment2, originParentTechComment2, new Count(0L), new Count(0L), new Count(0L)); + TechComment parentTechComment4 = createRepliedTechComment(new CommentContents("최상위 댓글2의 답글2"), member, + techArticle, originParentTechComment2, originParentTechComment2, new Count(0L), new Count(0L), new Count(0L)); + + TechComment techcomment1 = createRepliedTechComment(new CommentContents("최상위 댓글1의 답글1의 답글"), member, + techArticle, originParentTechComment1, parentTechComment1, new Count(0L), new Count(0L), new Count(0L)); + TechComment techcomment2 = createRepliedTechComment(new CommentContents("최상위 댓글1의 답글2의 답글"), member, + techArticle, originParentTechComment1, parentTechComment2, new Count(0L), new Count(0L), new Count(0L)); + + techCommentRepository.saveAll(List.of( + originParentTechComment1, originParentTechComment2, originParentTechComment3, + originParentTechComment4, originParentTechComment5, originParentTechComment6, + parentTechComment1, parentTechComment2, parentTechComment3, parentTechComment4, + techcomment1, techcomment2 + )); + + Pageable pageable = PageRequest.of(0, 5); + + em.flush(); + em.clear(); + + // when + SliceCommentCustom response = guestTechCommentServiceV2.getTechComments(techArticleId, + null, TechCommentSort.OLDEST, pageable, anonymousMember.getAnonymousMemberId(), authentication); + + // then + assertThat(response.getTotalOriginParentComments()).isEqualTo(6L); + assertThat(response).hasSizeLessThanOrEqualTo(pageable.getPageSize()) + .extracting( + "techCommentId", + "memberId", + "author", + "maskedEmail", + "contents", + "replyTotalCount", + "recommendTotalCount", + "isCommentAuthor", + "isRecommended", + "isModified", + "isDeleted", + "anonymousMemberId" + ) + .containsExactly( + Tuple.tuple(originParentTechComment1.getId(), + null, + anonymousMember.getNickname(), + null, + originParentTechComment1.getContents().getCommentContents(), + originParentTechComment1.getReplyTotalCount().getCount(), + originParentTechComment1.getRecommendTotalCount().getCount(), + true, + false, + false, + false, + anonymousMember.getId() + ), + Tuple.tuple(originParentTechComment2.getId(), + member.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + originParentTechComment2.getContents().getCommentContents(), + originParentTechComment2.getReplyTotalCount().getCount(), + originParentTechComment2.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null + ), + Tuple.tuple(originParentTechComment3.getId(), + member.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + originParentTechComment3.getContents().getCommentContents(), + originParentTechComment3.getReplyTotalCount().getCount(), + originParentTechComment3.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null + ), + Tuple.tuple(originParentTechComment4.getId(), + member.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + originParentTechComment4.getContents().getCommentContents(), + originParentTechComment4.getReplyTotalCount().getCount(), + originParentTechComment4.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null + ), + Tuple.tuple(originParentTechComment5.getId(), + member.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + originParentTechComment5.getContents().getCommentContents(), + originParentTechComment5.getReplyTotalCount().getCount(), + originParentTechComment5.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null + ) + ); + + TechCommentsResponse techCommentsResponse1 = response.getContent().get(0); + List replies1 = techCommentsResponse1.getReplies(); + assertThat(replies1).hasSize(4) + .extracting( + "techCommentId", + "memberId", + "techParentCommentId", + "techParentCommentMemberId", + "techParentCommentAuthor", + "techOriginParentCommentId", + "author", + "maskedEmail", + "contents", + "recommendTotalCount", + "isCommentAuthor", + "isRecommended", + "isModified", + "isDeleted", + "anonymousMemberId", + "techParentCommentAnonymousMemberId" + ) + .containsExactly( + Tuple.tuple(parentTechComment1.getId(), + null, + originParentTechComment1.getId(), + null, + anonymousMember.getNickname(), + originParentTechComment1.getId(), + anonymousMember.getNickname(), + null, + parentTechComment1.getContents().getCommentContents(), + parentTechComment1.getRecommendTotalCount().getCount(), + true, + false, + false, + false, + anonymousMember.getId(), + originParentTechComment1.getCreatedAnonymousBy().getId() + ), + Tuple.tuple(parentTechComment2.getId(), + member.getId(), + originParentTechComment1.getId(), + null, + anonymousMember.getNickname(), + originParentTechComment1.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + parentTechComment2.getContents().getCommentContents(), + parentTechComment2.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null, + originParentTechComment1.getCreatedAnonymousBy().getId() + ), + Tuple.tuple(techcomment1.getId(), + member.getId(), + parentTechComment1.getId(), + null, + anonymousMember.getNickname(), + originParentTechComment1.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + techcomment1.getContents().getCommentContents(), + techcomment1.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null, + originParentTechComment1.getCreatedAnonymousBy().getId() + ), + Tuple.tuple(techcomment2.getId(), + member.getId(), + parentTechComment2.getId(), + parentTechComment2.getCreatedBy().getId(), + member.getNicknameAsString(), + originParentTechComment1.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + techcomment2.getContents().getCommentContents(), + techcomment2.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null, + null + ) + ); + + TechCommentsResponse techCommentsResponse2 = response.getContent().get(1); + List replies2 = techCommentsResponse2.getReplies(); + assertThat(replies2).hasSize(2) + .extracting( + "techCommentId", + "memberId", + "techParentCommentId", + "techParentCommentMemberId", + "techParentCommentAuthor", + "techOriginParentCommentId", + "author", + "maskedEmail", + "contents", + "recommendTotalCount", + "isCommentAuthor", + "isRecommended", + "isModified", + "isDeleted", + "anonymousMemberId", + "techParentCommentAnonymousMemberId" + ) + .containsExactly( + Tuple.tuple(parentTechComment3.getId(), + member.getId(), + originParentTechComment2.getId(), + originParentTechComment2.getCreatedBy().getId(), + member.getNicknameAsString(), + originParentTechComment2.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + parentTechComment3.getContents().getCommentContents(), + parentTechComment3.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null, + null + ), + Tuple.tuple(parentTechComment4.getId(), + member.getId(), + originParentTechComment2.getId(), + originParentTechComment2.getCreatedBy().getId(), + member.getNicknameAsString(), + originParentTechComment2.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + parentTechComment4.getContents().getCommentContents(), + parentTechComment4.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null, + null + ) + ); + + TechCommentsResponse techCommentsResponse3 = response.getContent().get(2); + List replies3 = techCommentsResponse3.getReplies(); + assertThat(replies3).hasSize(0); + + TechCommentsResponse techCommentsResponse4 = response.getContent().get(3); + List replies4 = techCommentsResponse4.getReplies(); + assertThat(replies4).hasSize(0); + + TechCommentsResponse techCommentsResponse5 = response.getContent().get(4); + List replies5 = techCommentsResponse5.getReplies(); + assertThat(replies5).hasSize(0); + } + + @Test + @DisplayName("익명 회원은 커서 방식으로 기술블로그 댓글/답글을 조회할 수 있다. (기본 정렬은 최신순)") + void getTechCommentsSortByLATEST() { + // given + SocialMemberDto socialMemberDto = createSocialDto(userId, name, nickname, password, email, socialType, role); + Member member = Member.createMemberBy(socialMemberDto); + memberRepository.save(member); + + // 익명회원 생성 + AnonymousMember anonymousMember = AnonymousMember.create("anonymousMemberId", "익명으로 개발하는 댑댑이"); + anonymousMemberRepository.save(anonymousMember); + + Authentication authentication = mock(Authentication.class); + when(authentication.getPrincipal()).thenReturn(AuthenticationMemberUtils.ANONYMOUS_USER); + + Company company = createCompany("꿈빛 파티시엘", "https://example.com/company.png", "https://example.com", + "https://example.com"); + companyRepository.save(company); + + TechArticle techArticle = TechArticle.createTechArticle(new Title("기술블로그 제목"), new Url("https://example.com"), + new Count(1L), new Count(1L), new Count(12L), new Count(1L), null, company); + techArticleRepository.save(techArticle); + Long techArticleId = techArticle.getId(); + + TechComment originParentTechComment1 = createMainTechComment(new CommentContents("최상위 댓글1"), member, + techArticle, new Count(0L), new Count(0L), new Count(0L)); + TechComment originParentTechComment2 = createMainTechComment(new CommentContents("최상위 댓글2"), member, + techArticle, new Count(0L), new Count(0L), new Count(0L)); + TechComment originParentTechComment3 = createMainTechComment(new CommentContents("최상위 댓글3"), member, + techArticle, new Count(0L), new Count(0L), new Count(0L)); + TechComment originParentTechComment4 = createMainTechComment(new CommentContents("최상위 댓글4"), member, + techArticle, new Count(0L), new Count(0L), new Count(0L)); + TechComment originParentTechComment5 = createMainTechComment(new CommentContents("최상위 댓글5"), member, + techArticle, new Count(0L), new Count(0L), new Count(0L)); + TechComment originParentTechComment6 = createMainTechComment(new CommentContents("최상위 댓글6"), anonymousMember, + techArticle, new Count(0L), new Count(0L), new Count(0L)); + + TechComment parentTechComment1 = createRepliedTechComment(new CommentContents("최상위 댓글1의 답글1"), member, + techArticle, originParentTechComment1, originParentTechComment1, new Count(0L), new Count(0L), new Count(0L)); + TechComment parentTechComment2 = createRepliedTechComment(new CommentContents("최상위 댓글1의 답글2"), member, techArticle, + originParentTechComment1, originParentTechComment1, new Count(0L), new Count(0L), new Count(0L)); + TechComment parentTechComment3 = createRepliedTechComment(new CommentContents("최상위 댓글2의 답글1"), member, techArticle, + originParentTechComment2, originParentTechComment2, new Count(0L), new Count(0L), new Count(0L)); + TechComment parentTechComment4 = createRepliedTechComment(new CommentContents("최상위 댓글2의 답글2"), member, techArticle, + originParentTechComment2, originParentTechComment2, new Count(0L), new Count(0L), new Count(0L)); + + TechComment techcomment1 = createRepliedTechComment(new CommentContents("최상위 댓글1의 답글1의 답글"), member, + techArticle, originParentTechComment1, parentTechComment1, new Count(0L), new Count(0L), new Count(0L)); + TechComment techcomment2 = createRepliedTechComment(new CommentContents("최상위 댓글1의 답글2의 답글"), member, + techArticle, originParentTechComment1, parentTechComment2, new Count(0L), new Count(0L), new Count(0L)); + + techCommentRepository.saveAll(List.of( + originParentTechComment1, originParentTechComment2, originParentTechComment3, + originParentTechComment4, originParentTechComment5, originParentTechComment6, + parentTechComment1, parentTechComment2, parentTechComment3, parentTechComment4, + techcomment1, techcomment2 + )); + + Pageable pageable = PageRequest.of(0, 5); + + em.flush(); + em.clear(); + + // when + SliceCommentCustom response = guestTechCommentServiceV2.getTechComments(techArticleId, + null, TechCommentSort.LATEST, pageable, anonymousMember.getAnonymousMemberId(), authentication); + + // then + assertThat(response.getTotalOriginParentComments()).isEqualTo(6L); + assertThat(response).hasSizeLessThanOrEqualTo(pageable.getPageSize()) + .extracting( + "techCommentId", + "memberId", + "author", + "maskedEmail", + "contents", + "replyTotalCount", + "recommendTotalCount", + "isCommentAuthor", + "isRecommended", + "isModified", + "isDeleted", + "anonymousMemberId" + ) + .containsExactly( + Tuple.tuple(originParentTechComment6.getId(), + null, + anonymousMember.getNickname(), + null, + originParentTechComment6.getContents().getCommentContents(), + originParentTechComment6.getReplyTotalCount().getCount(), + originParentTechComment6.getRecommendTotalCount().getCount(), + true, + false, + false, + false, + anonymousMember.getId() + ), + Tuple.tuple(originParentTechComment5.getId(), + member.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + originParentTechComment5.getContents().getCommentContents(), + originParentTechComment5.getReplyTotalCount().getCount(), + originParentTechComment5.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null + ), + Tuple.tuple(originParentTechComment4.getId(), + member.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + originParentTechComment4.getContents().getCommentContents(), + originParentTechComment4.getReplyTotalCount().getCount(), + originParentTechComment4.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null + ), + Tuple.tuple(originParentTechComment3.getId(), + member.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + originParentTechComment3.getContents().getCommentContents(), + originParentTechComment3.getReplyTotalCount().getCount(), + originParentTechComment3.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null + ), + Tuple.tuple(originParentTechComment2.getId(), + member.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + originParentTechComment2.getContents().getCommentContents(), + originParentTechComment2.getReplyTotalCount().getCount(), + originParentTechComment2.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null + ) + ); + + TechCommentsResponse techCommentsResponse6 = response.getContent().get(0); + List replies6 = techCommentsResponse6.getReplies(); + assertThat(replies6).hasSize(0); + + TechCommentsResponse techCommentsResponse5 = response.getContent().get(1); + List replies5 = techCommentsResponse5.getReplies(); + assertThat(replies5).hasSize(0); + + TechCommentsResponse techCommentsResponse4 = response.getContent().get(2); + List replies4 = techCommentsResponse4.getReplies(); + assertThat(replies4).hasSize(0); + + TechCommentsResponse techCommentsResponse3 = response.getContent().get(3); + List replies3 = techCommentsResponse3.getReplies(); + assertThat(replies3).hasSize(0); + + TechCommentsResponse techCommentsResponse2 = response.getContent().get(4); + List replies2 = techCommentsResponse2.getReplies(); + assertThat(replies2).hasSize(2) + .extracting("techCommentId") + .containsExactly(parentTechComment3.getId(), parentTechComment4.getId()); + } + + @Test + @DisplayName("익명 회원은 커서 방식으로 기술블로그 댓글/답글을 조회할 수 있다. (댓글 많은 순)") + void getTechCommentsSortByMostCommented() { + // given + SocialMemberDto socialMemberDto = createSocialDto(userId, name, nickname, password, email, socialType, role); + Member member = Member.createMemberBy(socialMemberDto); + memberRepository.save(member); + + // 익명회원 생성 + AnonymousMember anonymousMember = AnonymousMember.create("anonymousMemberId", "익명으로 개발하는 댑댑이"); + anonymousMemberRepository.save(anonymousMember); + + Authentication authentication = mock(Authentication.class); + when(authentication.getPrincipal()).thenReturn(AuthenticationMemberUtils.ANONYMOUS_USER); + + Company company = createCompany("꿈빛 파티시엘", "https://example.com/company.png", "https://example.com", + "https://example.com"); + companyRepository.save(company); + + TechArticle techArticle = TechArticle.createTechArticle(new Title("기술블로그 제목"), new Url("https://example.com"), + new Count(1L), + new Count(1L), new Count(12L), new Count(1L), null, company); + techArticleRepository.save(techArticle); + Long techArticleId = techArticle.getId(); + + TechComment originParentTechComment1 = createMainTechComment(new CommentContents("최상위 댓글1"), member, + techArticle, new Count(0L), new Count(0L), new Count(0L)); + TechComment originParentTechComment2 = createMainTechComment(new CommentContents("최상위 댓글2"), member, + techArticle, new Count(0L), new Count(0L), new Count(4L)); + TechComment originParentTechComment3 = createMainTechComment(new CommentContents("최상위 댓글3"), member, + techArticle, new Count(0L), new Count(0L), new Count(0L)); + TechComment originParentTechComment4 = createMainTechComment(new CommentContents("최상위 댓글4"), member, + techArticle, new Count(0L), new Count(0L), new Count(2L)); + TechComment originParentTechComment5 = createMainTechComment(new CommentContents("최상위 댓글5"), member, + techArticle, new Count(0L), new Count(0L), new Count(0L)); + TechComment originParentTechComment6 = createMainTechComment(new CommentContents("최상위 댓글6"), member, + techArticle, new Count(0L), new Count(0L), new Count(0L)); + + TechComment parentTechComment1 = createRepliedTechComment(new CommentContents("최상위 댓글2의 답글1"), anonymousMember, + techArticle, originParentTechComment2, originParentTechComment2, new Count(0L), new Count(0L), new Count(0L)); + TechComment parentTechComment2 = createRepliedTechComment(new CommentContents("최상위 댓글2의 답글2"), member, + techArticle, originParentTechComment2, originParentTechComment2, new Count(0L), new Count(0L), new Count(0L)); + TechComment parentTechComment3 = createRepliedTechComment(new CommentContents("최상위 댓글4의 답글1"), member, + techArticle, originParentTechComment4, originParentTechComment4, new Count(0L), new Count(0L), new Count(0L)); + TechComment parentTechComment4 = createRepliedTechComment(new CommentContents("최상위 댓글4의 답글2"), member, + techArticle, originParentTechComment4, originParentTechComment4, new Count(0L), new Count(0L), new Count(0L)); + + TechComment techcomment1 = createRepliedTechComment(new CommentContents("최상위 댓글2의 답글1의 답글"), member, + techArticle, originParentTechComment2, parentTechComment1, new Count(0L), new Count(0L), new Count(0L)); + TechComment techcomment2 = createRepliedTechComment(new CommentContents("최상위 댓글2의 답글2의 답글"), member, + techArticle, originParentTechComment2, parentTechComment2, new Count(0L), new Count(0L), new Count(0L)); + + techCommentRepository.saveAll(List.of( + originParentTechComment1, originParentTechComment2, originParentTechComment3, + originParentTechComment4, originParentTechComment5, originParentTechComment6, + parentTechComment1, parentTechComment2, parentTechComment3, parentTechComment4, + techcomment1, techcomment2 + )); + + Pageable pageable = PageRequest.of(0, 5); + + em.flush(); + em.clear(); + + // when + SliceCommentCustom response = guestTechCommentServiceV2.getTechComments(techArticleId, + null, TechCommentSort.MOST_COMMENTED, pageable, anonymousMember.getAnonymousMemberId(), authentication); + + // then + assertThat(response.getTotalOriginParentComments()).isEqualTo(6L); + assertThat(response).hasSizeLessThanOrEqualTo(pageable.getPageSize()) + .extracting( + "techCommentId", + "memberId", + "author", + "maskedEmail", + "contents", + "replyTotalCount", + "recommendTotalCount", + "isCommentAuthor", + "isRecommended", + "isModified", + "isDeleted", + "anonymousMemberId" + ) + .containsExactly( + Tuple.tuple(originParentTechComment2.getId(), + member.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + originParentTechComment2.getContents().getCommentContents(), + originParentTechComment2.getReplyTotalCount().getCount(), + originParentTechComment2.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null + ), + Tuple.tuple(originParentTechComment4.getId(), + member.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + originParentTechComment4.getContents().getCommentContents(), + originParentTechComment4.getReplyTotalCount().getCount(), + originParentTechComment4.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null + ), + Tuple.tuple(originParentTechComment6.getId(), + member.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + originParentTechComment6.getContents().getCommentContents(), + originParentTechComment6.getReplyTotalCount().getCount(), + originParentTechComment6.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null + ), + Tuple.tuple(originParentTechComment5.getId(), + member.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + originParentTechComment5.getContents().getCommentContents(), + originParentTechComment5.getReplyTotalCount().getCount(), + originParentTechComment5.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null + ), + Tuple.tuple(originParentTechComment3.getId(), + member.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + originParentTechComment3.getContents().getCommentContents(), + originParentTechComment3.getReplyTotalCount().getCount(), + originParentTechComment3.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null + ) + ); + + TechCommentsResponse techCommentsResponse1 = response.getContent().get(0); + List replies1 = techCommentsResponse1.getReplies(); + assertThat(replies1).hasSize(4) + .extracting( + "techCommentId", + "memberId", + "techParentCommentId", + "techParentCommentMemberId", + "techParentCommentAuthor", + "techOriginParentCommentId", + "author", + "maskedEmail", + "contents", + "recommendTotalCount", + "isCommentAuthor", + "isRecommended", + "isModified", + "isDeleted", + "anonymousMemberId", + "techParentCommentAnonymousMemberId" + ) + .containsExactly( + Tuple.tuple(parentTechComment1.getId(), + null, + originParentTechComment2.getId(), + originParentTechComment2.getCreatedBy().getId(), + member.getNicknameAsString(), + originParentTechComment2.getId(), + anonymousMember.getNickname(), + null, + parentTechComment1.getContents().getCommentContents(), + parentTechComment1.getRecommendTotalCount().getCount(), + true, + false, + false, + false, + anonymousMember.getId(), + null + ), + Tuple.tuple(parentTechComment2.getId(), + member.getId(), + originParentTechComment2.getId(), + originParentTechComment2.getCreatedBy().getId(), + member.getNicknameAsString(), + originParentTechComment2.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + parentTechComment2.getContents().getCommentContents(), + parentTechComment2.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null, + null + ), + Tuple.tuple(techcomment1.getId(), + member.getId(), + parentTechComment1.getId(), + null, + anonymousMember.getNickname(), + originParentTechComment2.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + techcomment1.getContents().getCommentContents(), + techcomment1.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null, + parentTechComment1.getCreatedAnonymousBy().getId() + ), + Tuple.tuple(techcomment2.getId(), + member.getId(), + parentTechComment2.getId(), + parentTechComment2.getCreatedBy().getId(), + member.getNicknameAsString(), + originParentTechComment2.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + techcomment2.getContents().getCommentContents(), + techcomment2.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null, + null + ) + ); + + TechCommentsResponse techCommentsResponse2 = response.getContent().get(1); + List replies2 = techCommentsResponse2.getReplies(); + assertThat(replies2).hasSize(2) + .extracting( + "techCommentId", + "memberId", + "techParentCommentId", + "techParentCommentMemberId", + "techParentCommentAuthor", + "techOriginParentCommentId", + "author", + "maskedEmail", + "contents", + "recommendTotalCount", + "isCommentAuthor", + "isRecommended", + "isModified", + "isDeleted", + "anonymousMemberId", + "techParentCommentAnonymousMemberId" + ) + .containsExactly( + Tuple.tuple(parentTechComment3.getId(), + member.getId(), + originParentTechComment4.getId(), + originParentTechComment4.getCreatedBy().getId(), + member.getNicknameAsString(), + originParentTechComment4.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + parentTechComment3.getContents().getCommentContents(), + parentTechComment3.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null, + null + ), + Tuple.tuple(parentTechComment4.getId(), + member.getId(), + originParentTechComment4.getId(), + originParentTechComment4.getCreatedBy().getId(), + member.getNicknameAsString(), + originParentTechComment4.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + parentTechComment4.getContents().getCommentContents(), + parentTechComment4.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null, + null + ) + ); + + TechCommentsResponse techCommentsResponse3 = response.getContent().get(2); + List replies3 = techCommentsResponse3.getReplies(); + assertThat(replies3).hasSize(0); + + TechCommentsResponse techCommentsResponse4 = response.getContent().get(3); + List replies4 = techCommentsResponse4.getReplies(); + assertThat(replies4).hasSize(0); + + TechCommentsResponse techCommentsResponse5 = response.getContent().get(4); + List replies5 = techCommentsResponse5.getReplies(); + assertThat(replies5).hasSize(0); + } + + @Test + @DisplayName("익명 회원은 커서 방식으로 기술블로그 댓글/답글을 조회할 수 있다. (추천 많은 순)") + void getTechCommentsSortByMostRecommended() { + // given + SocialMemberDto socialMemberDto = createSocialDto(userId, name, nickname, password, email, socialType, role); + Member member = Member.createMemberBy(socialMemberDto); + memberRepository.save(member); + + // 익명회원 생성 + AnonymousMember anonymousMember = AnonymousMember.create("anonymousMemberId", "익명으로 개발하는 댑댑이"); + anonymousMemberRepository.save(anonymousMember); + + Authentication authentication = mock(Authentication.class); + when(authentication.getPrincipal()).thenReturn(AuthenticationMemberUtils.ANONYMOUS_USER); + + Company company = createCompany("꿈빛 파티시엘", "https://example.com/company.png", "https://example.com", + "https://example.com"); + companyRepository.save(company); + + TechArticle techArticle = TechArticle.createTechArticle(new Title("기술블로그 제목"), new Url("https://example.com"), + new Count(1L), + new Count(1L), new Count(12L), new Count(1L), null, company); + techArticleRepository.save(techArticle); + Long techArticleId = techArticle.getId(); + + TechComment originParentTechComment1 = createMainTechComment(new CommentContents("최상위 댓글1"), member, + techArticle, new Count(0L), new Count(3L), new Count(0L)); + TechComment originParentTechComment2 = createMainTechComment(new CommentContents("최상위 댓글2"), member, + techArticle, new Count(0L), new Count(1L), new Count(0L)); + TechComment originParentTechComment3 = createMainTechComment(new CommentContents("최상위 댓글3"), member, + techArticle, new Count(0L), new Count(5L), new Count(0L)); + TechComment originParentTechComment4 = createMainTechComment(new CommentContents("최상위 댓글4"), member, + techArticle, new Count(0L), new Count(4L), new Count(0L)); + TechComment originParentTechComment5 = createMainTechComment(new CommentContents("최상위 댓글5"), member, + techArticle, new Count(0L), new Count(2L), new Count(0L)); + TechComment originParentTechComment6 = createMainTechComment(new CommentContents("최상위 댓글6"), anonymousMember, + techArticle, new Count(0L), new Count(6L), new Count(0L)); + + techCommentRepository.saveAll(List.of( + originParentTechComment1, originParentTechComment2, originParentTechComment3, + originParentTechComment4, originParentTechComment5, originParentTechComment6 + )); + + Pageable pageable = PageRequest.of(0, 5); + + em.flush(); + em.clear(); + + // when + SliceCommentCustom response = guestTechCommentServiceV2.getTechComments(techArticleId, + null, TechCommentSort.MOST_LIKED, pageable, anonymousMember.getAnonymousMemberId(), authentication); + + // then + assertThat(response.getTotalOriginParentComments()).isEqualTo(6L); + assertThat(response).hasSizeLessThanOrEqualTo(pageable.getPageSize()) + .extracting( + "techCommentId", + "memberId", + "author", + "maskedEmail", + "contents", + "replyTotalCount", + "recommendTotalCount", + "isCommentAuthor", + "isRecommended", + "isModified", + "isDeleted", + "anonymousMemberId" + ) + .containsExactly( + Tuple.tuple(originParentTechComment6.getId(), + null, + anonymousMember.getNickname(), + null, + originParentTechComment6.getContents().getCommentContents(), + originParentTechComment6.getReplyTotalCount().getCount(), + originParentTechComment6.getRecommendTotalCount().getCount(), + true, + false, + false, + false, + anonymousMember.getId() + ), + Tuple.tuple(originParentTechComment3.getId(), + member.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + originParentTechComment3.getContents().getCommentContents(), + originParentTechComment3.getReplyTotalCount().getCount(), + originParentTechComment3.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null + ), + Tuple.tuple(originParentTechComment4.getId(), + member.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + originParentTechComment4.getContents().getCommentContents(), + originParentTechComment4.getReplyTotalCount().getCount(), + originParentTechComment4.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null + ), + Tuple.tuple(originParentTechComment1.getId(), + member.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + originParentTechComment1.getContents().getCommentContents(), + originParentTechComment1.getReplyTotalCount().getCount(), + originParentTechComment1.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null + ), + Tuple.tuple(originParentTechComment5.getId(), + member.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + originParentTechComment5.getContents().getCommentContents(), + originParentTechComment5.getReplyTotalCount().getCount(), + originParentTechComment5.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null + ) + ); + + TechCommentsResponse techCommentsResponse6 = response.getContent().get(0); + List replies6 = techCommentsResponse6.getReplies(); + assertThat(replies6).hasSize(0); + + TechCommentsResponse techCommentsResponse3 = response.getContent().get(1); + List replies3 = techCommentsResponse3.getReplies(); + assertThat(replies3).hasSize(0); + + TechCommentsResponse techCommentsResponse4 = response.getContent().get(2); + List replies4 = techCommentsResponse4.getReplies(); + assertThat(replies4).hasSize(0); + + TechCommentsResponse techCommentsResponse1 = response.getContent().get(3); + List replies1 = techCommentsResponse1.getReplies(); + assertThat(replies1).hasSize(0); + + TechCommentsResponse techCommentsResponse5 = response.getContent().get(4); + List replies5 = techCommentsResponse5.getReplies(); + assertThat(replies5).hasSize(0); + } + + @Test + @DisplayName("익명 회원은 커서 방식으로 커서 다음의 기술블로그 댓글/답글을 조회할 수 있다.") + void getTechCommentsByCursor() { + // given + SocialMemberDto socialMemberDto = createSocialDto(userId, name, nickname, password, email, socialType, role); + Member member = Member.createMemberBy(socialMemberDto); + memberRepository.save(member); + + // 익명회원 생성 + AnonymousMember anonymousMember = AnonymousMember.create("anonymousMemberId", "익명으로 개발하는 댑댑이"); + anonymousMemberRepository.save(anonymousMember); + + Authentication authentication = mock(Authentication.class); + when(authentication.getPrincipal()).thenReturn(AuthenticationMemberUtils.ANONYMOUS_USER); + + Company company = createCompany("꿈빛 파티시엘", "https://example.com/company.png", "https://example.com", + "https://example.com"); + companyRepository.save(company); + + TechArticle techArticle = TechArticle.createTechArticle(new Title("기술블로그 제목"), new Url("https://example.com"), + new Count(1L), new Count(1L), new Count(12L), new Count(1L), null, company); + techArticleRepository.save(techArticle); + Long techArticleId = techArticle.getId(); + + TechComment originParentTechComment1 = createMainTechComment(new CommentContents("최상위 댓글1"), anonymousMember, + techArticle, new Count(0L), new Count(0L), new Count(0L)); + TechComment originParentTechComment2 = createMainTechComment(new CommentContents("최상위 댓글2"), member, + techArticle, new Count(0L), new Count(0L), new Count(0L)); + TechComment originParentTechComment3 = createMainTechComment(new CommentContents("최상위 댓글3"), member, + techArticle, new Count(0L), new Count(0L), new Count(0L)); + TechComment originParentTechComment4 = createMainTechComment(new CommentContents("최상위 댓글4"), member, + techArticle, new Count(0L), new Count(0L), new Count(0L)); + TechComment originParentTechComment5 = createMainTechComment(new CommentContents("최상위 댓글5"), member, + techArticle, new Count(0L), new Count(0L), new Count(0L)); + TechComment originParentTechComment6 = createMainTechComment(new CommentContents("최상위 댓글6"), member, + techArticle, new Count(0L), new Count(0L), new Count(0L)); + + originParentTechComment6.changeDeletedAt(LocalDateTime.now(), member); + + techCommentRepository.saveAll(List.of( + originParentTechComment1, originParentTechComment2, originParentTechComment3, + originParentTechComment4, originParentTechComment5, originParentTechComment6 + )); + + Pageable pageable = PageRequest.of(0, 5); + + em.flush(); + em.clear(); + + // when + SliceCommentCustom response = guestTechCommentServiceV2.getTechComments(techArticleId, + originParentTechComment6.getId(), null, pageable, anonymousMember.getAnonymousMemberId(), authentication); + + // then + assertThat(response.getTotalOriginParentComments()).isEqualTo(5L); // 삭제된 댓글은 카운트하지 않는다 + assertThat(response).hasSizeLessThanOrEqualTo(pageable.getPageSize()) + .extracting( + "techCommentId", + "memberId", + "author", + "maskedEmail", + "contents", + "replyTotalCount", + "recommendTotalCount", + "isCommentAuthor", + "isRecommended", + "isModified", + "isDeleted", + "anonymousMemberId" + ) + .containsExactly( + Tuple.tuple(originParentTechComment5.getId(), + member.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + originParentTechComment5.getContents().getCommentContents(), + originParentTechComment5.getReplyTotalCount().getCount(), + originParentTechComment5.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null + ), + Tuple.tuple(originParentTechComment4.getId(), + member.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + originParentTechComment4.getContents().getCommentContents(), + originParentTechComment4.getReplyTotalCount().getCount(), + originParentTechComment4.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null + ), + Tuple.tuple(originParentTechComment3.getId(), + member.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + originParentTechComment3.getContents().getCommentContents(), + originParentTechComment3.getReplyTotalCount().getCount(), + originParentTechComment3.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null + ), + Tuple.tuple(originParentTechComment2.getId(), + member.getId(), + member.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member.getEmailAsString()), + originParentTechComment2.getContents().getCommentContents(), + originParentTechComment2.getReplyTotalCount().getCount(), + originParentTechComment2.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null + ), + Tuple.tuple(originParentTechComment1.getId(), + null, + anonymousMember.getNickname(), + null, + originParentTechComment1.getContents().getCommentContents(), + originParentTechComment1.getReplyTotalCount().getCount(), + originParentTechComment1.getRecommendTotalCount().getCount(), + true, + false, + false, + false, + anonymousMember.getId() + ) + ); + + TechCommentsResponse techCommentsResponse6 = response.getContent().get(0); + List replies6 = techCommentsResponse6.getReplies(); + assertThat(replies6).hasSize(0); + + TechCommentsResponse techCommentsResponse3 = response.getContent().get(1); + List replies3 = techCommentsResponse3.getReplies(); + assertThat(replies3).hasSize(0); + + TechCommentsResponse techCommentsResponse4 = response.getContent().get(2); + List replies4 = techCommentsResponse4.getReplies(); + assertThat(replies4).hasSize(0); + + TechCommentsResponse techCommentsResponse1 = response.getContent().get(3); + List replies1 = techCommentsResponse1.getReplies(); + assertThat(replies1).hasSize(0); + + TechCommentsResponse techCommentsResponse5 = response.getContent().get(4); + List replies5 = techCommentsResponse5.getReplies(); + assertThat(replies5).hasSize(0); + } + + @Test + @DisplayName("익명 회원이 아닌 경우 익명회원 전용 기술블로그 베스트 댓글 조회 메소드를 호출하면 예외가 발생한다.") + void findTechBestCommentsNotAnonymousMember() { + // given + SocialMemberDto socialMemberDto = createSocialDto(userId, name, nickname, password, email, socialType, role); + Member member = Member.createMemberBy(socialMemberDto); + memberRepository.save(member); + + // 익명회원 생성 + AnonymousMember anonymousMember = AnonymousMember.create("anonymousMemberId", "익명으로 개발하는 댑댑이"); + anonymousMemberRepository.save(anonymousMember); + + UserPrincipal userPrincipal = UserPrincipal.createByMember(member); + SecurityContext context = SecurityContextHolder.getContext(); + context.setAuthentication(new OAuth2AuthenticationToken(userPrincipal, userPrincipal.getAuthorities(), + userPrincipal.getSocialType().name())); + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + + // when // then + assertThatThrownBy(() -> guestTechCommentServiceV2.findTechBestComments(3, 1L, anonymousMember.getAnonymousMemberId(), + authentication)) + .isInstanceOf(IllegalStateException.class) + .hasMessage(INVALID_METHODS_CALL_MESSAGE); + } + + @Test + @DisplayName("익명 회원이 offset에 정책에 맞게 기술블로그 베스트 댓글을 조회한다.") + void findTechBestComments() { + // given + // 회원 생성 + SocialMemberDto socialMemberDto1 = createSocialDto("user1", name, "nickname1", password, "user1@gmail.com", + socialType, Role.ROLE_ADMIN.name()); + SocialMemberDto socialMemberDto2 = createSocialDto("user2", name, "nickname2", password, "user2@gmail.com", + socialType, role); + SocialMemberDto socialMemberDto3 = createSocialDto("user3", name, "nickname3", password, "user3@gmail.com", + socialType, role); + Member member1 = Member.createMemberBy(socialMemberDto1); + Member member2 = Member.createMemberBy(socialMemberDto2); + Member member3 = Member.createMemberBy(socialMemberDto3); + memberRepository.saveAll(List.of(member1, member2, member3)); + + // 익명회원 생성 + AnonymousMember anonymousMember = AnonymousMember.create("anonymousMemberId", "익명으로 개발하는 댑댑이"); + anonymousMemberRepository.save(anonymousMember); + + // 회사 생성 + Company company = createCompany("꿈빛 파티시엘", "https://example.com/company.png", "https://example.com", + "https://example.com"); + companyRepository.save(company); + + // 기술 블로그 생성 + TechArticle techArticle = TechArticle.createTechArticle(new Title("기술블로그 제목"), new Url("https://example.com"), + new Count(1L), new Count(1L), new Count(12L), new Count(1L), null, company); + techArticleRepository.save(techArticle); + + // 댓글 생성 + TechComment originParentTechComment1 = createMainTechComment(new CommentContents("최상위 댓글1"), anonymousMember, + techArticle, new Count(0L), new Count(3L), new Count(0L)); + originParentTechComment1.modifyCommentContents(new CommentContents("최상위 댓글1 수정"), LocalDateTime.now()); + TechComment originParentTechComment2 = createMainTechComment(new CommentContents("최상위 댓글1"), member2, + techArticle, new Count(0L), new Count(2L), new Count(0L)); + TechComment originParentTechComment3 = createMainTechComment(new CommentContents("최상위 댓글1"), member3, + techArticle, new Count(0L), new Count(1L), new Count(0L)); + techCommentRepository.saveAll( + List.of(originParentTechComment1, originParentTechComment2, originParentTechComment3)); + + // 추천 생성 + TechCommentRecommend techCommentRecommend = createTechCommentRecommend(true, originParentTechComment1, member2); + techCommentRecommendRepository.save(techCommentRecommend); + + // 답글 생성 + TechComment repliedTechComment = createRepliedTechComment(new CommentContents("최상위 댓글1의 답글1"), member3, + techArticle, originParentTechComment1, originParentTechComment1, new Count(0L), new Count(0L), new Count(0L)); + techCommentRepository.save(repliedTechComment); + + // when + // 익명회원 목킹 + Authentication authentication = mock(Authentication.class); + when(authentication.getPrincipal()).thenReturn(AuthenticationMemberUtils.ANONYMOUS_USER); + + List response = guestTechCommentServiceV2.findTechBestComments(3, techArticle.getId(), + anonymousMember.getAnonymousMemberId(), authentication); + + // then + assertThat(response).hasSize(3) + .extracting( + "techCommentId", + "memberId", + "author", + "maskedEmail", + "contents", + "replyTotalCount", + "recommendTotalCount", + "isCommentAuthor", + "isRecommended", + "isModified", + "isDeleted", + "anonymousMemberId" + ) + .containsExactly( + Tuple.tuple(originParentTechComment1.getId(), + null, + anonymousMember.getNickname(), + null, + originParentTechComment1.getContents().getCommentContents(), + originParentTechComment1.getReplyTotalCount().getCount(), + originParentTechComment1.getRecommendTotalCount().getCount(), + true, + false, + true, + false, + anonymousMember.getId() + ), + Tuple.tuple(originParentTechComment2.getId(), + member2.getId(), + member2.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member2.getEmailAsString()), + originParentTechComment2.getContents().getCommentContents(), + originParentTechComment2.getReplyTotalCount().getCount(), + originParentTechComment2.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null + ), + Tuple.tuple(originParentTechComment3.getId(), + member3.getId(), + member3.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member3.getEmailAsString()), + originParentTechComment3.getContents().getCommentContents(), + originParentTechComment3.getReplyTotalCount().getCount(), + originParentTechComment3.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null + ) + ); + + TechCommentsResponse techCommentsResponse = response.get(0); + List replies = techCommentsResponse.getReplies(); + assertThat(replies).hasSize(1) + .extracting( + "techCommentId", + "memberId", + "techParentCommentId", + "techParentCommentMemberId", + "techParentCommentAuthor", + "techOriginParentCommentId", + "author", + "maskedEmail", + "contents", + "recommendTotalCount", + "isCommentAuthor", + "isRecommended", + "isModified", + "isDeleted", + "anonymousMemberId", + "techParentCommentAnonymousMemberId" + ).containsExactly( + Tuple.tuple(repliedTechComment.getId(), + member3.getId(), + repliedTechComment.getParent().getId(), + null, + repliedTechComment.getParent().getCreatedAnonymousBy().getNickname(), + repliedTechComment.getOriginParent().getId(), + member3.getNicknameAsString(), + CommonResponseUtil.sliceAndMaskEmail(member3.getEmailAsString()), + repliedTechComment.getContents().getCommentContents(), + repliedTechComment.getRecommendTotalCount().getCount(), + false, + false, + false, + false, + null, + repliedTechComment.getParent().getCreatedAnonymousBy().getId() + ) + ); + } +} \ No newline at end of file diff --git a/src/test/java/com/dreamypatisiel/devdevdev/web/docs/TechArticleCommentControllerDocsTest.java b/src/test/java/com/dreamypatisiel/devdevdev/web/docs/TechArticleCommentControllerDocsTest.java index afa5ff38..637858ab 100644 --- a/src/test/java/com/dreamypatisiel/devdevdev/web/docs/TechArticleCommentControllerDocsTest.java +++ b/src/test/java/com/dreamypatisiel/devdevdev/web/docs/TechArticleCommentControllerDocsTest.java @@ -2,7 +2,13 @@ import static com.dreamypatisiel.devdevdev.domain.exception.MemberExceptionMessage.INVALID_MEMBER_NOT_FOUND_MESSAGE; import static com.dreamypatisiel.devdevdev.domain.exception.TechArticleExceptionMessage.NOT_FOUND_TECH_ARTICLE_MESSAGE; +import static com.dreamypatisiel.devdevdev.domain.service.techArticle.TechTestUtils.createCompany; +import static com.dreamypatisiel.devdevdev.domain.service.techArticle.TechTestUtils.createMainTechComment; +import static com.dreamypatisiel.devdevdev.domain.service.techArticle.TechTestUtils.createRepliedTechComment; +import static com.dreamypatisiel.devdevdev.domain.service.techArticle.TechTestUtils.createSocialDto; +import static com.dreamypatisiel.devdevdev.domain.service.techArticle.TechTestUtils.createTechCommentRecommend; import static com.dreamypatisiel.devdevdev.global.constant.SecurityConstant.AUTHORIZATION_HEADER; +import static com.dreamypatisiel.devdevdev.web.WebConstant.HEADER_ANONYMOUS_MEMBER_ID; import static com.dreamypatisiel.devdevdev.web.docs.format.ApiDocsFormatGenerator.authenticationType; import static com.dreamypatisiel.devdevdev.web.docs.format.ApiDocsFormatGenerator.techCommentSortType; import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; @@ -30,19 +36,18 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import com.dreamypatisiel.devdevdev.domain.entity.AnonymousMember; import com.dreamypatisiel.devdevdev.domain.entity.Company; import com.dreamypatisiel.devdevdev.domain.entity.Member; import com.dreamypatisiel.devdevdev.domain.entity.TechArticle; import com.dreamypatisiel.devdevdev.domain.entity.TechComment; import com.dreamypatisiel.devdevdev.domain.entity.TechCommentRecommend; import com.dreamypatisiel.devdevdev.domain.entity.embedded.CommentContents; -import com.dreamypatisiel.devdevdev.domain.entity.embedded.CompanyName; import com.dreamypatisiel.devdevdev.domain.entity.embedded.Count; import com.dreamypatisiel.devdevdev.domain.entity.embedded.Title; import com.dreamypatisiel.devdevdev.domain.entity.embedded.Url; -import com.dreamypatisiel.devdevdev.domain.entity.enums.Role; -import com.dreamypatisiel.devdevdev.domain.entity.enums.SocialType; import com.dreamypatisiel.devdevdev.domain.repository.CompanyRepository; +import com.dreamypatisiel.devdevdev.domain.repository.member.AnonymousMemberRepository; import com.dreamypatisiel.devdevdev.domain.repository.member.MemberRepository; import com.dreamypatisiel.devdevdev.domain.repository.techArticle.TechArticleRepository; import com.dreamypatisiel.devdevdev.domain.repository.techArticle.TechCommentRecommendRepository; @@ -50,7 +55,6 @@ import com.dreamypatisiel.devdevdev.domain.repository.techArticle.TechCommentSort; import com.dreamypatisiel.devdevdev.global.constant.SecurityConstant; import com.dreamypatisiel.devdevdev.global.security.oauth2.model.SocialMemberDto; -import com.dreamypatisiel.devdevdev.global.security.oauth2.model.UserPrincipal; import com.dreamypatisiel.devdevdev.web.dto.request.techArticle.ModifyTechCommentRequest; import com.dreamypatisiel.devdevdev.web.dto.request.techArticle.RegisterTechCommentRequest; import com.dreamypatisiel.devdevdev.web.dto.response.ResultType; @@ -68,10 +72,6 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.restdocs.payload.JsonFieldType; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.test.web.servlet.ResultActions; public class TechArticleCommentControllerDocsTest extends SupportControllerDocsTest { @@ -91,6 +91,9 @@ public class TechArticleCommentControllerDocsTest extends SupportControllerDocsT @Autowired TechCommentRecommendRepository techCommentRecommendRepository; + @Autowired + AnonymousMemberRepository anonymousMemberRepository; + @Autowired EntityManager em; @@ -180,7 +183,8 @@ void registerTechComment() throws Exception { preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), requestHeaders( - headerWithName(AUTHORIZATION_HEADER).description("Bearer 엑세스 토큰") + headerWithName(AUTHORIZATION_HEADER).optional().description("Bearer 엑세스 토큰"), + headerWithName(HEADER_ANONYMOUS_MEMBER_ID).optional().description("익명회원 아이디") ), pathParameters( parameterWithName("techArticleId").description("기술블로그 아이디") @@ -385,7 +389,8 @@ void modifyTechComment() throws Exception { preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), requestHeaders( - headerWithName(AUTHORIZATION_HEADER).description("Bearer 엑세스 토큰") + headerWithName(AUTHORIZATION_HEADER).optional().description("Bearer 엑세스 토큰"), + headerWithName(HEADER_ANONYMOUS_MEMBER_ID).optional().description("익명회원 아이디") ), pathParameters( parameterWithName("techArticleId").description("기술블로그 아이디"), @@ -553,7 +558,8 @@ void deleteTechComment() throws Exception { preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), requestHeaders( - headerWithName(AUTHORIZATION_HEADER).description("Bearer 엑세스 토큰") + headerWithName(AUTHORIZATION_HEADER).optional().description("Bearer 엑세스 토큰"), + headerWithName(HEADER_ANONYMOUS_MEMBER_ID).optional().description("익명회원 아이디") ), pathParameters( parameterWithName("techArticleId").description("기술블로그 아이디"), @@ -670,7 +676,8 @@ void registerTechReply() throws Exception { preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), requestHeaders( - headerWithName(AUTHORIZATION_HEADER).description("Bearer 엑세스 토큰") + headerWithName(AUTHORIZATION_HEADER).optional().description("Bearer 엑세스 토큰"), + headerWithName(HEADER_ANONYMOUS_MEMBER_ID).optional().description("익명회원 아이디") ), pathParameters( parameterWithName("techArticleId").description("기술블로그 아이디"), @@ -754,30 +761,26 @@ void registerTechReplyContentsIsNullException(String contents) throws Exception @DisplayName("기술블로그 댓글/답글을 정렬 조건에 따라서 조회한다.") void getTechComments() throws Exception { // given - SocialMemberDto socialMemberDto = createSocialDto("dreamy5patisiel", "꿈빛파티시엘", - "꿈빛파티시엘", "1234", email, socialType, role); + SocialMemberDto socialMemberDto = createSocialDto("dreamy5patisiel", "꿈빛파티시엘", "꿈빛파티시엘", "1234", email, socialType, role); Member member = Member.createMemberBy(socialMemberDto); memberRepository.save(member); - UserPrincipal userPrincipal = UserPrincipal.createByMember(member); - SecurityContext context = SecurityContextHolder.getContext(); - context.setAuthentication(new OAuth2AuthenticationToken(userPrincipal, userPrincipal.getAuthorities(), - userPrincipal.getSocialType().name())); - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + // 익명회원 생성 + AnonymousMember anonymousMember = AnonymousMember.create("anonymousMemberId", "익명으로 개발하는 댑댑이"); + anonymousMemberRepository.save(anonymousMember); Company company = createCompany("꿈빛 파티시엘", "https://example.com/company.png", "https://example.com", "https://example.com"); companyRepository.save(company); TechArticle techArticle = TechArticle.createTechArticle(new Title("기술블로그 제목"), new Url("https://example.com"), - new Count(1L), - new Count(1L), new Count(12L), new Count(1L), null, company); + new Count(1L), new Count(1L), new Count(12L), new Count(1L), null, company); techArticleRepository.save(techArticle); Long techArticleId = techArticle.getId(); TechComment originParentTechComment1 = createMainTechComment(new CommentContents("최상위 댓글1"), member, techArticle, new Count(0L), new Count(0L), new Count(0L)); - TechComment originParentTechComment2 = createMainTechComment(new CommentContents("최상위 댓글2"), member, + TechComment originParentTechComment2 = createMainTechComment(new CommentContents("최상위 댓글2"), anonymousMember, techArticle, new Count(0L), new Count(0L), new Count(0L)); TechComment originParentTechComment3 = createMainTechComment(new CommentContents("최상위 댓글3"), member, techArticle, new Count(0L), new Count(0L), new Count(0L)); @@ -785,29 +788,21 @@ void getTechComments() throws Exception { techArticle, new Count(0L), new Count(0L), new Count(0L)); TechComment originParentTechComment5 = createMainTechComment(new CommentContents("최상위 댓글5"), member, techArticle, new Count(0L), new Count(0L), new Count(0L)); - TechComment originParentTechComment6 = createMainTechComment(new CommentContents("최상위 댓글6"), member, + TechComment originParentTechComment6 = createMainTechComment(new CommentContents("최상위 댓글6"), anonymousMember, techArticle, new Count(0L), new Count(0L), new Count(0L)); TechComment parentTechComment1 = createRepliedTechComment(new CommentContents("최상위 댓글1의 답글1"), member, - techArticle, originParentTechComment1, originParentTechComment1, new Count(0L), new Count(0L), - new Count(0L)); - TechComment parentTechComment2 = createRepliedTechComment(new CommentContents("최상위 댓글1의 답글2"), member, - techArticle, originParentTechComment1, originParentTechComment1, new Count(0L), new Count(0L), - new Count(0L)); + techArticle, originParentTechComment1, originParentTechComment1, new Count(0L), new Count(0L), new Count(0L)); + TechComment parentTechComment2 = createRepliedTechComment(new CommentContents("최상위 댓글1의 답글2"), anonymousMember, + techArticle, originParentTechComment1, originParentTechComment1, new Count(0L), new Count(0L), new Count(0L)); TechComment parentTechComment3 = createRepliedTechComment(new CommentContents("최상위 댓글2의 답글1"), member, - techArticle, originParentTechComment2, originParentTechComment2, new Count(0L), new Count(0L), - new Count(0L)); + techArticle, originParentTechComment2, originParentTechComment2, new Count(0L), new Count(0L), new Count(0L)); TechComment parentTechComment4 = createRepliedTechComment(new CommentContents("최상위 댓글2의 답글2"), member, - techArticle, originParentTechComment2, originParentTechComment2, new Count(0L), new Count(0L), - new Count(0L)); + techArticle, originParentTechComment2, originParentTechComment2, new Count(0L), new Count(0L), new Count(0L)); TechComment techComment1 = createRepliedTechComment(new CommentContents("최상위 댓글1의 답글1의 답글"), member, techArticle, originParentTechComment1, parentTechComment1, new Count(0L), new Count(0L), new Count(0L)); - TechComment techComment2 = createRepliedTechComment(new CommentContents("최상위 댓글1의 답글2의 답글"), member, - techArticle, originParentTechComment1, parentTechComment2, new Count(0L), new Count(0L), new Count(0L)); - TechComment techcomment1 = createRepliedTechComment(new CommentContents("최상위 댓글1의 답글1의 답글"), member, - techArticle, originParentTechComment1, parentTechComment1, new Count(0L), new Count(0L), new Count(0L)); - TechComment techcomment2 = createRepliedTechComment(new CommentContents("최상위 댓글1의 답글2의 답글"), member, + TechComment techComment2 = createRepliedTechComment(new CommentContents("최상위 댓글1의 답글2의 답글"), anonymousMember, techArticle, originParentTechComment1, parentTechComment2, new Count(0L), new Count(0L), new Count(0L)); techCommentRepository.saveAll(List.of( @@ -837,60 +832,15 @@ techArticle, originParentTechComment2, originParentTechComment2, new Count(0L), .header(AUTHORIZATION_HEADER, SecurityConstant.BEARER_PREFIX + accessToken) .characterEncoding(StandardCharsets.UTF_8)) .andDo(print()) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.resultType").value(ResultType.SUCCESS.name())) - .andExpect(jsonPath("$.data").isNotEmpty()) - .andExpect(jsonPath("$.data.content").isArray()) - .andExpect(jsonPath("$.data.content.[0].techCommentId").isNumber()) - .andExpect(jsonPath("$.data.content.[0].createdAt").isString()) - .andExpect(jsonPath("$.data.content.[0].memberId").isNumber()) - .andExpect(jsonPath("$.data.content.[0].author").isString()) - .andExpect(jsonPath("$.data.content.[0].maskedEmail").isString()) - .andExpect(jsonPath("$.data.content.[0].contents").isString()) - .andExpect(jsonPath("$.data.content.[0].replyTotalCount").isNumber()) - .andExpect(jsonPath("$.data.content.[0].recommendTotalCount").isNumber()) - .andExpect(jsonPath("$.data.content.[0].isDeleted").isBoolean()) - .andExpect(jsonPath("$.data.content.[0].isRecommended").isBoolean()) - .andExpect(jsonPath("$.data.content.[0].replies.[0].techCommentId").isNumber()) - .andExpect(jsonPath("$.data.content.[0].replies.[0].memberId").isNumber()) - .andExpect(jsonPath("$.data.content.[0].replies.[0].techParentCommentId").isNumber()) - .andExpect(jsonPath("$.data.content.[0].replies.[0].techOriginParentCommentId").isNumber()) - .andExpect(jsonPath("$.data.content.[0].replies.[0].createdAt").isString()) - .andExpect(jsonPath("$.data.content.[0].replies.[0].author").isString()) - .andExpect(jsonPath("$.data.content.[0].replies.[0].maskedEmail").isString()) - .andExpect(jsonPath("$.data.content.[0].replies.[0].contents").isString()) - .andExpect(jsonPath("$.data.content.[0].replies.[0].techParentCommentMemberId").isNumber()) - .andExpect(jsonPath("$.data.content.[0].replies.[0].techParentCommentAuthor").isString()) - .andExpect(jsonPath("$.data.content.[0].replies.[0].recommendTotalCount").isNumber()) - .andExpect(jsonPath("$.data.content.[0].replies.[0].isDeleted").isBoolean()) - .andExpect(jsonPath("$.data.content.[0].replies.[0].isRecommended").isBoolean()) - .andExpect(jsonPath("$.data.pageable").isNotEmpty()) - .andExpect(jsonPath("$.data.pageable.pageNumber").isNumber()) - .andExpect(jsonPath("$.data.pageable.pageSize").isNumber()) - .andExpect(jsonPath("$.data.pageable.sort").isNotEmpty()) - .andExpect(jsonPath("$.data.pageable.sort.empty").isBoolean()) - .andExpect(jsonPath("$.data.pageable.sort.sorted").isBoolean()) - .andExpect(jsonPath("$.data.pageable.sort.unsorted").isBoolean()) - .andExpect(jsonPath("$.data.pageable.offset").isNumber()) - .andExpect(jsonPath("$.data.pageable.paged").isBoolean()) - .andExpect(jsonPath("$.data.pageable.unpaged").isBoolean()) - .andExpect(jsonPath("$.data.first").isBoolean()) - .andExpect(jsonPath("$.data.last").isBoolean()) - .andExpect(jsonPath("$.data.size").isNumber()) - .andExpect(jsonPath("$.data.number").isNumber()) - .andExpect(jsonPath("$.data.sort").isNotEmpty()) - .andExpect(jsonPath("$.data.sort.empty").isBoolean()) - .andExpect(jsonPath("$.data.sort.sorted").isBoolean()) - .andExpect(jsonPath("$.data.sort.unsorted").isBoolean()) - .andExpect(jsonPath("$.data.numberOfElements").isNumber()) - .andExpect(jsonPath("$.data.empty").isBoolean()); + .andExpect(status().isOk()); // docs actions.andDo(document("get-tech-comments", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), requestHeaders( - headerWithName(AUTHORIZATION_HEADER).optional().description("Bearer 엑세스 토큰") + headerWithName(AUTHORIZATION_HEADER).optional().description("Bearer 엑세스 토큰"), + headerWithName(HEADER_ANONYMOUS_MEMBER_ID).optional().description("익명회원 아이디") ), pathParameters( parameterWithName("techArticleId").description("기술블로그 아이디") @@ -908,9 +858,11 @@ techArticle, originParentTechComment2, originParentTechComment2, new Count(0L), fieldWithPath("data.content").type(ARRAY).description("기술블로그 댓글/답글 메인 배열"), fieldWithPath("data.content[].techCommentId").type(NUMBER).description("기술블로그 댓글 아이디"), fieldWithPath("data.content[].createdAt").type(STRING).description("기술블로그 댓글 작성일시"), - fieldWithPath("data.content[].memberId").type(NUMBER).description("기술블로그 댓글 작성자 아이디"), + fieldWithPath("data.content[].memberId").optional().type(NUMBER).description("기술블로그 댓글 작성자 아이디"), + fieldWithPath("data.content[].anonymousMemberId").optional().type(NUMBER) + .description("기술블로그 댓글 익명 작성자 아이디"), fieldWithPath("data.content[].author").type(STRING).description("기술블로그 댓글 작성자 닉네임"), - fieldWithPath("data.content[].maskedEmail").type(STRING).description("기술블로그 댓글 작성자 이메일"), + fieldWithPath("data.content[].maskedEmail").type(STRING).optional().description("기술블로그 댓글 작성자 이메일"), fieldWithPath("data.content[].contents").type(STRING).description("기술블로그 댓글 내용"), fieldWithPath("data.content[].isCommentAuthor").type(BOOLEAN) .description("회원의 기술블로그 댓글 작성자 여부"), @@ -929,19 +881,23 @@ techArticle, originParentTechComment2, originParentTechComment2, new Count(0L), fieldWithPath("data.content[].replies[].techCommentId").type(NUMBER) .description("기술블로그 답글 아이디"), fieldWithPath("data.content[].replies[].memberId").type(NUMBER).description("기술블로그 답글 작성자 아이디"), + fieldWithPath("data.content[].replies[].anonymousMemberId").optional().type(NUMBER) + .description("기술블로그 답글 익명 작성자 아이디"), fieldWithPath("data.content[].replies[].techParentCommentId").type(NUMBER) .description("기술블로그 답글의 부모 댓글 아이디"), fieldWithPath("data.content[].replies[].techOriginParentCommentId").type(NUMBER) .description("기술블로그 답글의 최상위 부모 댓글 아이디"), fieldWithPath("data.content[].replies[].createdAt").type(STRING).description("기술블로그 답글 작성일시"), - fieldWithPath("data.content[].replies[].techParentCommentMemberId").type(NUMBER) + fieldWithPath("data.content[].replies[].techParentCommentMemberId").optional().type(NUMBER) .description("기술블로그 답글의 부모 댓글 작성자 아이디"), + fieldWithPath("data.content[].replies[].techParentCommentAnonymousMemberId").optional().type(NUMBER) + .description("기술블로그 답글의 부모 댓글 익명 작성자 아이디"), fieldWithPath("data.content[].replies[].techParentCommentAuthor").type(STRING) .description("기술블로그 답글의 부모 댓글 작성자 닉네임"), fieldWithPath("data.content[].replies[].author").type(STRING).description("기술블로그 답글 작성자 닉네임"), fieldWithPath("data.content[].replies[].isCommentAuthor").type(BOOLEAN) .description("회원의 기술블로그 답글 작성자 여부"), - fieldWithPath("data.content[].replies[].maskedEmail").type(STRING) + fieldWithPath("data.content[].replies[].maskedEmail").type(STRING).optional() .description("기술블로그 답글 작성자 이메일"), fieldWithPath("data.content[].replies[].contents").type(STRING).description("기술블로그 답글 내용"), fieldWithPath("data.content[].replies[].recommendTotalCount").type(NUMBER) @@ -1024,7 +980,8 @@ void recommendTechComment() throws Exception { preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), requestHeaders( - headerWithName(AUTHORIZATION_HEADER).description("Bearer 엑세스 토큰") + headerWithName(AUTHORIZATION_HEADER).optional().description("Bearer 엑세스 토큰"), + headerWithName(HEADER_ANONYMOUS_MEMBER_ID).optional().description("익명회원 아이디") ), pathParameters( parameterWithName("techArticleId").description("기술블로그 아이디"), @@ -1109,6 +1066,10 @@ void getTechBestComments() throws Exception { Member member3 = Member.createMemberBy(socialMemberDto3); memberRepository.saveAll(List.of(member1, member2, member3)); + // 익명회원 생성 + AnonymousMember anonymousMember = AnonymousMember.create("anonymousMemberId", "익명으로 개발하는 댑댑이"); + anonymousMemberRepository.save(anonymousMember); + // 회사 생성 Company company = createCompany("꿈빛 파티시엘", "https://example.com/company.png", "https://example.com", "https://example.com"); @@ -1121,7 +1082,7 @@ void getTechBestComments() throws Exception { techArticleRepository.save(techArticle); // 댓글 생성 - TechComment originParentTechComment1 = createMainTechComment(new CommentContents("최상위 댓글1"), member1, + TechComment originParentTechComment1 = createMainTechComment(new CommentContents("최상위 댓글1"), anonymousMember, techArticle, new Count(0L), new Count(3L), new Count(0L)); originParentTechComment1.modifyCommentContents(new CommentContents("최상위 댓글1 수정"), LocalDateTime.now()); TechComment originParentTechComment2 = createMainTechComment(new CommentContents("최상위 댓글1"), member2, @@ -1156,7 +1117,8 @@ techArticle, originParentTechComment1, originParentTechComment1, new Count(0L), preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), requestHeaders( - headerWithName(AUTHORIZATION_HEADER).optional().description("Bearer 엑세스 토큰") + headerWithName(AUTHORIZATION_HEADER).optional().description("Bearer 엑세스 토큰"), + headerWithName(HEADER_ANONYMOUS_MEMBER_ID).optional().description("익명회원 아이디") ), pathParameters( parameterWithName("techArticleId").description("기술블로그 아이디") @@ -1170,26 +1132,25 @@ techArticle, originParentTechComment1, originParentTechComment1, new Count(0L), fieldWithPath("datas.[].techCommentId").type(NUMBER).description("기술블로그 댓글 아이디"), fieldWithPath("datas.[].createdAt").type(STRING).description("기술블로그 댓글 작성일시"), - fieldWithPath("datas.[].memberId").type(NUMBER).description("기술블로그 댓글 작성자 아이디"), + fieldWithPath("datas.[].memberId").type(NUMBER).optional().description("기술블로그 댓글 작성자 아이디"), + fieldWithPath("datas.[].anonymousMemberId").type(NUMBER).optional().description("기술블로그 댓글 익명 작성자 아이디"), fieldWithPath("datas.[].author").type(STRING).description("기술블로그 댓글 작성자 닉네임"), fieldWithPath("datas.[].isCommentAuthor").type(BOOLEAN) .description("로그인한 회원이 댓글 작성자인지 여부"), fieldWithPath("datas.[].isRecommended").type(BOOLEAN) .description("로그인한 회원이 댓글 추천 여부"), - fieldWithPath("datas.[].maskedEmail").type(STRING).description("기술블로그 댓글 작성자 이메일"), + fieldWithPath("datas.[].maskedEmail").optional().type(STRING).description("기술블로그 댓글 작성자 이메일"), fieldWithPath("datas.[].contents").type(STRING).description("기술블로그 댓글 내용"), - fieldWithPath("datas.[].replyTotalCount").type(NUMBER) - .description("기술블로그 댓글의 답글 총 갯수"), - fieldWithPath("datas.[].recommendTotalCount").type(NUMBER) - .description("기술블로그 댓글 좋아요 총 갯수"), - fieldWithPath("datas.[].isDeleted").type(BOOLEAN) - .description("기술블로그 댓글 삭제 여부"), - fieldWithPath("datas.[].isModified").type(BOOLEAN) - .description("기술블로그 댓글 수정 여부"), + fieldWithPath("datas.[].replyTotalCount").type(NUMBER).description("기술블로그 댓글의 답글 총 갯수"), + fieldWithPath("datas.[].recommendTotalCount").type(NUMBER).description("기술블로그 댓글 좋아요 총 갯수"), + fieldWithPath("datas.[].isDeleted").type(BOOLEAN).description("기술블로그 댓글 삭제 여부"), + fieldWithPath("datas.[].isModified").type(BOOLEAN).description("기술블로그 댓글 수정 여부"), fieldWithPath("datas.[].replies").type(ARRAY).description("기술블로그 답글 배열"), fieldWithPath("datas.[].replies[].techCommentId").type(NUMBER).description("기술블로그 답글 아이디"), - fieldWithPath("datas.[].replies[].memberId").type(NUMBER).description("기술블로그 답글 작성자 아이디"), + fieldWithPath("datas.[].replies[].memberId").optional().type(NUMBER).description("기술블로그 답글 작성자 아이디"), + fieldWithPath("datas.[].replies[].anonymousMemberId").optional().type(NUMBER) + .description("기술블로그 답글 익명 작성자 아이디"), fieldWithPath("datas.[].replies[].techParentCommentId").type(NUMBER) .description("기술블로그 답글의 부모 댓글 아이디"), fieldWithPath("datas.[].replies[].techOriginParentCommentId").type(NUMBER) @@ -1209,78 +1170,13 @@ techArticle, originParentTechComment1, originParentTechComment1, new Count(0L), .description("기술블로그 답글 삭제 여부"), fieldWithPath("datas.[].replies[].isModified").type(BOOLEAN) .description("기술블로그 답글 수정 여부"), - fieldWithPath("datas.[].replies[].techParentCommentMemberId").type(NUMBER) - .description("기술블로그 부모 댓글 작성자 아이디"), + fieldWithPath("datas.[].replies[].techParentCommentMemberId").optional().type(NUMBER).description( + "기술블로그 부모 댓글 작성자 아이디"), + fieldWithPath("datas.[].replies[].techParentCommentAnonymousMemberId").optional().type(NUMBER) + .description("기술블로그 부모 댓글 익명 작성자 아이디"), fieldWithPath("datas.[].replies[].techParentCommentAuthor").type(STRING) .description("기술블로그 부모 댓글 작성자 닉네임") ) )); } - - private TechCommentRecommend createTechCommentRecommend(Boolean recommendedStatus, TechComment techComment, - Member member) { - TechCommentRecommend techCommentRecommend = TechCommentRecommend.builder() - .recommendedStatus(recommendedStatus) - .techComment(techComment) - .member(member) - .build(); - - techCommentRecommend.changeTechComment(techComment); - - return techCommentRecommend; - } - - private SocialMemberDto createSocialDto(String userId, String name, String nickName, String password, String email, - String socialType, String role) { - return SocialMemberDto.builder() - .userId(userId) - .name(name) - .nickname(nickName) - .password(password) - .email(email) - .socialType(SocialType.valueOf(socialType)) - .role(Role.valueOf(role)) - .build(); - } - - private static Company createCompany(String companyName, String officialImageUrl, String officialUrl, - String careerUrl) { - return Company.builder() - .name(new CompanyName(companyName)) - .officialImageUrl(new Url(officialImageUrl)) - .careerUrl(new Url(careerUrl)) - .officialUrl(new Url(officialUrl)) - .build(); - } - - private static TechComment createMainTechComment(CommentContents contents, Member createdBy, - TechArticle techArticle, - Count blameTotalCount, Count recommendTotalCount, - Count replyTotalCount) { - return TechComment.builder() - .contents(contents) - .createdBy(createdBy) - .techArticle(techArticle) - .blameTotalCount(blameTotalCount) - .recommendTotalCount(recommendTotalCount) - .replyTotalCount(replyTotalCount) - .build(); - } - - private static TechComment createRepliedTechComment(CommentContents contents, Member createdBy, - TechArticle techArticle, - TechComment originParent, TechComment parent, - Count blameTotalCount, Count recommendTotalCount, - Count replyTotalCount) { - return TechComment.builder() - .contents(contents) - .createdBy(createdBy) - .techArticle(techArticle) - .blameTotalCount(blameTotalCount) - .recommendTotalCount(recommendTotalCount) - .replyTotalCount(replyTotalCount) - .originParent(originParent) - .parent(parent) - .build(); - } }