From 37d24571fc1120a732675e9984cd8f82e0e1d211 Mon Sep 17 00:00:00 2001 From: Park Yun Chan Date: Tue, 1 Oct 2024 14:14:21 +0900 Subject: [PATCH] =?UTF-8?q?=ED=94=BC=EB=93=9C=20=EC=8B=A0=EA=B3=A0=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20(#285)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feature: 피드 신고 기록 기능 구현 * fix: 필요없는 메서드 삭제 * fix: Report 엔티티에 BaseTimeEntity추가 * fix: /reports/ 엔드포인트 제거 * fix: ErrorCode message수정 * fix: 정적 팩토리 메서드 사용 * fix: DTO에 Swagger Schema 어노테이션추가 * fix: reportReason을 request에서 String으로 요청 * fix: response example 수정 --- .../domain/report/api/ReportController.java | 28 +++++++++ .../report/application/ReportService.java | 38 ++++++++++++ .../domain/report/dao/ReportRepository.java | 6 ++ .../stonebed/domain/report/domain/Report.java | 58 +++++++++++++++++++ .../report/dto/request/ReportRequest.java | 18 ++++++ .../dto/response/ReportReasonResponse.java | 8 +++ .../stonebed/global/error/ErrorCode.java | 5 +- 7 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/depromeet/stonebed/domain/report/api/ReportController.java create mode 100644 src/main/java/com/depromeet/stonebed/domain/report/application/ReportService.java create mode 100644 src/main/java/com/depromeet/stonebed/domain/report/dao/ReportRepository.java create mode 100644 src/main/java/com/depromeet/stonebed/domain/report/domain/Report.java create mode 100644 src/main/java/com/depromeet/stonebed/domain/report/dto/request/ReportRequest.java create mode 100644 src/main/java/com/depromeet/stonebed/domain/report/dto/response/ReportReasonResponse.java diff --git a/src/main/java/com/depromeet/stonebed/domain/report/api/ReportController.java b/src/main/java/com/depromeet/stonebed/domain/report/api/ReportController.java new file mode 100644 index 00000000..aa9c13d8 --- /dev/null +++ b/src/main/java/com/depromeet/stonebed/domain/report/api/ReportController.java @@ -0,0 +1,28 @@ +package com.depromeet.stonebed.domain.report.api; + +import com.depromeet.stonebed.domain.report.application.ReportService; +import com.depromeet.stonebed.domain.report.dto.request.ReportRequest; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +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; + +@Tag(name = "8. [신고]", description = "신고 기능 관련 API입니다.") +@RestController +@RequestMapping("/reports") +@RequiredArgsConstructor +public class ReportController { + private final ReportService reportService; + + @Operation(summary = "신고하기", description = "특정 피드를 신고한다.") + @PostMapping + public ResponseEntity reportFeed(@RequestBody ReportRequest reportRequest) { + reportService.reportFeed(reportRequest); + return ResponseEntity.status(HttpStatus.CREATED).build(); + } +} diff --git a/src/main/java/com/depromeet/stonebed/domain/report/application/ReportService.java b/src/main/java/com/depromeet/stonebed/domain/report/application/ReportService.java new file mode 100644 index 00000000..ba2f24a0 --- /dev/null +++ b/src/main/java/com/depromeet/stonebed/domain/report/application/ReportService.java @@ -0,0 +1,38 @@ +package com.depromeet.stonebed.domain.report.application; + +import com.depromeet.stonebed.domain.member.domain.Member; +import com.depromeet.stonebed.domain.missionRecord.dao.MissionRecordRepository; +import com.depromeet.stonebed.domain.missionRecord.domain.MissionRecord; +import com.depromeet.stonebed.domain.report.dao.ReportRepository; +import com.depromeet.stonebed.domain.report.domain.Report; +import com.depromeet.stonebed.domain.report.dto.request.ReportRequest; +import com.depromeet.stonebed.global.error.ErrorCode; +import com.depromeet.stonebed.global.error.exception.CustomException; +import com.depromeet.stonebed.global.util.MemberUtil; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional +public class ReportService { + private final ReportRepository reportRepository; + private final MissionRecordRepository missionRecordRepository; + private final MemberUtil memberUtil; + + public void reportFeed(ReportRequest reportRequest) { + final Member member = memberUtil.getCurrentMember(); + + MissionRecord missionRecord = + missionRecordRepository + .findById(reportRequest.recordId()) + .orElseThrow(() -> new CustomException(ErrorCode.MISSION_RECORD_NOT_FOUND)); + + Report report = + Report.createReport( + missionRecord, member, reportRequest.reason(), reportRequest.details()); + + reportRepository.save(report); + } +} diff --git a/src/main/java/com/depromeet/stonebed/domain/report/dao/ReportRepository.java b/src/main/java/com/depromeet/stonebed/domain/report/dao/ReportRepository.java new file mode 100644 index 00000000..fb70a0e3 --- /dev/null +++ b/src/main/java/com/depromeet/stonebed/domain/report/dao/ReportRepository.java @@ -0,0 +1,6 @@ +package com.depromeet.stonebed.domain.report.dao; + +import com.depromeet.stonebed.domain.report.domain.Report; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ReportRepository extends JpaRepository {} diff --git a/src/main/java/com/depromeet/stonebed/domain/report/domain/Report.java b/src/main/java/com/depromeet/stonebed/domain/report/domain/Report.java new file mode 100644 index 00000000..80d962b1 --- /dev/null +++ b/src/main/java/com/depromeet/stonebed/domain/report/domain/Report.java @@ -0,0 +1,58 @@ +package com.depromeet.stonebed.domain.report.domain; + +import com.depromeet.stonebed.domain.common.BaseTimeEntity; +import com.depromeet.stonebed.domain.member.domain.Member; +import com.depromeet.stonebed.domain.missionRecord.domain.MissionRecord; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "feed_report") +public class Report extends BaseTimeEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "mission_record_id", nullable = false) + private MissionRecord missionRecord; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id", nullable = false) + private Member member; + + private String reason; + + private String details; + + @Builder(access = AccessLevel.PRIVATE) + private Report(MissionRecord missionRecord, Member member, String reason, String details) { + this.missionRecord = missionRecord; + this.member = member; + this.reason = reason; + this.details = details; + } + + public static Report createReport( + MissionRecord missionRecord, Member member, String reportReason, String details) { + return Report.builder() + .missionRecord(missionRecord) + .member(member) + .reason(reportReason) + .details(details) + .build(); + } +} diff --git a/src/main/java/com/depromeet/stonebed/domain/report/dto/request/ReportRequest.java b/src/main/java/com/depromeet/stonebed/domain/report/dto/request/ReportRequest.java new file mode 100644 index 00000000..fe0be098 --- /dev/null +++ b/src/main/java/com/depromeet/stonebed/domain/report/dto/request/ReportRequest.java @@ -0,0 +1,18 @@ +package com.depromeet.stonebed.domain.report.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +@Schema(description = "신고 요청 정보") +public record ReportRequest( + @Schema(description = "신고할 대상 기록의 ID", example = "123", required = true) @NotNull + Long recordId, + @Schema(description = "신고 사유", example = "사기 또는 사칭", required = true) @NotNull + String reason, + @Schema( + description = "신고 상세 내용 (최대 500자)", + example = "해당 게시물은 부적절한 내용을 포함하고 있습니다.", + maxLength = 500) + @Size(max = 500) + String details) {} diff --git a/src/main/java/com/depromeet/stonebed/domain/report/dto/response/ReportReasonResponse.java b/src/main/java/com/depromeet/stonebed/domain/report/dto/response/ReportReasonResponse.java new file mode 100644 index 00000000..6c682e75 --- /dev/null +++ b/src/main/java/com/depromeet/stonebed/domain/report/dto/response/ReportReasonResponse.java @@ -0,0 +1,8 @@ +package com.depromeet.stonebed.domain.report.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "신고 사유 응답 정보") +public record ReportReasonResponse( + @Schema(description = "신고 사유", example = "HARASSMENT") String enumValue, + @Schema(description = "신고 사유 설명", example = "사기 또는 사칭") String description) {} diff --git a/src/main/java/com/depromeet/stonebed/global/error/ErrorCode.java b/src/main/java/com/depromeet/stonebed/global/error/ErrorCode.java index 9d40cd91..dd76c07f 100644 --- a/src/main/java/com/depromeet/stonebed/global/error/ErrorCode.java +++ b/src/main/java/com/depromeet/stonebed/global/error/ErrorCode.java @@ -57,7 +57,10 @@ public enum ErrorCode { // fcm INVALID_FCM_TOKEN(HttpStatus.BAD_REQUEST, "FCM 토큰값이 비어있습니다."), FAILED_TO_FIND_FCM_TOKEN(HttpStatus.NOT_FOUND, "해당 FCM 토큰을 찾을 수 없습니다."), - NOTIFICATION_NOT_FOUND(HttpStatus.NOT_FOUND, "해당 알림을 찾을 수 없습니다."); + NOTIFICATION_NOT_FOUND(HttpStatus.NOT_FOUND, "해당 알림을 찾을 수 없습니다."), + + // report + INVALID_REPORT_REASON(HttpStatus.NOT_FOUND, "해당 신고 사유를 찾을 수 없습니다."); private final HttpStatus httpStatus; private final String message; }