From 5613230b4adc822d4ef68382ac4982cfa2338da4 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 23 Jul 2025 12:51:41 +0900 Subject: [PATCH 1/8] =?UTF-8?q?feat:=20=EC=8B=A0=EA=B3=A0=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../report/domain/ReasonType.java | 14 +++++ .../solidconnection/report/domain/Report.java | 52 +++++++++++++++++++ .../report/domain/TargetType.java | 7 +++ .../db/migration/V24__create_report_table.sql | 11 ++++ 4 files changed, 84 insertions(+) create mode 100644 src/main/java/com/example/solidconnection/report/domain/ReasonType.java create mode 100644 src/main/java/com/example/solidconnection/report/domain/Report.java create mode 100644 src/main/java/com/example/solidconnection/report/domain/TargetType.java create mode 100644 src/main/resources/db/migration/V24__create_report_table.sql diff --git a/src/main/java/com/example/solidconnection/report/domain/ReasonType.java b/src/main/java/com/example/solidconnection/report/domain/ReasonType.java new file mode 100644 index 000000000..caf33277f --- /dev/null +++ b/src/main/java/com/example/solidconnection/report/domain/ReasonType.java @@ -0,0 +1,14 @@ +package com.example.solidconnection.report.domain; + +public enum ReasonType { + + ADVERTISEMENT, // 광고 + SPAM, // 낚시/도배 + PERSONAL_INFO_EXPOSURE, // 개인정보 노출 + PORNOGRAPHY, // 선정성 + COPYRIGHT_INFRINGEMENT, // 저작권 침해 + ILLEGAL_ACTIVITY, // 불법 행위 + IMPERSONATION, // 사칭/도용 + INSULT, // 욕설/비하 + ; +} diff --git a/src/main/java/com/example/solidconnection/report/domain/Report.java b/src/main/java/com/example/solidconnection/report/domain/Report.java new file mode 100644 index 000000000..a65d44e8d --- /dev/null +++ b/src/main/java/com/example/solidconnection/report/domain/Report.java @@ -0,0 +1,52 @@ +package com.example.solidconnection.report.domain; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(uniqueConstraints = { + @UniqueConstraint( + name = "uk_report_reporter_id_target_type_target_id", + columnNames = {"reporter_id", "target_type", "target_id"} + ) +}) +public class Report { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(name = "reporter_id") + private long reporterId; + + @Column(name = "target_type") + @Enumerated(value = EnumType.STRING) + private TargetType targetType; + + @Column(name = "target_id") + private long targetId; + + @Column(name = "reason_type") + @Enumerated(value = EnumType.STRING) + private ReasonType reasonType; + + public Report(long reporterId, TargetType targetType, long targetId, ReasonType reasonType) { + this.reporterId = reporterId; + this.targetType = targetType; + this.targetId = targetId; + this.reasonType = reasonType; + } +} diff --git a/src/main/java/com/example/solidconnection/report/domain/TargetType.java b/src/main/java/com/example/solidconnection/report/domain/TargetType.java new file mode 100644 index 000000000..c48f50ac0 --- /dev/null +++ b/src/main/java/com/example/solidconnection/report/domain/TargetType.java @@ -0,0 +1,7 @@ +package com.example.solidconnection.report.domain; + +public enum TargetType { + + POST, + ; +} diff --git a/src/main/resources/db/migration/V24__create_report_table.sql b/src/main/resources/db/migration/V24__create_report_table.sql new file mode 100644 index 000000000..daa92e7af --- /dev/null +++ b/src/main/resources/db/migration/V24__create_report_table.sql @@ -0,0 +1,11 @@ +CREATE TABLE report +( + id BIGINT NOT NULL AUTO_INCREMENT, + reporter_id BIGINT NOT NULL, + target_type ENUM ('POST') NOT NULL, + target_id BIGINT NOT NULL, + reason_type ENUM ('ADVERTISEMENT', 'SPAM', 'PERSONAL_INFO_EXPOSURE', 'PORNOGRAPHY', 'COPYRIGHT_INFRINGEMENT', 'ILLEGAL_ACTIVITY', 'IMPERSONATION', 'INSULT') NOT NULL, + primary key (id), + constraint fk_report_reporter_id foreign key (reporter_id) references site_user (id), + unique uk_report_reporter_id_target_type_target_id (reporter_id, target_type, target_id) +); From 8a9c1960a7982a3ec4b6d30260e9a18a96c94ef4 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 23 Jul 2025 22:50:59 +0900 Subject: [PATCH 2/8] =?UTF-8?q?feat:=20=EC=8B=A0=EA=B3=A0=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20dto=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../report/dto/ReportRequest.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/main/java/com/example/solidconnection/report/dto/ReportRequest.java diff --git a/src/main/java/com/example/solidconnection/report/dto/ReportRequest.java b/src/main/java/com/example/solidconnection/report/dto/ReportRequest.java new file mode 100644 index 000000000..ee16b2637 --- /dev/null +++ b/src/main/java/com/example/solidconnection/report/dto/ReportRequest.java @@ -0,0 +1,17 @@ +package com.example.solidconnection.report.dto; + +import com.example.solidconnection.report.domain.ReasonType; +import com.example.solidconnection.report.domain.TargetType; +import jakarta.validation.constraints.NotNull; + +public record ReportRequest( + long targetId, + + @NotNull(message = "신고 대상을 포함해주세요.") + TargetType targetType, + + @NotNull(message = "신고 사유를 선택해주세요.") + ReasonType type +) { + +} From 8f8219255274ebdc15126bf7cdc054e370e29051 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 23 Jul 2025 23:08:33 +0900 Subject: [PATCH 3/8] =?UTF-8?q?feat:=20=EC=8B=A0=EA=B3=A0=20=EB=A0=88?= =?UTF-8?q?=ED=8F=AC=EC=A7=80=ED=86=A0=EB=A6=AC=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../report/repository/ReportRepository.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/java/com/example/solidconnection/report/repository/ReportRepository.java diff --git a/src/main/java/com/example/solidconnection/report/repository/ReportRepository.java b/src/main/java/com/example/solidconnection/report/repository/ReportRepository.java new file mode 100644 index 000000000..c32d3cd5f --- /dev/null +++ b/src/main/java/com/example/solidconnection/report/repository/ReportRepository.java @@ -0,0 +1,10 @@ +package com.example.solidconnection.report.repository; + +import com.example.solidconnection.report.domain.Report; +import com.example.solidconnection.report.domain.TargetType; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ReportRepository extends JpaRepository { + + boolean existsByReporterIdAndTargetTypeAndTargetId(long reporterId, TargetType targetType, long targetId); +} From 08716d13f96ea5e8cf9bd73a0c079b0ba2e18f26 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 23 Jul 2025 23:10:23 +0900 Subject: [PATCH 4/8] =?UTF-8?q?feat:=20=EC=8B=A0=EA=B3=A0=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/exception/ErrorCode.java | 6 ++- .../report/service/ReportService.java | 49 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/example/solidconnection/report/service/ReportService.java diff --git a/src/main/java/com/example/solidconnection/common/exception/ErrorCode.java b/src/main/java/com/example/solidconnection/common/exception/ErrorCode.java index 7b71469aa..824c531f6 100644 --- a/src/main/java/com/example/solidconnection/common/exception/ErrorCode.java +++ b/src/main/java/com/example/solidconnection/common/exception/ErrorCode.java @@ -44,6 +44,7 @@ public enum ErrorCode { LANGUAGE_TEST_SCORE_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "존재하지 않는 어학성적입니다."), NEWS_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "존재하지 않는 소식지입니다."), MENTOR_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "존재하지 않는 멘토입니다."), + REPORT_TARGET_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "존재하지 않는 신고 대상입니다."), // auth USER_ALREADY_SIGN_OUT(HttpStatus.UNAUTHORIZED.value(), "로그아웃 되었습니다."), @@ -78,7 +79,7 @@ public enum ErrorCode { // community INVALID_POST_CATEGORY(HttpStatus.BAD_REQUEST.value(), "잘못된 카테고리명입니다."), INVALID_BOARD_CODE(HttpStatus.BAD_REQUEST.value(), "잘못된 게시판 코드입니다."), - INVALID_POST_ID(HttpStatus.BAD_REQUEST.value(), "존재하지 않는 게시글입니다."), + INVALID_POST_ID(HttpStatus.BAD_REQUEST.value(), "존재하지 않는 게시글입니다."), // todo: NOT_FOUND로 통일 필요 INVALID_POST_ACCESS(HttpStatus.BAD_REQUEST.value(), "자신의 게시글만 제어할 수 있습니다."), CAN_NOT_DELETE_OR_UPDATE_QUESTION(HttpStatus.BAD_REQUEST.value(), "질문글은 수정이나 삭제할 수 없습니다."), CAN_NOT_UPLOAD_MORE_THAN_FIVE_IMAGES(HttpStatus.BAD_REQUEST.value(), "5개 이상의 파일을 업로드할 수 없습니다."), @@ -111,6 +112,9 @@ public enum ErrorCode { UNAUTHORIZED_MENTORING(HttpStatus.FORBIDDEN.value(), "멘토링 권한이 없습니다."), MENTORING_ALREADY_CONFIRMED(HttpStatus.BAD_REQUEST.value(), "이미 승인 또는 거절된 멘토링입니다."), + // report + ALREADY_REPORTED_BY_CURRENT_USER(HttpStatus.BAD_REQUEST.value(), "이미 신고한 상태입니다."), + // database DATA_INTEGRITY_VIOLATION(HttpStatus.CONFLICT.value(), "데이터베이스 무결성 제약조건 위반이 발생했습니다."), diff --git a/src/main/java/com/example/solidconnection/report/service/ReportService.java b/src/main/java/com/example/solidconnection/report/service/ReportService.java new file mode 100644 index 000000000..c1df1e84f --- /dev/null +++ b/src/main/java/com/example/solidconnection/report/service/ReportService.java @@ -0,0 +1,49 @@ +package com.example.solidconnection.report.service; + +import com.example.solidconnection.common.exception.CustomException; +import com.example.solidconnection.common.exception.ErrorCode; +import com.example.solidconnection.community.post.repository.PostRepository; +import com.example.solidconnection.report.domain.Report; +import com.example.solidconnection.report.domain.TargetType; +import com.example.solidconnection.report.dto.ReportRequest; +import com.example.solidconnection.report.repository.ReportRepository; +import com.example.solidconnection.siteuser.repository.SiteUserRepository; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class ReportService { + + private final ReportRepository reportRepository; + private final SiteUserRepository siteUserRepository; + private final PostRepository postRepository; + + @Transactional + public void createReport(long reporterId, ReportRequest request) { + validateReporterExists(reporterId); + validateTargetExists(request.targetType(), request.targetId()); + validateFirstReportByUser(reporterId, request.targetType(), request.targetId()); + + Report report = new Report(reporterId, request.targetType(), request.targetId(), request.type()); + reportRepository.save(report); + } + + private void validateReporterExists(long reporterId) { + siteUserRepository.findById(reporterId) + .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); + } + + private void validateTargetExists(TargetType targetType, long targetId) { + if (targetType == TargetType.POST && !postRepository.existsById(targetId)) { + throw new CustomException(ErrorCode.REPORT_TARGET_NOT_FOUND); + } + } + + private void validateFirstReportByUser(long reporterId, TargetType targetType, long targetId) { + if (reportRepository.existsByReporterIdAndTargetTypeAndTargetId(reporterId, targetType, targetId)) { + throw new CustomException(ErrorCode.ALREADY_REPORTED_BY_CURRENT_USER); + } + } +} From 26667ea2bc1f9b92af6a6e7ab5d8f5c9398ee161 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 23 Jul 2025 23:15:38 +0900 Subject: [PATCH 5/8] =?UTF-8?q?test:=20=EC=8B=A0=EA=B3=A0=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../community/post/fixture/PostFixture.java | 15 +++ .../report/fixture/ReportFixture.java | 21 ++++ .../report/fixture/ReportFixtureBuilder.java | 54 ++++++++++ .../report/service/ReportServiceTest.java | 99 +++++++++++++++++++ 4 files changed, 189 insertions(+) create mode 100644 src/test/java/com/example/solidconnection/report/fixture/ReportFixture.java create mode 100644 src/test/java/com/example/solidconnection/report/fixture/ReportFixtureBuilder.java create mode 100644 src/test/java/com/example/solidconnection/report/service/ReportServiceTest.java diff --git a/src/test/java/com/example/solidconnection/community/post/fixture/PostFixture.java b/src/test/java/com/example/solidconnection/community/post/fixture/PostFixture.java index 5d6eaea55..5ddf13888 100644 --- a/src/test/java/com/example/solidconnection/community/post/fixture/PostFixture.java +++ b/src/test/java/com/example/solidconnection/community/post/fixture/PostFixture.java @@ -13,6 +13,21 @@ public class PostFixture { private final PostFixtureBuilder postFixtureBuilder; + public Post 게시글( + Board board, + SiteUser siteUser + ) { + return postFixtureBuilder + .title("제목") + .content("내용") + .isQuestion(false) + .likeCount(0L) + .postCategory(PostCategory.자유) + .board(board) + .siteUser(siteUser) + .create(); + } + public Post 게시글( String title, String content, diff --git a/src/test/java/com/example/solidconnection/report/fixture/ReportFixture.java b/src/test/java/com/example/solidconnection/report/fixture/ReportFixture.java new file mode 100644 index 000000000..91c837bf3 --- /dev/null +++ b/src/test/java/com/example/solidconnection/report/fixture/ReportFixture.java @@ -0,0 +1,21 @@ +package com.example.solidconnection.report.fixture; + +import com.example.solidconnection.report.domain.Report; +import com.example.solidconnection.report.domain.TargetType; +import lombok.RequiredArgsConstructor; +import org.springframework.boot.test.context.TestComponent; + +@TestComponent +@RequiredArgsConstructor +public class ReportFixture { + + private final ReportFixtureBuilder reportFixtureBuilder; + + public Report 신고(long reporterId, TargetType targetType, long targetId) { + return reportFixtureBuilder.report() + .reporterId(reporterId) + .targetType(targetType) + .targetId(targetId) + .create(); + } +} diff --git a/src/test/java/com/example/solidconnection/report/fixture/ReportFixtureBuilder.java b/src/test/java/com/example/solidconnection/report/fixture/ReportFixtureBuilder.java new file mode 100644 index 000000000..aab195964 --- /dev/null +++ b/src/test/java/com/example/solidconnection/report/fixture/ReportFixtureBuilder.java @@ -0,0 +1,54 @@ +package com.example.solidconnection.report.fixture; + +import com.example.solidconnection.report.domain.ReasonType; +import com.example.solidconnection.report.domain.Report; +import com.example.solidconnection.report.domain.TargetType; +import com.example.solidconnection.report.repository.ReportRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.boot.test.context.TestComponent; + +@TestComponent +@RequiredArgsConstructor +public class ReportFixtureBuilder { + + private final ReportRepository reportRepository; + + private long reporterId; + private TargetType targetType; + private long targetId; + private ReasonType reasonType = ReasonType.ADVERTISEMENT; + + public ReportFixtureBuilder report() { + return new ReportFixtureBuilder(reportRepository); + } + + public ReportFixtureBuilder reporterId(long reporterId) { + this.reporterId = reporterId; + return this; + } + + public ReportFixtureBuilder targetType(TargetType targetType) { + this.targetType = targetType; + return this; + } + + public ReportFixtureBuilder targetId(long targetId) { + this.targetId = targetId; + return this; + } + + public ReportFixtureBuilder reasonType(ReasonType reasonType) { + this.reasonType = reasonType; + return this; + } + + public Report create() { + Report report = new Report( + reporterId, + targetType, + targetId, + reasonType + ); + return reportRepository.save(report); + } +} diff --git a/src/test/java/com/example/solidconnection/report/service/ReportServiceTest.java b/src/test/java/com/example/solidconnection/report/service/ReportServiceTest.java new file mode 100644 index 000000000..ad438934c --- /dev/null +++ b/src/test/java/com/example/solidconnection/report/service/ReportServiceTest.java @@ -0,0 +1,99 @@ +package com.example.solidconnection.report.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; + +import com.example.solidconnection.common.exception.CustomException; +import com.example.solidconnection.common.exception.ErrorCode; +import com.example.solidconnection.community.board.domain.Board; +import com.example.solidconnection.community.board.fixture.BoardFixture; +import com.example.solidconnection.community.post.domain.Post; +import com.example.solidconnection.community.post.fixture.PostFixture; +import com.example.solidconnection.report.domain.ReasonType; +import com.example.solidconnection.report.domain.TargetType; +import com.example.solidconnection.report.dto.ReportRequest; +import com.example.solidconnection.report.fixture.ReportFixture; +import com.example.solidconnection.report.repository.ReportRepository; +import com.example.solidconnection.siteuser.domain.SiteUser; +import com.example.solidconnection.siteuser.fixture.SiteUserFixture; +import com.example.solidconnection.support.TestContainerSpringBootTest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +@DisplayName("신고 서비스 테스트") +@TestContainerSpringBootTest +class ReportServiceTest { + + @Autowired + private ReportService reportService; + + @Autowired + private ReportRepository reportRepository; + + @Autowired + private BoardFixture boardFixture; + + @Autowired + private PostFixture postFixture; + + @Autowired + private SiteUserFixture siteUserFixture; + + @Autowired + private ReportFixture reportFixture; + + private SiteUser siteUser; + private Post post; + + @BeforeEach + void setUp() { + siteUser = siteUserFixture.사용자(); + Board board = boardFixture.자유게시판(); + post = postFixture.게시글(board, siteUser); + } + + @Nested + class 신고_생성 { + + @Test + void 정상적으로_신고한다() { + // given + ReportRequest request = new ReportRequest(post.getId(), TargetType.POST, ReasonType.INSULT); + + // when + reportService.createReport(siteUser.getId(), request); + + // then + boolean isSaved = reportRepository.existsByReporterIdAndTargetTypeAndTargetId( + siteUser.getId(), TargetType.POST, post.getId()); + assertThat(isSaved).isTrue(); + } + + @Test + void 신고_대상이_존재하지_않으면_예외가_발생한다() { + // given + long notExistingId = 999L; + ReportRequest request = new ReportRequest(notExistingId, TargetType.POST, ReasonType.INSULT); + + // when & then + assertThatCode(() -> reportService.createReport(siteUser.getId(), request)) + .isInstanceOf(CustomException.class) + .hasMessageContaining(ErrorCode.REPORT_TARGET_NOT_FOUND.getMessage()); + } + + @Test + void 이미_신고한_경우_예외가_발생한다() { + // given + reportFixture.신고(siteUser.getId(), TargetType.POST, post.getId()); + ReportRequest request = new ReportRequest(post.getId(), TargetType.POST, ReasonType.INSULT); + + // when & then + assertThatCode(() -> reportService.createReport(siteUser.getId(), request)) + .isInstanceOf(CustomException.class) + .hasMessageContaining(ErrorCode.ALREADY_REPORTED_BY_CURRENT_USER.getMessage()); + } + } +} From bdc675c643712ad2aa0df4a4728429a05386709d Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 23 Jul 2025 23:15:59 +0900 Subject: [PATCH 6/8] =?UTF-8?q?feat:=20=EC=8B=A0=EA=B3=A0=20=EC=BB=A8?= =?UTF-8?q?=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../report/controller/ReportController.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/main/java/com/example/solidconnection/report/controller/ReportController.java diff --git a/src/main/java/com/example/solidconnection/report/controller/ReportController.java b/src/main/java/com/example/solidconnection/report/controller/ReportController.java new file mode 100644 index 000000000..cab986f92 --- /dev/null +++ b/src/main/java/com/example/solidconnection/report/controller/ReportController.java @@ -0,0 +1,30 @@ +package com.example.solidconnection.report.controller; + +import com.example.solidconnection.common.resolver.AuthorizedUser; +import com.example.solidconnection.report.dto.ReportRequest; +import com.example.solidconnection.report.service.ReportService; +import com.example.solidconnection.siteuser.domain.SiteUser; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/reports") +public class ReportController { + + private final ReportService reportService; + + @PostMapping + public ResponseEntity createReport( + @AuthorizedUser SiteUser siteUser, + @Valid @RequestBody ReportRequest reportRequest + ) { + reportService.createReport(siteUser.getId(), reportRequest); + return ResponseEntity.ok().build(); + } +} From 0328fa4d4086796c2fbc3763cb0046a610c1c294 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Thu, 24 Jul 2025 23:11:59 +0900 Subject: [PATCH 7/8] =?UTF-8?q?refactor:=20'=EC=8B=A0=EA=B3=A0=20=EC=9C=A0?= =?UTF-8?q?=ED=98=95'=20=EC=BB=AC=EB=9F=BC=20=EC=9D=B4=EB=A6=84=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../solidconnection/report/domain/Report.java | 12 ++++++------ .../domain/{ReasonType.java => ReportType.java} | 2 +- .../solidconnection/report/dto/ReportRequest.java | 8 ++++---- .../report/service/ReportService.java | 2 +- .../db/migration/V24__create_report_table.sql | 2 +- .../report/fixture/ReportFixtureBuilder.java | 12 ++++++------ .../report/service/ReportServiceTest.java | 8 ++++---- 7 files changed, 23 insertions(+), 23 deletions(-) rename src/main/java/com/example/solidconnection/report/domain/{ReasonType.java => ReportType.java} (94%) diff --git a/src/main/java/com/example/solidconnection/report/domain/Report.java b/src/main/java/com/example/solidconnection/report/domain/Report.java index a65d44e8d..e723db281 100644 --- a/src/main/java/com/example/solidconnection/report/domain/Report.java +++ b/src/main/java/com/example/solidconnection/report/domain/Report.java @@ -32,6 +32,10 @@ public class Report { @Column(name = "reporter_id") private long reporterId; + @Column(name = "report_type") + @Enumerated(value = EnumType.STRING) + private ReportType reportType; + @Column(name = "target_type") @Enumerated(value = EnumType.STRING) private TargetType targetType; @@ -39,14 +43,10 @@ public class Report { @Column(name = "target_id") private long targetId; - @Column(name = "reason_type") - @Enumerated(value = EnumType.STRING) - private ReasonType reasonType; - - public Report(long reporterId, TargetType targetType, long targetId, ReasonType reasonType) { + public Report(long reporterId, ReportType reportType, TargetType targetType, long targetId) { + this.reportType = reportType; this.reporterId = reporterId; this.targetType = targetType; this.targetId = targetId; - this.reasonType = reasonType; } } diff --git a/src/main/java/com/example/solidconnection/report/domain/ReasonType.java b/src/main/java/com/example/solidconnection/report/domain/ReportType.java similarity index 94% rename from src/main/java/com/example/solidconnection/report/domain/ReasonType.java rename to src/main/java/com/example/solidconnection/report/domain/ReportType.java index caf33277f..18a5e5d9b 100644 --- a/src/main/java/com/example/solidconnection/report/domain/ReasonType.java +++ b/src/main/java/com/example/solidconnection/report/domain/ReportType.java @@ -1,6 +1,6 @@ package com.example.solidconnection.report.domain; -public enum ReasonType { +public enum ReportType { ADVERTISEMENT, // 광고 SPAM, // 낚시/도배 diff --git a/src/main/java/com/example/solidconnection/report/dto/ReportRequest.java b/src/main/java/com/example/solidconnection/report/dto/ReportRequest.java index ee16b2637..52f608015 100644 --- a/src/main/java/com/example/solidconnection/report/dto/ReportRequest.java +++ b/src/main/java/com/example/solidconnection/report/dto/ReportRequest.java @@ -1,17 +1,17 @@ package com.example.solidconnection.report.dto; -import com.example.solidconnection.report.domain.ReasonType; +import com.example.solidconnection.report.domain.ReportType; import com.example.solidconnection.report.domain.TargetType; import jakarta.validation.constraints.NotNull; public record ReportRequest( - long targetId, + @NotNull(message = "신고 유형을 선택해주세요.") + ReportType reportType, @NotNull(message = "신고 대상을 포함해주세요.") TargetType targetType, - @NotNull(message = "신고 사유를 선택해주세요.") - ReasonType type + long targetId ) { } diff --git a/src/main/java/com/example/solidconnection/report/service/ReportService.java b/src/main/java/com/example/solidconnection/report/service/ReportService.java index c1df1e84f..ae4e5f9b2 100644 --- a/src/main/java/com/example/solidconnection/report/service/ReportService.java +++ b/src/main/java/com/example/solidconnection/report/service/ReportService.java @@ -26,7 +26,7 @@ public void createReport(long reporterId, ReportRequest request) { validateTargetExists(request.targetType(), request.targetId()); validateFirstReportByUser(reporterId, request.targetType(), request.targetId()); - Report report = new Report(reporterId, request.targetType(), request.targetId(), request.type()); + Report report = new Report(reporterId, request.reportType(), request.targetType(), request.targetId()); reportRepository.save(report); } diff --git a/src/main/resources/db/migration/V24__create_report_table.sql b/src/main/resources/db/migration/V24__create_report_table.sql index daa92e7af..f40b6f562 100644 --- a/src/main/resources/db/migration/V24__create_report_table.sql +++ b/src/main/resources/db/migration/V24__create_report_table.sql @@ -4,7 +4,7 @@ CREATE TABLE report reporter_id BIGINT NOT NULL, target_type ENUM ('POST') NOT NULL, target_id BIGINT NOT NULL, - reason_type ENUM ('ADVERTISEMENT', 'SPAM', 'PERSONAL_INFO_EXPOSURE', 'PORNOGRAPHY', 'COPYRIGHT_INFRINGEMENT', 'ILLEGAL_ACTIVITY', 'IMPERSONATION', 'INSULT') NOT NULL, + report_type ENUM ('ADVERTISEMENT', 'SPAM', 'PERSONAL_INFO_EXPOSURE', 'PORNOGRAPHY', 'COPYRIGHT_INFRINGEMENT', 'ILLEGAL_ACTIVITY', 'IMPERSONATION', 'INSULT') NOT NULL, primary key (id), constraint fk_report_reporter_id foreign key (reporter_id) references site_user (id), unique uk_report_reporter_id_target_type_target_id (reporter_id, target_type, target_id) diff --git a/src/test/java/com/example/solidconnection/report/fixture/ReportFixtureBuilder.java b/src/test/java/com/example/solidconnection/report/fixture/ReportFixtureBuilder.java index aab195964..08d0b276c 100644 --- a/src/test/java/com/example/solidconnection/report/fixture/ReportFixtureBuilder.java +++ b/src/test/java/com/example/solidconnection/report/fixture/ReportFixtureBuilder.java @@ -1,7 +1,7 @@ package com.example.solidconnection.report.fixture; -import com.example.solidconnection.report.domain.ReasonType; import com.example.solidconnection.report.domain.Report; +import com.example.solidconnection.report.domain.ReportType; import com.example.solidconnection.report.domain.TargetType; import com.example.solidconnection.report.repository.ReportRepository; import lombok.RequiredArgsConstructor; @@ -16,7 +16,7 @@ public class ReportFixtureBuilder { private long reporterId; private TargetType targetType; private long targetId; - private ReasonType reasonType = ReasonType.ADVERTISEMENT; + private ReportType reportType = ReportType.ADVERTISEMENT; public ReportFixtureBuilder report() { return new ReportFixtureBuilder(reportRepository); @@ -37,17 +37,17 @@ public ReportFixtureBuilder targetId(long targetId) { return this; } - public ReportFixtureBuilder reasonType(ReasonType reasonType) { - this.reasonType = reasonType; + public ReportFixtureBuilder reasonType(ReportType reportType) { + this.reportType = reportType; return this; } public Report create() { Report report = new Report( reporterId, + reportType, targetType, - targetId, - reasonType + targetId ); return reportRepository.save(report); } diff --git a/src/test/java/com/example/solidconnection/report/service/ReportServiceTest.java b/src/test/java/com/example/solidconnection/report/service/ReportServiceTest.java index ad438934c..23523ae34 100644 --- a/src/test/java/com/example/solidconnection/report/service/ReportServiceTest.java +++ b/src/test/java/com/example/solidconnection/report/service/ReportServiceTest.java @@ -9,7 +9,7 @@ import com.example.solidconnection.community.board.fixture.BoardFixture; import com.example.solidconnection.community.post.domain.Post; import com.example.solidconnection.community.post.fixture.PostFixture; -import com.example.solidconnection.report.domain.ReasonType; +import com.example.solidconnection.report.domain.ReportType; import com.example.solidconnection.report.domain.TargetType; import com.example.solidconnection.report.dto.ReportRequest; import com.example.solidconnection.report.fixture.ReportFixture; @@ -61,7 +61,7 @@ class 신고_생성 { @Test void 정상적으로_신고한다() { // given - ReportRequest request = new ReportRequest(post.getId(), TargetType.POST, ReasonType.INSULT); + ReportRequest request = new ReportRequest(ReportType.INSULT, TargetType.POST, post.getId()); // when reportService.createReport(siteUser.getId(), request); @@ -76,7 +76,7 @@ class 신고_생성 { void 신고_대상이_존재하지_않으면_예외가_발생한다() { // given long notExistingId = 999L; - ReportRequest request = new ReportRequest(notExistingId, TargetType.POST, ReasonType.INSULT); + ReportRequest request = new ReportRequest(ReportType.INSULT, TargetType.POST, notExistingId); // when & then assertThatCode(() -> reportService.createReport(siteUser.getId(), request)) @@ -88,7 +88,7 @@ class 신고_생성 { void 이미_신고한_경우_예외가_발생한다() { // given reportFixture.신고(siteUser.getId(), TargetType.POST, post.getId()); - ReportRequest request = new ReportRequest(post.getId(), TargetType.POST, ReasonType.INSULT); + ReportRequest request = new ReportRequest(ReportType.INSULT, TargetType.POST, post.getId()); // when & then assertThatCode(() -> reportService.createReport(siteUser.getId(), request)) From ad803d9f9d2f1521b667774d10eee6420934aa9c Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Thu, 24 Jul 2025 23:13:00 +0900 Subject: [PATCH 8/8] =?UTF-8?q?refactor:=20findBy=20=EB=B3=B4=EB=8B=A4=20?= =?UTF-8?q?=EC=84=B1=EB=8A=A5=EC=9D=B4=20=EC=A2=8B=EC=9D=80=20existsBy=20?= =?UTF-8?q?=EB=A1=9C=20=EC=A1=B4=EC=9E=AC=20=EC=97=AC=EB=B6=80=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../solidconnection/report/service/ReportService.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/solidconnection/report/service/ReportService.java b/src/main/java/com/example/solidconnection/report/service/ReportService.java index ae4e5f9b2..3546861ea 100644 --- a/src/main/java/com/example/solidconnection/report/service/ReportService.java +++ b/src/main/java/com/example/solidconnection/report/service/ReportService.java @@ -31,8 +31,9 @@ public void createReport(long reporterId, ReportRequest request) { } private void validateReporterExists(long reporterId) { - siteUserRepository.findById(reporterId) - .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); + if (!siteUserRepository.existsById(reporterId)) { + throw new CustomException(ErrorCode.USER_NOT_FOUND); + } } private void validateTargetExists(TargetType targetType, long targetId) {