From 46923759be34feece7c3283e9c723e26e108575a Mon Sep 17 00:00:00 2001 From: JunH Date: Wed, 18 Oct 2023 12:05:19 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20(#757)=20=EC=8B=A0=EA=B3=A0=20=EC=A1=B0?= =?UTF-8?q?=EC=B9=98=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/exception/MemberExceptionType.java | 2 +- .../domain/member/service/MemberService.java | 2 +- .../controller/ReportCommandController.java | 7 + .../ReportCommandControllerDocs.java | 23 ++ .../dto/request/ReportActionRequest.java | 17 + .../report/exception/ReportExceptionType.java | 1 + .../repository/ReportCustomRepository.java | 6 +- .../ReportCustomRepositoryImpl.java | 31 +- .../report/service/ReportCommandService.java | 25 ++ .../report/service/ReportQueryService.java | 2 +- .../strategy/ReportCommentStrategy.java | 31 +- .../strategy/ReportNicknameStrategy.java | 47 ++- .../service/strategy/ReportPostStrategy.java | 31 +- .../service/strategy/ReportStrategy.java | 3 + .../ReportActionAlarmRepositoryTest.java | 6 +- .../ReportCommandControllerTest.java | 98 +++-- .../controller/ReportQueryControllerTest.java | 20 +- .../ReportCustomRepositoryImplTest.java | 68 +++- .../service/ReportCommandServiceTest.java | 339 ++++++++++++++---- .../service/ReportQueryServiceTest.java | 12 +- .../strategy/ReportCommentStrategyTest.java | 118 ++++-- .../strategy/ReportNicknameStrategyTest.java | 96 +++-- .../strategy/ReportPostStrategyTest.java | 120 +++++-- 23 files changed, 843 insertions(+), 262 deletions(-) create mode 100644 backend/src/main/java/com/votogether/domain/report/dto/request/ReportActionRequest.java diff --git a/backend/src/main/java/com/votogether/domain/member/exception/MemberExceptionType.java b/backend/src/main/java/com/votogether/domain/member/exception/MemberExceptionType.java index 67546d872..a824e406d 100644 --- a/backend/src/main/java/com/votogether/domain/member/exception/MemberExceptionType.java +++ b/backend/src/main/java/com/votogether/domain/member/exception/MemberExceptionType.java @@ -9,7 +9,7 @@ public enum MemberExceptionType implements ExceptionType { INVALID_NICKNAME_LENGTH(800, "닉네임의 길이가 올바르지 않습니다."), INVALID_NICKNAME_LETTER(801, "닉네임에 들어갈 수 없는 문자가 포함되어 있습니다."), ALREADY_EXISTENT_NICKNAME(802, "이미 중복된 닉네임이 존재합니다."), - NONEXISTENT_MEMBER(803, "해당 회원이 존재하지 않습니다."), + NON_EXISTENT_MEMBER(803, "해당 회원이 존재하지 않습니다."), INVALID_AGE(804, "존재할 수 없는 연령입니다."), ALREADY_ASSIGNED_GENDER(805, "이미 성별이 할당되어 있습니다."), ALREADY_ASSIGNED_BIRTH_YEAR(806, "이미 출생년도가 할당되어 있습니다."), diff --git a/backend/src/main/java/com/votogether/domain/member/service/MemberService.java b/backend/src/main/java/com/votogether/domain/member/service/MemberService.java index adc6bdb7f..f6f351f72 100644 --- a/backend/src/main/java/com/votogether/domain/member/service/MemberService.java +++ b/backend/src/main/java/com/votogether/domain/member/service/MemberService.java @@ -50,7 +50,7 @@ public Member register(final Member member) { @Transactional(readOnly = true) public Member findById(final Long memberId) { return memberRepository.findById(memberId) - .orElseThrow(() -> new NotFoundException(MemberExceptionType.NONEXISTENT_MEMBER)); + .orElseThrow(() -> new NotFoundException(MemberExceptionType.NON_EXISTENT_MEMBER)); } @Transactional(readOnly = true) diff --git a/backend/src/main/java/com/votogether/domain/report/controller/ReportCommandController.java b/backend/src/main/java/com/votogether/domain/report/controller/ReportCommandController.java index 2cab9c34a..8265fc599 100644 --- a/backend/src/main/java/com/votogether/domain/report/controller/ReportCommandController.java +++ b/backend/src/main/java/com/votogether/domain/report/controller/ReportCommandController.java @@ -1,6 +1,7 @@ package com.votogether.domain.report.controller; import com.votogether.domain.member.entity.Member; +import com.votogether.domain.report.dto.request.ReportActionRequest; import com.votogether.domain.report.dto.request.ReportRequest; import com.votogether.domain.report.service.ReportCommandService; import com.votogether.global.jwt.Auth; @@ -23,4 +24,10 @@ public ResponseEntity report(@Valid @RequestBody final ReportRequest reque return ResponseEntity.ok().build(); } + @PostMapping("/reports/action/admin") + public ResponseEntity reportAction(@Valid @RequestBody final ReportActionRequest request) { + reportCommandService.reportAction(request); + return ResponseEntity.ok().build(); + } + } diff --git a/backend/src/main/java/com/votogether/domain/report/controller/ReportCommandControllerDocs.java b/backend/src/main/java/com/votogether/domain/report/controller/ReportCommandControllerDocs.java index aab4566b5..9418a37f4 100644 --- a/backend/src/main/java/com/votogether/domain/report/controller/ReportCommandControllerDocs.java +++ b/backend/src/main/java/com/votogether/domain/report/controller/ReportCommandControllerDocs.java @@ -1,6 +1,7 @@ package com.votogether.domain.report.controller; import com.votogether.domain.member.entity.Member; +import com.votogether.domain.report.dto.request.ReportActionRequest; import com.votogether.domain.report.dto.request.ReportRequest; import com.votogether.global.exception.ExceptionResponse; import io.swagger.v3.oas.annotations.Operation; @@ -9,6 +10,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.constraints.Positive; import org.springframework.http.ResponseEntity; @Tag(name = "신고", description = "신고 API") @@ -30,4 +32,25 @@ public interface ReportCommandControllerDocs { }) ResponseEntity report(final ReportRequest request, final Member member); + @Operation(summary = "신고 조치", description = "신고를 조치한다.") + @ApiResponses({ + @ApiResponse( + responseCode = "200", + description = "신고 조치 성공" + ), + @ApiResponse( + responseCode = "400", + description = """ + 1.신고 ID가 양의 정수가 아닌 경우 + """, + content = @Content(schema = @Schema(implementation = ExceptionResponse.class)) + ), + @ApiResponse( + responseCode = "404", + description = "존재하지 않는 신고", + content = @Content(schema = @Schema(implementation = ExceptionResponse.class)) + ) + }) + ResponseEntity reportAction(final ReportActionRequest request); + } diff --git a/backend/src/main/java/com/votogether/domain/report/dto/request/ReportActionRequest.java b/backend/src/main/java/com/votogether/domain/report/dto/request/ReportActionRequest.java new file mode 100644 index 000000000..5d38b21e7 --- /dev/null +++ b/backend/src/main/java/com/votogether/domain/report/dto/request/ReportActionRequest.java @@ -0,0 +1,17 @@ +package com.votogether.domain.report.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; + +@Schema(description = "신고 조치 요청") +public record ReportActionRequest( + @Schema(description = "신고 ID", example = "1") + @NotNull(message = "신고 ID는 빈 값일 수 없습니다.") + @Positive(message = "신고 ID는 양의 정수만 가능합니다.") + Long id, + + @Schema(description = "신고 조치 여부", example = "true") + boolean hasAction +) { +} diff --git a/backend/src/main/java/com/votogether/domain/report/exception/ReportExceptionType.java b/backend/src/main/java/com/votogether/domain/report/exception/ReportExceptionType.java index ea38d6342..407d35008 100644 --- a/backend/src/main/java/com/votogether/domain/report/exception/ReportExceptionType.java +++ b/backend/src/main/java/com/votogether/domain/report/exception/ReportExceptionType.java @@ -14,6 +14,7 @@ public enum ReportExceptionType implements ExceptionType { DUPLICATE_COMMENT_REPORT(1205, "하나의 댓글에 대해서 중복하여 신고할 수 없습니다."), REPORT_MY_NICKNAME(1206, "자신의 닉네임은 신고할 수 없습니다."), DUPLICATE_NICKNAME_REPORT(1207, "하나의 닉네임에 대해서 중복하여 신고할 수 없습니다."), + NOT_FOUND(1208, "신고가 존재하지 않습니다.") ; private final int code; diff --git a/backend/src/main/java/com/votogether/domain/report/repository/ReportCustomRepository.java b/backend/src/main/java/com/votogether/domain/report/repository/ReportCustomRepository.java index 1c9616ca6..9c97d95c7 100644 --- a/backend/src/main/java/com/votogether/domain/report/repository/ReportCustomRepository.java +++ b/backend/src/main/java/com/votogether/domain/report/repository/ReportCustomRepository.java @@ -1,11 +1,15 @@ package com.votogether.domain.report.repository; import com.votogether.domain.report.dto.ReportAggregateDto; +import com.votogether.domain.report.entity.vo.ReportType; import java.util.List; +import java.util.Optional; import org.springframework.data.domain.Pageable; public interface ReportCustomRepository { - List findReportsGroupedByReportTypeAndTargetId(final Pageable pageable); + List findReportAggregateDtosByReportTypeAndTargetId(final Pageable pageable); + + Optional findReportAggregateDtoByReportTypeAndTargetId(ReportType reportType, Long targetId); } diff --git a/backend/src/main/java/com/votogether/domain/report/repository/ReportCustomRepositoryImpl.java b/backend/src/main/java/com/votogether/domain/report/repository/ReportCustomRepositoryImpl.java index 55c7f2ed4..cc353fa23 100644 --- a/backend/src/main/java/com/votogether/domain/report/repository/ReportCustomRepositoryImpl.java +++ b/backend/src/main/java/com/votogether/domain/report/repository/ReportCustomRepositoryImpl.java @@ -6,7 +6,9 @@ import com.querydsl.core.types.dsl.Expressions; import com.querydsl.jpa.impl.JPAQueryFactory; import com.votogether.domain.report.dto.ReportAggregateDto; +import com.votogether.domain.report.entity.vo.ReportType; import java.util.List; +import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Repository; @@ -18,7 +20,7 @@ public class ReportCustomRepositoryImpl implements ReportCustomRepository { private final JPAQueryFactory jpaQueryFactory; @Override - public List findReportsGroupedByReportTypeAndTargetId(final Pageable pageable) { + public List findReportAggregateDtosByReportTypeAndTargetId(final Pageable pageable) { return jpaQueryFactory.select( Projections.constructor( ReportAggregateDto.class, @@ -37,4 +39,31 @@ public List findReportsGroupedByReportTypeAndTargetId(final .fetch(); } + @Override + public Optional findReportAggregateDtoByReportTypeAndTargetId( + final ReportType reportType, + final Long targetId + ) { + ReportAggregateDto result = jpaQueryFactory.select( + Projections.constructor( + ReportAggregateDto.class, + report.id.max(), + report.reportType, + report.targetId, + Expressions.stringTemplate("group_concat({0})", report.reason), + report.createdAt.max() + ) + ) + .from(report) + .where( + report.reportType.eq(reportType), + report.targetId.eq(targetId) + ) + .groupBy(report.reportType, report.targetId) + .fetchOne(); + + return Optional.ofNullable(result); + } + + } diff --git a/backend/src/main/java/com/votogether/domain/report/service/ReportCommandService.java b/backend/src/main/java/com/votogether/domain/report/service/ReportCommandService.java index 54169af0e..4829bff92 100644 --- a/backend/src/main/java/com/votogether/domain/report/service/ReportCommandService.java +++ b/backend/src/main/java/com/votogether/domain/report/service/ReportCommandService.java @@ -1,9 +1,15 @@ package com.votogether.domain.report.service; import com.votogether.domain.member.entity.Member; +import com.votogether.domain.report.dto.ReportAggregateDto; +import com.votogether.domain.report.dto.request.ReportActionRequest; import com.votogether.domain.report.dto.request.ReportRequest; +import com.votogether.domain.report.entity.Report; +import com.votogether.domain.report.exception.ReportExceptionType; +import com.votogether.domain.report.repository.ReportRepository; import com.votogether.domain.report.service.strategy.ReportActionProvider; import com.votogether.domain.report.service.strategy.ReportStrategy; +import com.votogether.global.exception.NotFoundException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -14,10 +20,29 @@ public class ReportCommandService { private final ReportActionProvider reportActionProvider; + private final ReportRepository reportRepository; public void report(final Member reporter, final ReportRequest request) { final ReportStrategy reportStrategy = reportActionProvider.getStrategy(request.type()); reportStrategy.report(reporter, request); } + public void reportAction(final ReportActionRequest request) { + final Report report = reportRepository.findById(request.id()) + .orElseThrow(() -> new NotFoundException(ReportExceptionType.NOT_FOUND)); + + final ReportAggregateDto reportAggregateDto = reportRepository + .findReportAggregateDtoByReportTypeAndTargetId(report.getReportType(), report.getTargetId()) + .orElseThrow(() -> new NotFoundException(ReportExceptionType.NOT_FOUND)); + + reportRepository.deleteAllWithReportTypeAndTargetIdInBatch(report.getReportType(), report.getTargetId()); + + if (!request.hasAction()) { + return; + } + + final ReportStrategy strategy = reportActionProvider.getStrategy(reportAggregateDto.reportType()); + strategy.reportAction(reportAggregateDto); + } + } diff --git a/backend/src/main/java/com/votogether/domain/report/service/ReportQueryService.java b/backend/src/main/java/com/votogether/domain/report/service/ReportQueryService.java index 8bee3e6bd..5dfa30dd4 100644 --- a/backend/src/main/java/com/votogether/domain/report/service/ReportQueryService.java +++ b/backend/src/main/java/com/votogether/domain/report/service/ReportQueryService.java @@ -29,7 +29,7 @@ public ReportPageResponse getReports(final int page) { final Pageable pageable = PageRequest.of(page, BASIC_PAGE_SIZE); final List reportAggregateDtos = reportRepository - .findReportsGroupedByReportTypeAndTargetId(pageable); + .findReportAggregateDtosByReportTypeAndTargetId(pageable); final List reportResponses = parseReportResponses(reportAggregateDtos); return ReportPageResponse.of(totalPageNumber, page, reportResponses); diff --git a/backend/src/main/java/com/votogether/domain/report/service/strategy/ReportCommentStrategy.java b/backend/src/main/java/com/votogether/domain/report/service/strategy/ReportCommentStrategy.java index 8d0a79842..b630a5e87 100644 --- a/backend/src/main/java/com/votogether/domain/report/service/strategy/ReportCommentStrategy.java +++ b/backend/src/main/java/com/votogether/domain/report/service/strategy/ReportCommentStrategy.java @@ -1,9 +1,12 @@ package com.votogether.domain.report.service.strategy; +import com.votogether.domain.alarm.entity.ReportActionAlarm; +import com.votogether.domain.alarm.repository.ReportActionAlarmRepository; import com.votogether.domain.member.entity.Member; import com.votogether.domain.post.entity.comment.Comment; import com.votogether.domain.post.exception.CommentExceptionType; import com.votogether.domain.post.repository.CommentRepository; +import com.votogether.domain.report.dto.ReportAggregateDto; import com.votogether.domain.report.dto.request.ReportRequest; import com.votogether.domain.report.exception.ReportExceptionType; import com.votogether.domain.report.repository.ReportRepository; @@ -16,10 +19,9 @@ @Component public class ReportCommentStrategy implements ReportStrategy { - private static final int NUMBER_OF_COMMENT_BLIND_BASED_REPORTS = 5; - private final CommentRepository commentRepository; private final ReportRepository reportRepository; + private final ReportActionAlarmRepository reportActionAlarmRepository; @Override public void report(final Member reporter, final ReportRequest request) { @@ -28,7 +30,6 @@ public void report(final Member reporter, final ReportRequest request) { validateComment(reporter, request, reportedComment); saveReport(reporter, request, reportRepository); - blindComment(request, reportedComment); } private void validateComment( @@ -46,13 +47,6 @@ private void validateComment( ); } - private void blindComment(final ReportRequest request, final Comment reportedComment) { - final int reportCount = reportRepository.countByReportTypeAndTargetId(request.type(), request.id()); - if (reportCount >= NUMBER_OF_COMMENT_BLIND_BASED_REPORTS) { - reportedComment.blind(); - } - } - private void validateHiddenComment(final Comment comment) { if (comment.isHidden()) { throw new BadRequestException(CommentExceptionType.IS_HIDDEN); @@ -72,4 +66,21 @@ public String parseTarget(final Long targetId) { return reportedComment.getContent(); } + @Override + public void reportAction(final ReportAggregateDto reportAggregateDto) { + final Comment comment = commentRepository.findById(reportAggregateDto.targetId()) + .orElseThrow(() -> new NotFoundException(CommentExceptionType.NOT_FOUND)); + + final ReportActionAlarm reportActionAlarm = ReportActionAlarm.builder() + .member(comment.getWriter()) + .reportType(reportAggregateDto.reportType()) + .target(comment.getContent()) + .reasons(reportAggregateDto.reasons()) + .isChecked(false) + .build(); + + reportActionAlarmRepository.save(reportActionAlarm); + comment.blind(); + } + } diff --git a/backend/src/main/java/com/votogether/domain/report/service/strategy/ReportNicknameStrategy.java b/backend/src/main/java/com/votogether/domain/report/service/strategy/ReportNicknameStrategy.java index 76d5fd6dd..5483e4a99 100644 --- a/backend/src/main/java/com/votogether/domain/report/service/strategy/ReportNicknameStrategy.java +++ b/backend/src/main/java/com/votogether/domain/report/service/strategy/ReportNicknameStrategy.java @@ -1,15 +1,18 @@ package com.votogether.domain.report.service.strategy; +import com.votogether.domain.alarm.entity.ReportActionAlarm; +import com.votogether.domain.alarm.repository.ReportActionAlarmRepository; import com.votogether.domain.member.entity.Member; import com.votogether.domain.member.exception.MemberExceptionType; import com.votogether.domain.member.repository.MemberRepository; +import com.votogether.domain.report.dto.ReportAggregateDto; import com.votogether.domain.report.dto.request.ReportRequest; -import com.votogether.domain.report.entity.vo.ReportType; import com.votogether.domain.report.exception.ReportExceptionType; import com.votogether.domain.report.repository.ReportRepository; import com.votogether.global.exception.BadRequestException; import com.votogether.global.exception.NotFoundException; import java.util.Objects; +import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; @@ -17,19 +20,22 @@ @Component public class ReportNicknameStrategy implements ReportStrategy { - private static final int NUMBER_OF_NICKNAME_CHANGE_REPORTS = 3; - private final MemberRepository memberRepository; private final ReportRepository reportRepository; + private final ReportActionAlarmRepository reportActionAlarmRepository; @Override public void report(final Member reporter, final ReportRequest request) { - final Member reportedMember = memberRepository.findById(request.id()) - .orElseThrow(() -> new NotFoundException(MemberExceptionType.NONEXISTENT_MEMBER)); + validateMemberExistence(request); validateNickname(reporter, request); - saveReport(reporter, request, reportRepository); - changeNicknameByReport(reportedMember, request); + } + + private void validateMemberExistence(final ReportRequest request) { + final Optional memberById = memberRepository.findById(request.id()); + if (memberById.isEmpty()) { + throw new NotFoundException(MemberExceptionType.NON_EXISTENT_MEMBER); + } } private void validateNickname(final Member reporter, final ReportRequest request) { @@ -48,19 +54,28 @@ private void validateMyNickname(final Member reporter, final ReportRequest reque } } - private void changeNicknameByReport(final Member reportedMember, final ReportRequest request) { - final int reportCount = reportRepository.countByReportTypeAndTargetId(request.type(), reportedMember.getId()); - if (reportCount >= NUMBER_OF_NICKNAME_CHANGE_REPORTS) { - reportedMember.changeNicknameByReport(); - reportRepository.deleteAllWithReportTypeAndTargetIdInBatch(ReportType.NICKNAME, request.id()); - } - } - @Override public String parseTarget(final Long targetId) { final Member reportedMember = memberRepository.findById(targetId) - .orElseThrow(() -> new NotFoundException(MemberExceptionType.NONEXISTENT_MEMBER)); + .orElseThrow(() -> new NotFoundException(MemberExceptionType.NON_EXISTENT_MEMBER)); return reportedMember.getNickname(); } + @Override + public void reportAction(final ReportAggregateDto reportAggregateDto) { + final Member reportedMember = memberRepository.findById(reportAggregateDto.targetId()) + .orElseThrow(() -> new NotFoundException(MemberExceptionType.NON_EXISTENT_MEMBER)); + + final ReportActionAlarm reportActionAlarm = ReportActionAlarm.builder() + .member(reportedMember) + .reportType(reportAggregateDto.reportType()) + .target(reportedMember.getNickname()) + .reasons(reportAggregateDto.reasons()) + .isChecked(false) + .build(); + + reportActionAlarmRepository.save(reportActionAlarm); + reportedMember.changeNicknameByReport(); + } + } diff --git a/backend/src/main/java/com/votogether/domain/report/service/strategy/ReportPostStrategy.java b/backend/src/main/java/com/votogether/domain/report/service/strategy/ReportPostStrategy.java index 5f5d4c342..573f68ff6 100644 --- a/backend/src/main/java/com/votogether/domain/report/service/strategy/ReportPostStrategy.java +++ b/backend/src/main/java/com/votogether/domain/report/service/strategy/ReportPostStrategy.java @@ -1,9 +1,12 @@ package com.votogether.domain.report.service.strategy; +import com.votogether.domain.alarm.entity.ReportActionAlarm; +import com.votogether.domain.alarm.repository.ReportActionAlarmRepository; import com.votogether.domain.member.entity.Member; import com.votogether.domain.post.entity.Post; import com.votogether.domain.post.exception.PostExceptionType; import com.votogether.domain.post.repository.PostRepository; +import com.votogether.domain.report.dto.ReportAggregateDto; import com.votogether.domain.report.dto.request.ReportRequest; import com.votogether.domain.report.exception.ReportExceptionType; import com.votogether.domain.report.repository.ReportRepository; @@ -16,10 +19,9 @@ @Component public class ReportPostStrategy implements ReportStrategy { - private static final int NUMBER_OF_POST_BLIND_BASED_REPORTS = 5; - private final PostRepository postRepository; private final ReportRepository reportRepository; + private final ReportActionAlarmRepository reportActionAlarmRepository; @Override public void report(final Member reporter, final ReportRequest request) { @@ -28,7 +30,6 @@ public void report(final Member reporter, final ReportRequest request) { validatePost(reporter, reportedPost, request); saveReport(reporter, request, reportRepository); - blindPost(request, reportedPost); } private void validatePost( @@ -46,13 +47,6 @@ private void validatePost( ); } - private void blindPost(final ReportRequest request, final Post reportedPost) { - final int reportCount = reportRepository.countByReportTypeAndTargetId(request.type(), request.id()); - if (reportCount >= NUMBER_OF_POST_BLIND_BASED_REPORTS) { - reportedPost.blind(); - } - } - private void validateHiddenPost(final Post post) { if (post.isHidden()) { throw new BadRequestException(PostExceptionType.IS_HIDDEN); @@ -70,4 +64,21 @@ public String parseTarget(final Long targetId) { return targetId.toString(); } + @Override + public void reportAction(final ReportAggregateDto reportAggregateDto) { + final Post reportedPost = postRepository.findById(reportAggregateDto.targetId()) + .orElseThrow(() -> new NotFoundException(PostExceptionType.NOT_FOUND)); + + final ReportActionAlarm reportActionAlarm = ReportActionAlarm.builder() + .member(reportedPost.getWriter()) + .reportType(reportAggregateDto.reportType()) + .target(reportedPost.getId().toString()) + .reasons(reportAggregateDto.reasons()) + .isChecked(false) + .build(); + + reportActionAlarmRepository.save(reportActionAlarm); + reportedPost.blind(); + } + } diff --git a/backend/src/main/java/com/votogether/domain/report/service/strategy/ReportStrategy.java b/backend/src/main/java/com/votogether/domain/report/service/strategy/ReportStrategy.java index b8a66f1f2..bbbb0553f 100644 --- a/backend/src/main/java/com/votogether/domain/report/service/strategy/ReportStrategy.java +++ b/backend/src/main/java/com/votogether/domain/report/service/strategy/ReportStrategy.java @@ -1,6 +1,7 @@ package com.votogether.domain.report.service.strategy; import com.votogether.domain.member.entity.Member; +import com.votogether.domain.report.dto.ReportAggregateDto; import com.votogether.domain.report.dto.request.ReportRequest; import com.votogether.domain.report.entity.Report; import com.votogether.domain.report.exception.ReportExceptionType; @@ -13,6 +14,8 @@ public interface ReportStrategy { String parseTarget(Long targetId); + void reportAction(ReportAggregateDto reportAggregateDto); + default void validateDuplicatedReport( final Member reporter, final ReportRequest request, diff --git a/backend/src/test/java/com/votogether/domain/alarm/repository/ReportActionAlarmRepositoryTest.java b/backend/src/test/java/com/votogether/domain/alarm/repository/ReportActionAlarmRepositoryTest.java index 2b690df36..c26e394b9 100644 --- a/backend/src/test/java/com/votogether/domain/alarm/repository/ReportActionAlarmRepositoryTest.java +++ b/backend/src/test/java/com/votogether/domain/alarm/repository/ReportActionAlarmRepositoryTest.java @@ -59,7 +59,7 @@ void getInLatestOrder() { // then assertAll( - () -> assertThat(reportActionAlarms.size()).isEqualTo(3), + () -> assertThat(reportActionAlarms).hasSize(3), () -> assertThat(reportActionAlarms.get(0).getReportType()).isEqualTo( reportActionAlarmC.getReportType()), () -> assertThat(reportActionAlarms.get(1).getReportType()).isEqualTo( @@ -95,8 +95,8 @@ void getWithTen() { // then assertAll( - () -> assertThat(reportActionAlarmsA.size()).isEqualTo(10), - () -> assertThat(reportActionAlarmsB.size()).isEqualTo(1) + () -> assertThat(reportActionAlarmsA).hasSize(10), + () -> assertThat(reportActionAlarmsB).hasSize(1) ); } diff --git a/backend/src/test/java/com/votogether/domain/report/controller/ReportCommandControllerTest.java b/backend/src/test/java/com/votogether/domain/report/controller/ReportCommandControllerTest.java index aeb278f32..5636369b2 100644 --- a/backend/src/test/java/com/votogether/domain/report/controller/ReportCommandControllerTest.java +++ b/backend/src/test/java/com/votogether/domain/report/controller/ReportCommandControllerTest.java @@ -1,17 +1,16 @@ package com.votogether.domain.report.controller; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.BDDMockito.given; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; import static org.mockito.BDDMockito.willDoNothing; import com.votogether.domain.member.entity.Member; import com.votogether.domain.member.entity.vo.Gender; import com.votogether.domain.member.entity.vo.SocialType; +import com.votogether.domain.report.dto.request.ReportActionRequest; import com.votogether.domain.report.dto.request.ReportRequest; import com.votogether.domain.report.entity.vo.ReportType; import com.votogether.domain.report.service.ReportCommandService; -import com.votogether.global.jwt.TokenPayload; import com.votogether.test.ControllerTest; import io.restassured.http.ContentType; import io.restassured.module.mockmvc.RestAssuredMockMvc; @@ -22,6 +21,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.NullAndEmptySource; import org.junit.jupiter.params.provider.NullSource; +import org.junit.jupiter.params.provider.ValueSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; @@ -51,6 +51,8 @@ class Report { @DisplayName("게시글에 대해 정상적으로 작동한다.") void reportPost() throws Exception { // given + mockingAuthArgumentResolver(); + Member member = Member.builder() .nickname("저문") .gender(Gender.MALE) @@ -58,12 +60,6 @@ void reportPost() throws Exception { .socialId("abc123") .socialType(SocialType.KAKAO) .build(); - - TokenPayload tokenPayload = new TokenPayload(1L, 1L, 1L); - given(tokenProcessor.resolveToken(anyString())).willReturn("token"); - given(tokenProcessor.parseToken(anyString())).willReturn(tokenPayload); - given(memberService.findById(anyLong())).willReturn(member); - ReportRequest request = new ReportRequest(ReportType.POST, 1L, "불건전한 게시글"); willDoNothing().given(reportCommandService).report(member, request); @@ -83,6 +79,8 @@ void reportPost() throws Exception { @DisplayName("댓글에 대해 정상적으로 작동한다.") void reportComment() throws Exception { // given + mockingAuthArgumentResolver(); + Member member = Member.builder() .nickname("저문") .gender(Gender.MALE) @@ -90,12 +88,6 @@ void reportComment() throws Exception { .socialId("abc123") .socialType(SocialType.KAKAO) .build(); - - TokenPayload tokenPayload = new TokenPayload(1L, 1L, 1L); - given(tokenProcessor.resolveToken(anyString())).willReturn("token"); - given(tokenProcessor.parseToken(anyString())).willReturn(tokenPayload); - given(memberService.findById(anyLong())).willReturn(member); - ReportRequest request = new ReportRequest(ReportType.COMMENT, 1L, "불건전한 댓글"); willDoNothing().given(reportCommandService).report(member, request); @@ -115,6 +107,8 @@ void reportComment() throws Exception { @DisplayName("닉네임에 대해 정상적으로 작동한다.") void reportNickname() throws Exception { // given + mockingAuthArgumentResolver(); + Member member = Member.builder() .nickname("저문") .gender(Gender.MALE) @@ -122,12 +116,6 @@ void reportNickname() throws Exception { .socialId("abc123") .socialType(SocialType.KAKAO) .build(); - - TokenPayload tokenPayload = new TokenPayload(1L, 1L, 1L); - given(tokenProcessor.resolveToken(anyString())).willReturn("token"); - given(tokenProcessor.parseToken(anyString())).willReturn(tokenPayload); - given(memberService.findById(anyLong())).willReturn(member); - ReportRequest request = new ReportRequest(ReportType.NICKNAME, 1L, "불건전한 닉네임"); willDoNothing().given(reportCommandService).report(member, request); @@ -150,6 +138,8 @@ void reportNickname() throws Exception { @DisplayName("신고 대상 Id가 빈 값인 경우 400을 반환한다.") void report(Long id) throws Exception { // given + mockingAuthArgumentResolver(); + Member member = Member.builder() .nickname("저문") .gender(Gender.MALE) @@ -157,12 +147,6 @@ void report(Long id) throws Exception { .socialId("abc123") .socialType(SocialType.KAKAO) .build(); - - TokenPayload tokenPayload = new TokenPayload(1L, 1L, 1L); - given(tokenProcessor.resolveToken(anyString())).willReturn("token"); - given(tokenProcessor.parseToken(anyString())).willReturn(tokenPayload); - given(memberService.findById(anyLong())).willReturn(member); - ReportRequest request = new ReportRequest(ReportType.COMMENT, id, "불건전한 게시글"); willDoNothing().given(reportCommandService).report(member, request); @@ -183,6 +167,8 @@ void report(Long id) throws Exception { @DisplayName("신고 이유가 빈 값일 경우 400을 반환한다.") void reportBadRequest(String reason) throws Exception { // given + mockingAuthArgumentResolver(); + Member member = Member.builder() .nickname("저문") .gender(Gender.MALE) @@ -190,12 +176,6 @@ void reportBadRequest(String reason) throws Exception { .socialId("abc123") .socialType(SocialType.KAKAO) .build(); - - TokenPayload tokenPayload = new TokenPayload(1L, 1L, 1L); - given(tokenProcessor.resolveToken(anyString())).willReturn("token"); - given(tokenProcessor.parseToken(anyString())).willReturn(tokenPayload); - given(memberService.findById(anyLong())).willReturn(member); - ReportRequest request = new ReportRequest(ReportType.POST, 1L, reason); willDoNothing().given(reportCommandService).report(member, request); @@ -211,4 +191,54 @@ void reportBadRequest(String reason) throws Exception { .status(HttpStatus.BAD_REQUEST); } + @Nested + @DisplayName("신고 조치 기능은") + class ReportAction { + + @Test + @DisplayName("정상적으로 작동한다.") + void reportAction() throws Exception { + // given + mockingAuthArgumentResolver(); + + ReportActionRequest request = new ReportActionRequest(1L, true); + willDoNothing().given(reportCommandService).reportAction(request); + + // when, then + RestAssuredMockMvc + .given().log().all() + .headers(HttpHeaders.AUTHORIZATION, "Bearer token") + .contentType(ContentType.JSON) + .body(request) + .when().post("/reports/action/admin") + .then().log().all() + .assertThat() + .status(HttpStatus.OK); + } + + @ParameterizedTest + @NullSource + @ValueSource(longs = {-1, 0}) + @DisplayName("신고 Id가 양수가 아닌 경우 400을 반환한다.") + void reportIdNotPositiveException(Long reportId) throws Exception { + // given + mockingAuthArgumentResolver(); + + ReportActionRequest request = new ReportActionRequest(reportId, true); + willDoNothing().given(reportCommandService).reportAction(request); + + // when, then + RestAssuredMockMvc + .given().log().all() + .headers(HttpHeaders.AUTHORIZATION, "Bearer token") + .contentType(ContentType.JSON) + .body(request) + .when().post("/reports/action/admin") + .then().log().all() + .assertThat() + .status(HttpStatus.BAD_REQUEST); + } + + } + } diff --git a/backend/src/test/java/com/votogether/domain/report/controller/ReportQueryControllerTest.java b/backend/src/test/java/com/votogether/domain/report/controller/ReportQueryControllerTest.java index e68480a1e..a7f9fb2fc 100644 --- a/backend/src/test/java/com/votogether/domain/report/controller/ReportQueryControllerTest.java +++ b/backend/src/test/java/com/votogether/domain/report/controller/ReportQueryControllerTest.java @@ -51,13 +51,13 @@ void getReports() throws Exception { // given mockingAuthArgumentResolver(); - final int totalPages = 3; - final int currentPageNumber = 1; - final String reason = "reason"; - final ReportType reportType = ReportType.POST; - final long targetId = 1L; + int totalPages = 3; + int currentPageNumber = 1; + String reason = "reason"; + ReportType reportType = ReportType.POST; + long targetId = 1L; - final ReportAggregateDto reportAggregateDto = new ReportAggregateDto( + ReportAggregateDto reportAggregateDto = new ReportAggregateDto( 1L, reportType, targetId, @@ -65,7 +65,7 @@ void getReports() throws Exception { LocalDateTime.now() ); - final ReportPageResponse reportPageResponse = + ReportPageResponse reportPageResponse = ReportPageResponse.of( totalPages, currentPageNumber, @@ -76,7 +76,7 @@ void getReports() throws Exception { given(reportQueryService.getReports(page)).willReturn(reportPageResponse); // when - final ReportPageResponse reportPageResponses = RestAssuredMockMvc + ReportPageResponse reportPageResponses = RestAssuredMockMvc .given().log().all() .contentType(ContentType.JSON) .headers(HttpHeaders.AUTHORIZATION, "Bearer token") @@ -89,8 +89,8 @@ void getReports() throws Exception { }); // then - final List reports = reportPageResponses.reports(); - final ReportResponse reportResponse = reports.get(0); + List reports = reportPageResponses.reports(); + ReportResponse reportResponse = reports.get(0); assertSoftly(softly -> { softly.assertThat(reportPageResponses.totalPageNumber()).isEqualTo(totalPages); softly.assertThat(reportPageResponses.currentPageNumber()).isEqualTo(currentPageNumber); diff --git a/backend/src/test/java/com/votogether/domain/report/repository/ReportCustomRepositoryImplTest.java b/backend/src/test/java/com/votogether/domain/report/repository/ReportCustomRepositoryImplTest.java index 28076e3f5..5cdf3b140 100644 --- a/backend/src/test/java/com/votogether/domain/report/repository/ReportCustomRepositoryImplTest.java +++ b/backend/src/test/java/com/votogether/domain/report/repository/ReportCustomRepositoryImplTest.java @@ -7,6 +7,8 @@ import com.votogether.domain.report.dto.ReportAggregateDto; import com.votogether.domain.report.entity.Report; import com.votogether.domain.report.entity.vo.ReportType; +import com.votogether.domain.report.exception.ReportExceptionType; +import com.votogether.global.exception.NotFoundException; import com.votogether.test.RepositoryTest; import com.votogether.test.fixtures.MemberFixtures; import java.time.LocalDateTime; @@ -28,25 +30,25 @@ class ReportCustomRepositoryImplTest extends RepositoryTest { @Test @DisplayName("신고 조치 예정 목록을 최신순으로 조회한다") - void getReports() { + void getReportAggregateDtos() { // given - final Member member = memberRepository.save(MemberFixtures.MALE_30.get()); + Member member = memberRepository.save(MemberFixtures.MALE_30.get()); - final Report savedReportA = reportTestPersister.builder() + Report savedReportA = reportTestPersister.builder() .member(member) .reportType(ReportType.POST) .reason("reasonA") .targetId(1L) .save(); - final Report savedReportB = reportTestPersister.builder() + Report savedReportB = reportTestPersister.builder() .member(member) .reportType(ReportType.COMMENT) .reason("reasonB") .targetId(1L) .save(); - final ReportAggregateDto reportAggregateDtoA = new ReportAggregateDto( + ReportAggregateDto reportAggregateDtoA = new ReportAggregateDto( savedReportA.getId(), savedReportA.getReportType(), savedReportA.getTargetId(), @@ -54,7 +56,7 @@ void getReports() { savedReportA.getCreatedAt() ); - final ReportAggregateDto reportAggregateDtoB = new ReportAggregateDto( + ReportAggregateDto reportAggregateDtoB = new ReportAggregateDto( savedReportB.getId(), savedReportB.getReportType(), savedReportB.getTargetId(), @@ -62,11 +64,11 @@ void getReports() { savedReportB.getCreatedAt() ); - final PageRequest pageRequest = PageRequest.of(0, 20); + PageRequest pageRequest = PageRequest.of(0, 20); // when - final List reports = reportCustomRepository - .findReportsGroupedByReportTypeAndTargetId(pageRequest); + List reports = reportCustomRepository + .findReportAggregateDtosByReportTypeAndTargetId(pageRequest); // then assertSoftly(softly -> { @@ -76,9 +78,9 @@ void getReports() { } private void equalTo( - final SoftAssertions softly, - final ReportAggregateDto actualReport, - final ReportAggregateDto expectReport + SoftAssertions softly, + ReportAggregateDto actualReport, + ReportAggregateDto expectReport ) { softly.assertThat(actualReport).usingRecursiveComparison() .withEqualsForType( @@ -89,4 +91,46 @@ private void equalTo( .isEqualTo(expectReport); } + @Test + @DisplayName("신고 조치 예정 정보를 조회한다") + void getReportAggregateDto() { + // given + Member memberA = memberRepository.save(MemberFixtures.MALE_30.get()); + Member memberB = memberRepository.save(MemberFixtures.MALE_20.get()); + + final ReportType reportType = ReportType.POST; + final long targetId = 1L; + + final String reasonA = "reasonA"; + reportTestPersister.builder() + .member(memberA) + .reportType(reportType) + .reason(reasonA) + .targetId(targetId) + .save(); + + final String reasonB = "reasonB"; + Report savedReportB = reportTestPersister.builder() + .member(memberB) + .reportType(reportType) + .reason(reasonB) + .targetId(targetId) + .save(); + + // when + ReportAggregateDto reportAggregateDto = reportCustomRepository + .findReportAggregateDtoByReportTypeAndTargetId(reportType, targetId) + .orElseThrow(() -> new NotFoundException(ReportExceptionType.NOT_FOUND)); + + // then + assertSoftly(softly -> { + softly.assertThat(reportAggregateDto.reportMaxId()).isEqualTo(savedReportB.getId()); + softly.assertThat(reportAggregateDto.reportType()).isEqualTo(reportType); + softly.assertThat(reportAggregateDto.targetId()).isEqualTo(targetId); + softly.assertThat(reportAggregateDto.reasons()).contains(reasonA, reasonB); + softly.assertThat(reportAggregateDto.createdAt().truncatedTo(ChronoUnit.SECONDS)) + .isEqualTo(savedReportB.getCreatedAt().truncatedTo(ChronoUnit.SECONDS)); + }); + } + } diff --git a/backend/src/test/java/com/votogether/domain/report/service/ReportCommandServiceTest.java b/backend/src/test/java/com/votogether/domain/report/service/ReportCommandServiceTest.java index 851d33bbd..5a1be68a2 100644 --- a/backend/src/test/java/com/votogether/domain/report/service/ReportCommandServiceTest.java +++ b/backend/src/test/java/com/votogether/domain/report/service/ReportCommandServiceTest.java @@ -1,28 +1,38 @@ package com.votogether.domain.report.service; -import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.jupiter.api.Assertions.assertAll; +import static org.assertj.core.api.SoftAssertions.assertSoftly; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import com.votogether.domain.alarm.entity.ReportActionAlarm; +import com.votogether.domain.alarm.repository.ReportActionAlarmRepository; import com.votogether.domain.member.entity.Member; -import com.votogether.domain.post.dto.response.post.PostResponse; +import com.votogether.domain.member.service.MemberService; import com.votogether.domain.post.entity.Post; import com.votogether.domain.post.entity.comment.Comment; -import com.votogether.domain.post.entity.vo.PostClosingType; -import com.votogether.domain.post.entity.vo.PostSortType; +import com.votogether.domain.post.repository.CommentRepository; +import com.votogether.domain.post.repository.PostRepository; import com.votogether.domain.post.service.PostCommentService; import com.votogether.domain.post.service.PostGuestService; +import com.votogether.domain.report.dto.request.ReportActionRequest; import com.votogether.domain.report.dto.request.ReportRequest; +import com.votogether.domain.report.entity.Report; import com.votogether.domain.report.entity.vo.ReportType; +import com.votogether.domain.report.repository.ReportRepository; import com.votogether.global.exception.BadRequestException; import com.votogether.global.exception.NotFoundException; import com.votogether.test.ServiceTest; +import com.votogether.test.fixtures.MemberFixtures; +import java.time.LocalDateTime; import java.util.List; +import java.util.Optional; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.transaction.TestTransaction; class ReportCommandServiceTest extends ServiceTest { @@ -35,6 +45,21 @@ class ReportCommandServiceTest extends ServiceTest { @Autowired PostCommentService postCommentService; + @Autowired + MemberService memberService; + + @Autowired + ReportActionAlarmRepository reportActionAlarmRepository; + + @Autowired + ReportRepository reportRepository; + + @Autowired + PostRepository postRepository; + + @Autowired + CommentRepository commentRepository; + @Nested @DisplayName("게시글 신고기능은") class ReportPost { @@ -110,38 +135,6 @@ void reportDuplicated() { .hasMessage("하나의 글에 대해서 중복하여 신고할 수 없습니다."); } - @Test - @DisplayName("투표글 신고가 5회가 되면 블라인드 처리가 된다.") - void reportAndBlind() { - // given - Member reporter1 = memberTestPersister.builder().save(); - Member reporter2 = memberTestPersister.builder().save(); - Member reporter3 = memberTestPersister.builder().save(); - Member reporter4 = memberTestPersister.builder().save(); - Member reporter5 = memberTestPersister.builder().save(); - Post post = postTestPersister.postBuilder().save(); - ReportRequest request = new ReportRequest(ReportType.POST, post.getId(), "불건전한 게시글"); - - // when - reportCommandService.report(reporter1, request); - reportCommandService.report(reporter2, request); - reportCommandService.report(reporter3, request); - reportCommandService.report(reporter4, request); - reportCommandService.report(reporter5, request); - - // then - final List responses = postGuestService.getPosts( - 0, - PostClosingType.ALL, - PostSortType.HOT, - null - ); - assertAll( - () -> assertThat(post.isHidden()).isTrue(), - () -> assertThat(responses).isEmpty() - ); - } - } @Nested @@ -224,33 +217,6 @@ void reportDuplicated() { .hasMessage("하나의 댓글에 대해서 중복하여 신고할 수 없습니다."); } - @Test - @DisplayName("댓글 신고가 5회가 되면 블라인드 처리가 된다.") - void reportAndBlind() { - // given - Member reporter1 = memberTestPersister.builder().save(); - Member reporter2 = memberTestPersister.builder().save(); - Member reporter3 = memberTestPersister.builder().save(); - Member reporter4 = memberTestPersister.builder().save(); - Member reporter5 = memberTestPersister.builder().save(); - Post post = postTestPersister.postBuilder().save(); - Comment comment = commentTestPersister.builder().post(post).save(); - ReportRequest request = new ReportRequest(ReportType.COMMENT, comment.getId(), "불건전한 댓글"); - - // when - reportCommandService.report(reporter1, request); - reportCommandService.report(reporter2, request); - reportCommandService.report(reporter3, request); - reportCommandService.report(reporter4, request); - reportCommandService.report(reporter5, request); - - // then - assertAll( - () -> assertThat(comment.isHidden()).isTrue(), - () -> assertThat(postCommentService.getComments(post.getId())).isEmpty() - ); - } - } @Nested @@ -298,25 +264,248 @@ void reportDuplicated() { .isInstanceOf(BadRequestException.class) .hasMessage("하나의 닉네임에 대해서 중복하여 신고할 수 없습니다."); } + } + + @Nested + @DisplayName("신고 조치 기능은") + class ReportAction { + + @Test + @DisplayName("게시글에 대해 신고 조치를 한다.") + void postReportAction() { + // given + Member reporter = memberService.register(MemberFixtures.MALE_20.get()); + Member writer = memberService.register(MemberFixtures.MALE_30.get()); + + Post post = postTestPersister.postBuilder() + .writer(writer) + .title("title") + .content("content") + .deadline(LocalDateTime.now()) + .save(); + + Report savedReport = reportTestPersister.builder() + .member(reporter) + .reportType(ReportType.POST) + .reason("reasonA") + .targetId(post.getId()) + .save(); + + // when + ReportActionRequest request = new ReportActionRequest(savedReport.getId(), true); + reportCommandService.reportAction(request); + + // then + Post savedPost = postRepository.findById(post.getId()).get(); + Optional reportById = reportRepository.findById(savedReport.getId()); + ReportActionAlarm reportActionAlarm = reportActionAlarmRepository.findAll().get(0); + + assertSoftly(softly -> { + softly.assertThat(reportById).isEmpty(); + softly.assertThat(reportActionAlarm.getMember().getId()).isEqualTo(writer.getId()); + softly.assertThat(reportActionAlarm.getReportType()).isEqualTo(savedReport.getReportType()); + softly.assertThat(reportActionAlarm.getTarget()).isEqualTo(savedPost.getId().toString()); + softly.assertThat(reportActionAlarm.getReasons()).isEqualTo(savedReport.getReason()); + softly.assertThat(reportActionAlarm.isChecked()).isFalse(); + softly.assertThat(savedPost.isHidden()).isTrue(); + }); + } @Test - @DisplayName("닉네임 신고가 3회가 되면 닉네임이 자동변경처리가 된다.") - void reportAndBlind() { + @DisplayName("게시글에 대해 신고 조치를 하지 않는다.") + void postNotReportAction() { // given - Member reporter1 = memberTestPersister.builder().save(); - Member reporter2 = memberTestPersister.builder().save(); - Member reporter3 = memberTestPersister.builder().save(); - Member reported = memberTestPersister.builder().save(); - ReportRequest request = new ReportRequest(ReportType.NICKNAME, reported.getId(), "불건전한 닉네임"); + Member reporter = memberService.register(MemberFixtures.MALE_20.get()); + Member writer = memberService.register(MemberFixtures.MALE_30.get()); + + Post post = postTestPersister.postBuilder() + .writer(writer) + .title("title") + .content("content") + .deadline(LocalDateTime.now()) + .save(); + + Report savedReport = reportTestPersister.builder() + .member(reporter) + .reportType(ReportType.POST) + .reason("reasonA") + .targetId(post.getId()) + .save(); + + // when + ReportActionRequest request = new ReportActionRequest(savedReport.getId(), false); + reportCommandService.reportAction(request); + + + // then + Post savedPost = postRepository.findById(post.getId()).get(); + Optional reportById = reportRepository.findById(savedReport.getId()); + List reportActionAlarms = reportActionAlarmRepository.findAll(); + + assertSoftly(softly -> { + softly.assertThat(reportById).isEmpty(); + softly.assertThat(reportActionAlarms).isEmpty(); + softly.assertThat(savedPost.isHidden()).isFalse(); + }); + } + + @Test + @DisplayName("댓글에 대해 신고 조치를 한다.") + void commentReportAction() { + // given + Member writer = memberService.register(MemberFixtures.MALE_30.get()); + Member reporter = memberService.register(MemberFixtures.MALE_20.get()); + + Comment comment = commentTestPersister.builder() + .writer(writer) + .content("commnetA") + .save(); + + Report savedReport = reportTestPersister.builder() + .member(reporter) + .reportType(ReportType.COMMENT) + .reason("reasonA") + .targetId(comment.getId()) + .save(); // when - reportCommandService.report(reporter1, request); - reportCommandService.report(reporter2, request); - reportCommandService.report(reporter3, request); + ReportActionRequest request = new ReportActionRequest(savedReport.getId(), true); + reportCommandService.reportAction(request); // then - assertThat(reported.getNickname()).contains("Pause1"); + Comment savedComment = commentRepository.findById(comment.getId()).get(); + Optional reportById = reportRepository.findById(savedReport.getId()); + ReportActionAlarm reportActionAlarm = reportActionAlarmRepository.findAll().get(0); + + assertSoftly(softly -> { + softly.assertThat(reportById).isEmpty(); + softly.assertThat(reportActionAlarm.getMember().getId()).isEqualTo(writer.getId()); + softly.assertThat(reportActionAlarm.getReportType()).isEqualTo(savedReport.getReportType()); + softly.assertThat(reportActionAlarm.getTarget()).isEqualTo(savedComment.getContent()); + softly.assertThat(reportActionAlarm.getReasons()).isEqualTo(savedReport.getReason()); + softly.assertThat(reportActionAlarm.isChecked()).isFalse(); + softly.assertThat(savedComment.isHidden()).isTrue(); + }); + } + + @Test + @DisplayName("댓글에 대해 신고 조치를 하지 않는다.") + void commentNotReportAction() { + // given + Member writer = memberService.register(MemberFixtures.MALE_30.get()); + Member reporter = memberService.register(MemberFixtures.MALE_20.get()); + + Comment comment = commentTestPersister.builder() + .writer(writer) + .content("commnetA") + .save(); + + Report savedReport = reportTestPersister.builder() + .member(reporter) + .reportType(ReportType.COMMENT) + .reason("reasonA") + .targetId(comment.getId()) + .save(); + + // when + ReportActionRequest request = new ReportActionRequest(savedReport.getId(), false); + reportCommandService.reportAction(request); + + // then + Comment savedComment = commentRepository.findById(comment.getId()).get(); + Optional reportById = reportRepository.findById(savedReport.getId()); + List reportActionAlarms = reportActionAlarmRepository.findAll(); + + assertSoftly(softly -> { + softly.assertThat(reportById).isEmpty(); + softly.assertThat(reportActionAlarms).isEmpty(); + softly.assertThat(savedComment.isHidden()).isFalse(); + }); + } + + @Test + @DisplayName("닉네임에 대해 신고 조치를 한다.") + void nicknameReportAction() { + // given + Member reporter = memberService.register(MemberFixtures.MALE_20.get()); + Member member = memberService.register(MemberFixtures.MALE_30.get()); + + Report savedReport = reportTestPersister.builder() + .member(reporter) + .reportType(ReportType.NICKNAME) + .reason("reasonA") + .targetId(member.getId()) + .save(); + + // when + ReportActionRequest request = new ReportActionRequest(savedReport.getId(), true); + reportCommandService.reportAction(request); + + // then + Member savedMember = memberService.findById(member.getId()); + Optional reportById = reportRepository.findById(savedReport.getId()); + ReportActionAlarm reportActionAlarm = reportActionAlarmRepository.findAll().get(0); + + assertSoftly(softly -> { + softly.assertThat(reportById).isEmpty(); + softly.assertThat(reportActionAlarm.getMember().getId()).isEqualTo(member.getId()); + softly.assertThat(reportActionAlarm.getReportType()).isEqualTo(savedReport.getReportType()); + softly.assertThat(reportActionAlarm.getTarget()).isNotEqualTo(savedMember.getNickname()); + softly.assertThat(reportActionAlarm.getReasons()).isEqualTo(savedReport.getReason()); + softly.assertThat(reportActionAlarm.isChecked()).isFalse(); + }); + } + + @Test + @DisplayName("닉네임에 대해 신고 조치를 하지 않는다.") + void nicknameNotReportAction() { + // given + Member reporter = memberService.register(MemberFixtures.MALE_20.get()); + Member member = memberService.register(MemberFixtures.MALE_30.get()); + + Report savedReport = reportTestPersister.builder() + .member(reporter) + .reportType(ReportType.NICKNAME) + .reason("reasonA") + .targetId(member.getId()) + .save(); + + // when + ReportActionRequest request = new ReportActionRequest(savedReport.getId(), false); + reportCommandService.reportAction(request); + + // then + Member savedMember = memberService.findById(member.getId()); + Optional reportById = reportRepository.findById(savedReport.getId()); + List reportActionAlarms = reportActionAlarmRepository.findAll(); + + assertSoftly(softly -> { + softly.assertThat(reportById).isEmpty(); + softly.assertThat(reportActionAlarms).isEmpty(); + softly.assertThat(member.getNickname()).isEqualTo(savedMember.getNickname()); + }); + } + + @Test + @DisplayName("신고가 존재하지 않으면 예외 발생.") + void reportNotExistException() { + // given + Member reporter = memberService.register(MemberFixtures.MALE_20.get()); + Member member = memberService.register(MemberFixtures.MALE_30.get()); + + Report savedReport = reportTestPersister.builder() + .member(reporter) + .reportType(ReportType.NICKNAME) + .reason("reasonA") + .targetId(member.getId()) + .save(); + + // when, then + ReportActionRequest request = new ReportActionRequest(savedReport.getId() + 1L, true); + assertThatThrownBy(() -> reportCommandService.reportAction(request)) + .isInstanceOf(NotFoundException.class); } + } } diff --git a/backend/src/test/java/com/votogether/domain/report/service/ReportQueryServiceTest.java b/backend/src/test/java/com/votogether/domain/report/service/ReportQueryServiceTest.java index 577d157ca..b6d0a2a17 100644 --- a/backend/src/test/java/com/votogether/domain/report/service/ReportQueryServiceTest.java +++ b/backend/src/test/java/com/votogether/domain/report/service/ReportQueryServiceTest.java @@ -28,20 +28,20 @@ class ReportQueryServiceTest extends ServiceTest { @DisplayName("신고 조치 예정 목록을 최신순으로 조회한다") void getReports() { // given - final Member member = memberService.register(MemberFixtures.MALE_30.get()); + Member member = memberService.register(MemberFixtures.MALE_30.get()); - final Comment comment = commentTestPersister.builder() + Comment comment = commentTestPersister.builder() .content("commnetA") .save(); - final Report savedReportA = reportTestPersister.builder() + Report savedReportA = reportTestPersister.builder() .member(member) .reportType(ReportType.POST) .reason("reasonA") .targetId(1L) .save(); - final Report savedReportB = reportTestPersister.builder() + Report savedReportB = reportTestPersister.builder() .member(member) .reportType(ReportType.COMMENT) .reason("reasonB") @@ -49,10 +49,10 @@ void getReports() { .save(); // when - final ReportPageResponse reportPageResponse = reportQueryService.getReports(0); + ReportPageResponse reportPageResponse = reportQueryService.getReports(0); // then - final List reportResponses = reportPageResponse.reports(); + List reportResponses = reportPageResponse.reports(); assertSoftly(softly -> { softly.assertThat(reportPageResponse.totalPageNumber()).isOne(); softly.assertThat(reportPageResponse.currentPageNumber()).isZero(); diff --git a/backend/src/test/java/com/votogether/domain/report/service/strategy/ReportCommentStrategyTest.java b/backend/src/test/java/com/votogether/domain/report/service/strategy/ReportCommentStrategyTest.java index dfe1a0e39..fd7ab11b8 100644 --- a/backend/src/test/java/com/votogether/domain/report/service/strategy/ReportCommentStrategyTest.java +++ b/backend/src/test/java/com/votogether/domain/report/service/strategy/ReportCommentStrategyTest.java @@ -2,18 +2,25 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.jupiter.api.Assertions.assertAll; +import static org.assertj.core.api.SoftAssertions.assertSoftly; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import com.votogether.domain.alarm.entity.ReportActionAlarm; +import com.votogether.domain.alarm.repository.ReportActionAlarmRepository; import com.votogether.domain.member.entity.Member; +import com.votogether.domain.member.service.MemberService; import com.votogether.domain.post.entity.Post; import com.votogether.domain.post.entity.comment.Comment; import com.votogether.domain.post.service.PostCommentService; +import com.votogether.domain.report.dto.ReportAggregateDto; import com.votogether.domain.report.dto.request.ReportRequest; +import com.votogether.domain.report.entity.Report; import com.votogether.domain.report.entity.vo.ReportType; +import com.votogether.domain.report.repository.ReportRepository; import com.votogether.global.exception.BadRequestException; import com.votogether.global.exception.NotFoundException; import com.votogether.test.ServiceTest; +import com.votogether.test.fixtures.MemberFixtures; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -24,9 +31,18 @@ class ReportCommentStrategyTest extends ServiceTest { @Autowired ReportCommentStrategy reportCommentStrategy; + @Autowired + ReportRepository reportRepository; + + @Autowired + ReportActionAlarmRepository reportActionAlarmRepository; + @Autowired PostCommentService postCommentService; + @Autowired + MemberService memberService; + @Test @DisplayName("정상적으로 동작한다.") void reportComment() { @@ -103,46 +119,94 @@ void reportDuplicated() { } @Test - @DisplayName("댓글 신고가 5회가 되면 블라인드 처리가 된다.") - void reportAndBlind() { + @DisplayName("targetId를 통해 comment의 내용을 가져온다") + void parseTarget() { // given - Member reporter1 = memberTestPersister.builder().save(); - Member reporter2 = memberTestPersister.builder().save(); - Member reporter3 = memberTestPersister.builder().save(); - Member reporter4 = memberTestPersister.builder().save(); - Member reporter5 = memberTestPersister.builder().save(); - Post post = postTestPersister.postBuilder().save(); - Comment comment = commentTestPersister.builder().post(post).save(); - ReportRequest request = new ReportRequest(ReportType.COMMENT, comment.getId(), "불건전한 댓글"); + String savedCommentContent = "commentA"; + Comment comment = commentTestPersister.builder() + .content(savedCommentContent) + .save(); // when - reportCommentStrategy.report(reporter1, request); - reportCommentStrategy.report(reporter2, request); - reportCommentStrategy.report(reporter3, request); - reportCommentStrategy.report(reporter4, request); - reportCommentStrategy.report(reporter5, request); + String content = reportCommentStrategy.parseTarget(comment.getId()); // then - assertAll( - () -> assertThat(comment.isHidden()).isTrue(), - () -> assertThat(postCommentService.getComments(post.getId())).isEmpty() - ); + assertThat(content).isEqualTo(savedCommentContent); } @Test - @DisplayName("targetId를 통해 comment의 내용을 가져온다") - void parseTarget() { + @DisplayName("댓글에 대한 신고 조치를 한다.") + void commentReportAction() { // given - final String savedCommentContent = "commentA"; - final Comment comment = commentTestPersister.builder() - .content(savedCommentContent) + Member writer = memberService.register(MemberFixtures.MALE_30.get()); + Member reporter = memberService.register(MemberFixtures.MALE_20.get()); + + Comment comment = commentTestPersister.builder() + .writer(writer) + .content("commnetA") + .save(); + + Report savedReport = reportTestPersister.builder() + .member(reporter) + .reportType(ReportType.COMMENT) + .reason("reasonA") + .targetId(comment.getId()) .save(); + ReportAggregateDto reportAggregateDto = new ReportAggregateDto( + savedReport.getId(), + savedReport.getReportType(), + comment.getId(), + savedReport.getReason(), + savedReport.getCreatedAt() + ); + // when - final String content = reportCommentStrategy.parseTarget(comment.getId()); + reportCommentStrategy.reportAction(reportAggregateDto); // then - assertThat(content).isEqualTo(savedCommentContent); + ReportActionAlarm reportActionAlarm = reportActionAlarmRepository.findAll().get(0); + + assertSoftly(softly -> { + softly.assertThat(reportActionAlarm.getMember().getId()).isEqualTo(writer.getId()); + softly.assertThat(reportActionAlarm.getReportType()).isEqualTo(savedReport.getReportType()); + softly.assertThat(reportActionAlarm.getTarget()).isEqualTo(comment.getContent()); + softly.assertThat(reportActionAlarm.getReasons()).isEqualTo(savedReport.getReason()); + softly.assertThat(reportActionAlarm.isChecked()).isFalse(); + softly.assertThat(comment.isHidden()).isTrue(); + }); + } + + @Test + @DisplayName("댓글이 존재하지 않는 경우 예외 발생") + void commentNotExistException() { + // given + Member writer = memberService.register(MemberFixtures.MALE_30.get()); + Member reporter = memberService.register(MemberFixtures.MALE_20.get()); + + Comment comment = commentTestPersister.builder() + .writer(writer) + .content("commnetA") + .save(); + + Report savedReport = reportTestPersister.builder() + .member(reporter) + .reportType(ReportType.COMMENT) + .reason("reasonA") + .targetId(comment.getId()) + .save(); + + ReportAggregateDto reportAggregateDto = new ReportAggregateDto( + savedReport.getId(), + savedReport.getReportType(), + comment.getId() + 1L, + savedReport.getReason(), + savedReport.getCreatedAt() + ); + + // when, then + assertThatThrownBy(() -> reportCommentStrategy.reportAction(reportAggregateDto)) + .isInstanceOf(NotFoundException.class); } } diff --git a/backend/src/test/java/com/votogether/domain/report/service/strategy/ReportNicknameStrategyTest.java b/backend/src/test/java/com/votogether/domain/report/service/strategy/ReportNicknameStrategyTest.java index 80daedfef..b3879b49b 100644 --- a/backend/src/test/java/com/votogether/domain/report/service/strategy/ReportNicknameStrategyTest.java +++ b/backend/src/test/java/com/votogether/domain/report/service/strategy/ReportNicknameStrategyTest.java @@ -2,15 +2,21 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.jupiter.api.Assertions.assertAll; +import static org.assertj.core.api.SoftAssertions.assertSoftly; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import com.votogether.domain.alarm.entity.ReportActionAlarm; +import com.votogether.domain.alarm.repository.ReportActionAlarmRepository; import com.votogether.domain.member.entity.Member; import com.votogether.domain.member.repository.MemberRepository; +import com.votogether.domain.member.service.MemberService; +import com.votogether.domain.report.dto.ReportAggregateDto; import com.votogether.domain.report.dto.request.ReportRequest; +import com.votogether.domain.report.entity.Report; import com.votogether.domain.report.entity.vo.ReportType; import com.votogether.domain.report.repository.ReportRepository; import com.votogether.global.exception.BadRequestException; +import com.votogether.global.exception.NotFoundException; import com.votogether.test.ServiceTest; import com.votogether.test.fixtures.MemberFixtures; import org.junit.jupiter.api.DisplayName; @@ -23,6 +29,12 @@ class ReportNicknameStrategyTest extends ServiceTest { @Autowired ReportNicknameStrategy reportNicknameStrategy; + @Autowired + MemberService memberService; + + @Autowired + ReportActionAlarmRepository reportActionAlarmRepository; + @Autowired ReportRepository reportRepository; @@ -75,39 +87,81 @@ void reportDuplicated() { } @Test - @DisplayName("닉네임 신고가 3회가 되면 닉네임이 자동변경처리가 된다.") - void reportAndBlind() { + @DisplayName("targetId를 통해 해당 멤버의 Nickname을 가져온다") + void parseTarget() { // given - Member reporter1 = memberRepository.save(MemberFixtures.FEMALE_20.get()); - Member reporter2 = memberRepository.save(MemberFixtures.FEMALE_30.get()); - Member reporter3 = memberRepository.save(MemberFixtures.FEMALE_40.get()); - Member reported = memberRepository.save(MemberFixtures.FEMALE_10.get()); - - ReportRequest request = new ReportRequest(ReportType.NICKNAME, reported.getId(), "불건전한 닉네임"); + Member member = memberRepository.save(MemberFixtures.MALE_30.get()); // when - reportNicknameStrategy.report(reporter1, request); - reportNicknameStrategy.report(reporter2, request); - reportNicknameStrategy.report(reporter3, request); + String nickName = reportNicknameStrategy.parseTarget(member.getId()); // then - assertAll( - () -> assertThat(reported.getNickname()).contains("Pause1"), - () -> assertThat(reportRepository.findAll()).isEmpty() - ); + assertThat(nickName).isEqualTo(member.getNickname()); } @Test - @DisplayName("targetId를 통해 해당 멤버의 Nickname을 가져온다") - void parseTarget() { + @DisplayName("닉네임에 대한 신고 조치를 한다.") + void nicknameReportAction() { // given - final Member member = memberRepository.save(MemberFixtures.MALE_30.get()); + Member reporter = memberService.register(MemberFixtures.MALE_20.get()); + Member member = memberService.register(MemberFixtures.MALE_30.get()); + String nickname = member.getNickname(); + + Report savedReport = reportTestPersister.builder() + .member(reporter) + .reportType(ReportType.NICKNAME) + .reason("reasonA") + .targetId(member.getId()) + .save(); + + ReportAggregateDto reportAggregateDto = new ReportAggregateDto( + savedReport.getId(), + savedReport.getReportType(), + member.getId(), + savedReport.getReason(), + savedReport.getCreatedAt() + ); // when - final String nickName = reportNicknameStrategy.parseTarget(member.getId()); + reportNicknameStrategy.reportAction(reportAggregateDto); // then - assertThat(nickName).isEqualTo(member.getNickname()); + ReportActionAlarm reportActionAlarm = reportActionAlarmRepository.findAll().get(0); + + assertSoftly(softly -> { + softly.assertThat(reportActionAlarm.getMember().getId()).isEqualTo(member.getId()); + softly.assertThat(reportActionAlarm.getReportType()).isEqualTo(savedReport.getReportType()); + softly.assertThat(reportActionAlarm.getTarget()).isNotEqualTo(member.getNickname()); + softly.assertThat(reportActionAlarm.getReasons()).isEqualTo(savedReport.getReason()); + softly.assertThat(reportActionAlarm.isChecked()).isFalse(); + }); + } + + @Test + @DisplayName("회원이 존재하지 않는 경우 예외 발생") + void nicknameNotExistException() { + // given + Member reporter = memberService.register(MemberFixtures.MALE_20.get()); + Member member = memberService.register(MemberFixtures.MALE_30.get()); + + Report savedReport = reportTestPersister.builder() + .member(reporter) + .reportType(ReportType.NICKNAME) + .reason("reasonA") + .targetId(member.getId()) + .save(); + + ReportAggregateDto reportAggregateDto = new ReportAggregateDto( + savedReport.getId(), + savedReport.getReportType(), + member.getId() + 1L, + savedReport.getReason(), + savedReport.getCreatedAt() + ); + + // when, then + assertThatThrownBy(() -> reportNicknameStrategy.reportAction(reportAggregateDto)) + .isInstanceOf(NotFoundException.class); } } diff --git a/backend/src/test/java/com/votogether/domain/report/service/strategy/ReportPostStrategyTest.java b/backend/src/test/java/com/votogether/domain/report/service/strategy/ReportPostStrategyTest.java index b3278a7dd..9bf00eaa2 100644 --- a/backend/src/test/java/com/votogether/domain/report/service/strategy/ReportPostStrategyTest.java +++ b/backend/src/test/java/com/votogether/domain/report/service/strategy/ReportPostStrategyTest.java @@ -2,21 +2,25 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.jupiter.api.Assertions.assertAll; +import static org.assertj.core.api.SoftAssertions.assertSoftly; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import com.votogether.domain.alarm.entity.ReportActionAlarm; +import com.votogether.domain.alarm.repository.ReportActionAlarmRepository; import com.votogether.domain.member.entity.Member; -import com.votogether.domain.post.dto.response.post.PostResponse; +import com.votogether.domain.member.service.MemberService; import com.votogether.domain.post.entity.Post; -import com.votogether.domain.post.entity.vo.PostClosingType; -import com.votogether.domain.post.entity.vo.PostSortType; import com.votogether.domain.post.service.PostGuestService; +import com.votogether.domain.report.dto.ReportAggregateDto; import com.votogether.domain.report.dto.request.ReportRequest; +import com.votogether.domain.report.entity.Report; import com.votogether.domain.report.entity.vo.ReportType; +import com.votogether.domain.report.repository.ReportRepository; import com.votogether.global.exception.BadRequestException; import com.votogether.global.exception.NotFoundException; import com.votogether.test.ServiceTest; -import java.util.List; +import com.votogether.test.fixtures.MemberFixtures; +import java.time.LocalDateTime; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -30,6 +34,16 @@ class ReportPostStrategyTest extends ServiceTest { @Autowired PostGuestService postGuestService; + @Autowired + MemberService memberService; + + @Autowired + ReportActionAlarmRepository reportActionAlarmRepository; + + @Autowired + ReportRepository reportRepository; + + @Test @DisplayName("정상적으로 동작한다.") void reportPost() { @@ -102,48 +116,88 @@ void reportDuplicated() { } @Test - @DisplayName("투표글 신고가 5회가 되면 블라인드 처리가 된다.") - void reportAndBlind() { + @DisplayName("targetId를 문자열로 파싱한다.") + void parseTarget() { // given - Member reporter1 = memberTestPersister.builder().save(); - Member reporter2 = memberTestPersister.builder().save(); - Member reporter3 = memberTestPersister.builder().save(); - Member reporter4 = memberTestPersister.builder().save(); - Member reporter5 = memberTestPersister.builder().save(); Post post = postTestPersister.postBuilder().save(); - ReportRequest request = new ReportRequest(ReportType.POST, post.getId(), "불건전한 게시글"); // when - reportPostStrategy.report(reporter1, request); - reportPostStrategy.report(reporter2, request); - reportPostStrategy.report(reporter3, request); - reportPostStrategy.report(reporter4, request); - reportPostStrategy.report(reporter5, request); + String postId = reportPostStrategy.parseTarget(post.getId()); // then - final List responses = postGuestService.getPosts( - 0, - PostClosingType.ALL, - PostSortType.HOT, - null - ); - assertAll( - () -> assertThat(post.isHidden()).isTrue(), - () -> assertThat(responses).isEmpty() - ); + assertThat(postId).isEqualTo(post.getId().toString()); } @Test - @DisplayName("targetId를 문자열로 파싱한다.") - void parseTarget() { + @DisplayName("게시글에 대한 신고 조치를 한다.") + void postReportAction() { // given - Post post = postTestPersister.postBuilder().save(); + Member reporter = memberService.register(MemberFixtures.MALE_20.get()); + Member writer = memberService.register(MemberFixtures.MALE_30.get()); + + final Post post = postTestPersister.postBuilder() + .writer(writer) + .title("title") + .content("content") + .deadline(LocalDateTime.now()) + .save(); + + Report savedReport = reportTestPersister.builder() + .member(reporter) + .reportType(ReportType.POST) + .reason("reasonA") + .targetId(post.getId()) + .save(); + + ReportAggregateDto reportAggregateDto = new ReportAggregateDto( + savedReport.getId(), + savedReport.getReportType(), + post.getId(), + savedReport.getReason(), + savedReport.getCreatedAt() + ); // when - final String postId = reportPostStrategy.parseTarget(post.getId()); + reportPostStrategy.reportAction(reportAggregateDto); // then - assertThat(postId).isEqualTo(post.getId().toString()); + ReportActionAlarm reportActionAlarm = reportActionAlarmRepository.findAll().get(0); + + assertSoftly(softly -> { + softly.assertThat(reportActionAlarm.getMember().getId()).isEqualTo(writer.getId()); + softly.assertThat(reportActionAlarm.getReportType()).isEqualTo(savedReport.getReportType()); + softly.assertThat(reportActionAlarm.getTarget()).isEqualTo(post.getId().toString()); + softly.assertThat(reportActionAlarm.getReasons()).isEqualTo(savedReport.getReason()); + softly.assertThat(reportActionAlarm.isChecked()).isFalse(); + softly.assertThat(post.isHidden()).isTrue(); + }); + } + + @Test + @DisplayName("게시글이 존재하지 않는 경우 예외 발생") + void postNotExistException() { + // given + Member reporter = memberService.register(MemberFixtures.MALE_20.get()); + Member member = memberService.register(MemberFixtures.MALE_30.get()); + + Report savedReport = reportTestPersister.builder() + .member(reporter) + .reportType(ReportType.NICKNAME) + .reason("reasonA") + .targetId(member.getId()) + .save(); + + ReportAggregateDto reportAggregateDto = new ReportAggregateDto( + savedReport.getId(), + savedReport.getReportType(), + member.getId() + 1L, + savedReport.getReason(), + savedReport.getCreatedAt() + ); + + // when, then + assertThatThrownBy(() -> reportPostStrategy.reportAction(reportAggregateDto)) + .isInstanceOf(NotFoundException.class); } }