Skip to content

Commit

Permalink
투표글, 댓글, 닉네임 신고 기능 구현 (#262)
Browse files Browse the repository at this point in the history
* feat: (#164) 신고 엔티티, 레포지토리 구현

* feat: (#164) 게시글 신고 기능 구현

* refactor: (#164) 도메인으로 로직 이동, 및 예외 추가, 함수 분리

* test: (#164) Report의 repository, service 테스트 추가

* feat: (#164) 닉네임 신고 기능 구현

* refactor: (#164) 닉네임 getter 추가

* test: (#164) 닉네임 신고 기능에 대한 검증 추가

* chore: (#164) swagger 어노테이션 추가

* test: (#164) 컨트롤러 신고 검증 추가

* refactor: (#164) nested로 신고 기능 묶기

* refactor: (#164) Report 엔티티 클래스에 컬럼 복합 인덱스 설정

* refactor: (#164) 신고에 대한 비즈니스 로직을 어플리케이션 계층으로 이동

* refactor: (#164) enum타입으로 request받기, ReportService 클래스의 메서드 분리, 중복제거

* refactor: (#164) Report 클래스 reason 필드 추가

* refactor: (#164) NumberGenerator, NicknameNumberGenerator 삭제

* refactor: (#164) 신고 횟수에 대한 비즈니스 로직을 어플리케이션 계층으로 이동

* chore: (#164) conflict 해결 완료

* chore: (#164) conflict 해결 완료
  • Loading branch information
jeomxon authored Aug 9, 2023
1 parent 851fc9c commit 3495a23
Show file tree
Hide file tree
Showing 47 changed files with 1,257 additions and 849 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.apache.commons.lang3.RandomStringUtils;

@NoArgsConstructor(access = AccessLevel.PROTECTED)
@EqualsAndHashCode(of = {"id"})
@ToString
@Getter
@Entity
public class Member extends BaseEntity {
Expand Down Expand Up @@ -91,8 +93,13 @@ public void changeNickname(final String nickname) {
this.nickname = new Nickname(nickname);
}

public void changeNicknameByReport() {
final String reportedNickname = "Pause1" + RandomStringUtils.random(9, true, true);
this.nickname = new Nickname(reportedNickname);
}

public String getNickname() {
return nickname.getValue();
return this.nickname.getValue();
}

}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.votogether.domain.member.entity.Member;
import com.votogether.domain.post.entity.comment.Comment;
import com.votogether.domain.post.exception.PostExceptionType;
import com.votogether.domain.report.exception.ReportExceptionType;
import com.votogether.domain.vote.entity.Vote;
import com.votogether.exception.BadRequestException;
import jakarta.persistence.Basic;
Expand Down Expand Up @@ -57,6 +58,9 @@ public class Post extends BaseEntity {
@Column(columnDefinition = "datetime(6)", nullable = false)
private LocalDateTime deadline;

@Column(nullable = false)
private boolean isHidden;

@Basic(fetch = FetchType.LAZY)
@Formula("(select count(v.id) from Vote v where v.post_option_id in "
+ "(select po.id from Post_Option po where po.post_id = id)"
Expand All @@ -70,13 +74,15 @@ public class Post extends BaseEntity {
private Post(
final Member writer,
final PostBody postBody,
final LocalDateTime deadline
final LocalDateTime deadline,
final boolean isHidden
) {
this.writer = writer;
this.postBody = postBody;
this.deadline = deadline;
this.postCategories = new PostCategories();
this.postOptions = new PostOptions();
this.isHidden = isHidden;
}

public void mapCategories(final List<Category> categories) {
Expand Down Expand Up @@ -178,6 +184,22 @@ public boolean isVisibleVoteResult(final Member member) {
return this.postOptions.getSelectedOptionId(member) != 0 || this.writer.equals(member);
}

public void blind() {
this.isHidden = true;
}

public void validateMine(final Member member) {
if (this.writer.equals(member)) {
throw new BadRequestException(ReportExceptionType.REPORT_MY_POST);
}
}

public void validateHidden() {
if (this.isHidden) {
throw new BadRequestException(ReportExceptionType.ALREADY_HIDDEN_POST);
}
}

public void addComment(final Comment comment) {
comments.add(comment);
comment.setPost(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import com.votogether.domain.member.entity.Member;
import com.votogether.domain.post.entity.Post;
import com.votogether.domain.post.exception.CommentExceptionType;
import com.votogether.domain.report.exception.ReportExceptionType;
import com.votogether.exception.BadRequestException;
import jakarta.persistence.Column;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
Expand Down Expand Up @@ -41,11 +43,20 @@ public class Comment extends BaseEntity {
@Embedded
private Content content;

@Column(nullable = false)
private boolean isHidden;

@Builder
private Comment(final Post post, final Member member, final String content) {
private Comment(
final Post post,
final Member member,
final String content,
final boolean isHidden
) {
this.post = post;
this.member = member;
this.content = new Content(content);
this.isHidden = isHidden;
}

public void validateWriter(final Member member) {
Expand All @@ -60,10 +71,27 @@ public void validateBelong(final Post post) {
}
}

public void blind() {
this.isHidden = true;
}

public void validateMine(final Member reporter) {
if (this.member.equals(reporter)) {
throw new BadRequestException(ReportExceptionType.REPORT_MY_COMMENT);
}
}

public void validateHidden() {
if (this.isHidden) {
throw new BadRequestException(ReportExceptionType.ALREADY_HIDDEN_COMMENT);
}
}

public void updateContent(final String content) {
this.content = new Content(content);
}


public String getContent() {
return content.getValue();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.votogether.domain.member.entity.Member;
import com.votogether.domain.post.entity.Post;
import java.time.LocalDateTime;
import java.util.List;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.repository.JpaRepository;
Expand All @@ -17,6 +18,8 @@ public interface PostRepository extends JpaRepository<Post, Long>, PostCustomRep

int countByWriter(final Member member);

List<Post> findAllByWriter(final Member member);

@Query("SELECT v.postOption.post FROM Vote v WHERE v.member = :member "
+ "AND v.postOption.post.deadline < CURRENT_TIMESTAMP")
Slice<Post> findClosedPostsVotedByMember(@Param("member") final Member member, final Pageable pageable);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.votogether.domain.report.controller;

import com.votogether.domain.member.entity.Member;
import com.votogether.domain.report.dto.ReportRequest;
import com.votogether.domain.report.service.ReportService;
import com.votogether.global.jwt.Auth;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
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.RestController;

@RequiredArgsConstructor
@RestController
public class ReportController {

private final ReportService reportService;

@Operation(summary = "신고 기능", description = "게시글, 댓글, 닉네임을 신고한다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "신고 성공"),
@ApiResponse(responseCode = "400", description = "올바르지 않은 요청"),
@ApiResponse(responseCode = "404", description = "존재하지 않는 신고 대상")
})
@PostMapping("/report")
public ResponseEntity<Void> report(@Valid @RequestBody final ReportRequest request, @Auth final Member member) {
reportService.report(member, request);
return ResponseEntity.ok().build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.votogether.domain.report.dto;

import com.votogether.domain.report.entity.ReportType;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

@Schema(description = "신고 요청")
public record ReportRequest(
@Schema(description = "신고유형", example = "POST")
ReportType type,
@Schema(description = "신고대상ID", example = "1")
@NotNull(message = "대상 ID값은 빈 값일 수 없습니다.")
Long id,
@Schema(description = "신고 사유", example = "불건전한 닉네임")
@NotBlank(message = "신고 이유는 빈 값이거나 공백으로만 이루어질 수 없습니다.")
String reason
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.votogether.domain.report.entity;

import com.votogether.domain.common.BaseEntity;
import com.votogether.domain.member.entity.Member;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Table(
uniqueConstraints = {@UniqueConstraint(columnNames = {"member_id", "reportType", "targetId"})},
indexes = {@Index(columnList = "reportType, targetId")}
)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Entity
public class Report extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id", nullable = false)
private Member member;

@Enumerated(value = EnumType.STRING)
@Column(length = 10, nullable = false)
private ReportType reportType;

@Column(nullable = false)
private Long targetId;

@Column(nullable = false, length = 50)
private String reason;

@Builder
private Report(
final Member member,
final ReportType reportType,
final Long targetId,
final String reason
) {
this.member = member;
this.reportType = reportType;
this.targetId = targetId;
this.reason = reason;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.votogether.domain.report.entity;

public enum ReportType {

POST,
COMMENT,
NICKNAME,
;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.votogether.domain.report.exception;

import com.votogether.exception.ExceptionType;
import lombok.Getter;

@Getter
public enum ReportExceptionType implements ExceptionType {

REPORT_MY_POST(1200, "자신의 게시글은 신고할 수 없습니다."),
ALREADY_HIDDEN_POST(1201, "이미 블라인드 처리된 글입니다."),
DUPLICATE_POST_REPORT(1202, "하나의 글에 대해서 중복하여 신고할 수 없습니다."),
REPORT_MY_COMMENT(1203, "자신의 댓글은 신고할 수 없습니다."),
ALREADY_HIDDEN_COMMENT(1204, "이미 블라인드 처리된 댓글입니다."),
DUPLICATE_COMMENT_REPORT(1205, "하나의 댓글에 대해서 중복하여 신고할 수 없습니다."),
REPORT_MY_NICKNAME(1206, "자신의 닉네임은 신고할 수 없습니다."),
DUPLICATE_NICKNAME_REPORT(1207, "하나의 닉네임에 대해서 중복하여 신고할 수 없습니다."),
;

private final int code;
private final String message;

ReportExceptionType(final int code, final String message) {
this.code = code;
this.message = message;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.votogether.domain.report.repository;

import com.votogether.domain.member.entity.Member;
import com.votogether.domain.report.entity.Report;
import com.votogether.domain.report.entity.ReportType;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ReportRepository extends JpaRepository<Report, Long> {

int countByReportTypeAndTargetId(final ReportType reportType, final Long targetId);

Optional<Report> findByMemberAndReportTypeAndTargetId(
final Member member,
final ReportType reportType,
final Long targetId
);

}
Loading

0 comments on commit 3495a23

Please sign in to comment.