Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

피드 신고 기능 구현 #285

Merged
merged 9 commits into from
Oct 1, 2024
Original file line number Diff line number Diff line change
@@ -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<Void> reportFeed(@RequestBody ReportRequest reportRequest) {
reportService.reportFeed(reportRequest);
return ResponseEntity.status(HttpStatus.CREATED).build();
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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<Report, Long> {}
Original file line number Diff line number Diff line change
@@ -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;

Comment on lines +36 to +38
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Enumerated(EnumType.STRING) 사용해서 Enum 타입으로 정의하지 않는 이유가 있을까용??

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EnumType.STRING을 사용하면 db에 enum의 name값이들어가서 convert를 사용하거나 String을사용해서 value를 저장하려했습니다. 혹시 좋은 방법이 있을까요

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아니면 이건 기획 의도따라 다르겠지만 굳이 ReportReason을 enum으로 정의하지 않고,
일반적인 String 값으로 받는 건 어떨까요??

신고하려는 이유가 너무 불특정하게 계속 생길 수도 있고, enum에 대한 길이도 계속 길어지다보니 굳이 enum 자체를 Request 받지 않고 String으로 Request 받아도 될 듯해용

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

음.. figma를 봤을 땐 기획상 신고 사유가 많아지더라도 지금 수준이랑 비슷할 것 같다고 생각했어요! 그리고 기타라는 항목도 있기에 크게 이유가 불특정하게 enum값이 생길 것 같다고 생각을 안했습니다.

저는 Enum을 사용해서 관리하는 부분이 좀 더 낫다고 생각하는데 어떻게 생각하시나요?

추가로 현재는 Enum을 name-value형식으로 되어있는데 @convert를 사용해서 Enum을 사용하되, 원하는 value값을 저장하는 방식으로 코드를 수정하는건 어떨까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

위의 댓글 취소!,,, 윤범님이 말씀하신대로 클라이언트한테 request를 String으로받고 하는식으로 진행하도록 하겠습니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수정된 부분 확인한번 부탁드릴게요~

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();
}
}
Original file line number Diff line number Diff line change
@@ -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) {}
Original file line number Diff line number Diff line change
@@ -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) {}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Loading