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

[Feat] 신고 기능 추가 #158

Merged
merged 2 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
67 changes: 67 additions & 0 deletions src/main/generated/me/snaptime/report/domain/QReport.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package me.snaptime.report.domain;

import static com.querydsl.core.types.PathMetadataFactory.*;

import com.querydsl.core.types.dsl.*;

import com.querydsl.core.types.PathMetadata;
import javax.annotation.processing.Generated;
import com.querydsl.core.types.Path;
import com.querydsl.core.types.dsl.PathInits;


/**
* QReport is a Querydsl query type for Report
*/
@Generated("com.querydsl.codegen.DefaultEntitySerializer")
public class QReport extends EntityPathBase<Report> {

private static final long serialVersionUID = 454582437L;

private static final PathInits INITS = PathInits.DIRECT2;

public static final QReport report = new QReport("report");

public final me.snaptime.common.QBaseTimeEntity _super = new me.snaptime.common.QBaseTimeEntity(this);

//inherited
public final DateTimePath<java.time.LocalDateTime> createdDate = _super.createdDate;

public final NumberPath<Long> id = createNumber("id", Long.class);

//inherited
public final DateTimePath<java.time.LocalDateTime> lastModifiedDate = _super.lastModifiedDate;

public final me.snaptime.user.domain.QUser reporter;

public final EnumPath<me.snaptime.report.domain.enums.ReportReason> reportReason = createEnum("reportReason", me.snaptime.report.domain.enums.ReportReason.class);

public final EnumPath<me.snaptime.report.domain.enums.ReportStatus> reportStatus = createEnum("reportStatus", me.snaptime.report.domain.enums.ReportStatus.class);

public final EnumPath<me.snaptime.report.domain.enums.ReportType> reportType = createEnum("reportType", me.snaptime.report.domain.enums.ReportType.class);

public final NumberPath<Long> targetId = createNumber("targetId", Long.class);

public QReport(String variable) {
this(Report.class, forVariable(variable), INITS);
}

public QReport(Path<? extends Report> path) {
this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS));
}

public QReport(PathMetadata metadata) {
this(metadata, PathInits.getFor(metadata, INITS));
}

public QReport(PathMetadata metadata, PathInits inits) {
this(Report.class, metadata, inits);
}

public QReport(Class<? extends Report> type, PathMetadata metadata, PathInits inits) {
super(type, metadata, inits);
this.reporter = inits.isInitialized("reporter") ? new me.snaptime.user.domain.QUser(forProperty("reporter"), inits.get("reporter")) : null;
}

}

4 changes: 4 additions & 0 deletions src/main/generated/me/snaptime/user/domain/QUser.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ public class QUser extends EntityPathBase<User> {

public final me.snaptime.common.QBaseTimeEntity _super = new me.snaptime.common.QBaseTimeEntity(this);

public final DateTimePath<java.time.LocalDateTime> banEndTime = createDateTime("banEndTime", java.time.LocalDateTime.class);

//inherited
public final DateTimePath<java.time.LocalDateTime> createdDate = _super.createdDate;

Expand All @@ -38,6 +40,8 @@ public class QUser extends EntityPathBase<User> {

public final StringPath password = createString("password");

public final NumberPath<Integer> penalty = createNumber("penalty", Integer.class);

public final me.snaptime.profilePhoto.domain.QProfilePhoto profilePhoto;

public final ListPath<String, StringPath> roles = this.<String, StringPath>createList("roles", String.class, StringPath.class, PathInits.DIRECT2);
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/me/snaptime/SnaptimeApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import io.swagger.v3.oas.annotations.servers.Server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@EnableScheduling
@OpenAPIDefinition(servers =
{@Server(url = "/", description = "Development Server URL")})
@SpringBootApplication
Expand Down
7 changes: 6 additions & 1 deletion src/main/java/me/snaptime/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,12 @@ protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exce
.requestMatchers("/emails/send", "/emails/verify").permitAll()
.requestMatchers(HttpMethod.GET,"/users/profile", "/profile-photos/**","/snap/**","/friends/**").permitAll()
.requestMatchers("**exception**").permitAll()
.anyRequest().hasRole("USER")
.requestMatchers(HttpMethod.POST).hasAnyRole("USER", "ADMIN")
.requestMatchers(HttpMethod.PUT).hasAnyRole("USER", "ADMIN")
.requestMatchers(HttpMethod.PATCH).hasAnyRole("USER", "ADMIN")
.requestMatchers(HttpMethod.DELETE).hasAnyRole("USER", "ADMIN")
.requestMatchers("/**").hasAnyRole("USER", "ADMIN", "BEN")

)
.addFilterBefore(new JwtExceptionHandlerFilter(),
UsernamePasswordAuthenticationFilter.class)
Expand Down
12 changes: 11 additions & 1 deletion src/main/java/me/snaptime/exception/ExceptionCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ public enum ExceptionCode {
PASSWORD_DUPLICATE(HttpStatus.BAD_REQUEST,"같은 비밀번호로 수정 할 수 없습니다."),
LOGIN_ID_ALREADY_EXIST(HttpStatus.BAD_REQUEST, "이미 존재하는 loginId 입니다."),
EMAIL_DUPLICATE(HttpStatus.BAD_REQUEST,"이미 존재하는 이메일입니다."),
NOT_ADMIN(HttpStatus.BAD_REQUEST,"관리자 게정이 아닙니다."),

// Snap Exception
SNAP_NOT_EXIST(HttpStatus.BAD_REQUEST, "스냅이 존재하지 않습니다."),
SNAP_IS_PRIVATE(HttpStatus.BAD_REQUEST, "사용자가 이 스냅을 비공개로 설정했습니다."),
Expand Down Expand Up @@ -73,7 +75,15 @@ public enum ExceptionCode {
TOKEN_NOT_FOUND(HttpStatus.BAD_REQUEST, "토큰이 비었거나 null입니다"),

// Jsoup Action
URL_HAVING_PROBLEM(HttpStatus.BAD_REQUEST, "문제가 있는 URL입니다.");
URL_HAVING_PROBLEM(HttpStatus.BAD_REQUEST, "문제가 있는 URL입니다."),

// Report Exception
SELF_REPORT_NOT_ALLOWED(HttpStatus.BAD_REQUEST, "자신의 스냅, 댓글에 신고를 할 수 없습니다."),
DUPLICATE_REPORT(HttpStatus.BAD_REQUEST, "신고는 한번만 가능합니다."),
REPORT_NOT_EXIST(HttpStatus.BAD_REQUEST, "신고가 존재하지 않습니다."),
INVALID_REPORT_STATUS(HttpStatus.BAD_REQUEST,"올바르지 않은 신고 상태입니다."),
INVALID_REPORT_TYPE(HttpStatus.BAD_REQUEST,"올바르지 않은 신고 타입입니다."),
;

private final HttpStatus status;
private final String message;
Expand Down
9 changes: 4 additions & 5 deletions src/main/java/me/snaptime/jwt/JwtProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ protected void init(){
}

public String createAccessToken(Long userId, String email, List<String> roles){
Claims claims = Jwts.claims().setSubject(email);
Claims claims = (Claims) Jwts.claims().setSubject(email);
claims.put("userId",userId);
claims.put("type","access");
claims.put("roles",roles);
Expand Down Expand Up @@ -90,7 +90,7 @@ public String testCreateAccessToken(Long userId, String email, List<String> role
}

public String testCreateRefreshToken(Long id, String email, List<String> roles){
Claims claims = Jwts.claims().setSubject(email);
Claims claims = (Claims) Jwts.claims().setSubject(email);
claims.put("userId", id);
claims.put("type", "testRefresh");
claims.put("roles", roles);
Expand Down Expand Up @@ -123,9 +123,8 @@ public Authentication getAuthentication(String token){
//Jwts.parser()를 통해 secretKey를 설정하고 클레임을 추출해서 토큰을 생성할 때 넣었던 sub값을 추출합니다.
public String getUsername(String token)
{
String email = Jwts.parserBuilder()
String email = Jwts.parser()
.setSigningKey(secretKey)
.build()
.parseClaimsJws(token)
.getBody()
.getSubject();
Expand Down Expand Up @@ -171,7 +170,7 @@ public boolean validateToken(String token) {
}

private Claims getClaims(String token) {
JwtParser jwtParser = Jwts.parserBuilder().setSigningKey(secretKey).build();
JwtParser jwtParser = Jwts.parser().setSigningKey(secretKey);
try {
// Try to parse claims
return jwtParser.parseClaimsJws(token).getBody();
Expand Down
93 changes: 93 additions & 0 deletions src/main/java/me/snaptime/report/controller/ReportController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package me.snaptime.report.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.snaptime.common.CommonResponseDto;
import me.snaptime.report.dto.PagingReportInfo;
import me.snaptime.report.dto.ReportInfo;
import me.snaptime.report.domain.enums.ReportReason;
import me.snaptime.report.domain.enums.ReportStatus;
import me.snaptime.report.domain.enums.ReportType;
import me.snaptime.report.service.ReportService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;

@Tag(name = "[Report] Report API")
@RestController
@RequiredArgsConstructor
@Slf4j
@RequestMapping("/report")
public class ReportController {

private final ReportService reportService;


@Operation(summary = "게시물/댓글 을 신고합니다.", description = "게시글/댓글 ID와 신고 사유, 신고 대상 타입(SNAP, CHILD_REPLY, PARENT_REPLY 를 입력해주세요.")
@PostMapping("/create/{targetId}")
public ResponseEntity<CommonResponseDto<ReportInfo>> createReport(
@AuthenticationPrincipal UserDetails userDetails,
@PathVariable("targetId")Long targetId,
ReportReason reason,
ReportType type){
log.info("report Id : {}, report type : {} report Reason : {}", targetId, type, reason);
String reqEmail = userDetails.getUsername();
ReportInfo reportInfo = reportService.createReport(reqEmail,targetId,type,reason);

return ResponseEntity.status(HttpStatus.OK).body(new CommonResponseDto<>(
type + " 신고를 성공적으로 완료하였습니다.",
reportInfo
));
}
@Operation(summary = "신고 내역 조회", description = "관리자의 권한으로 상태에 맞는 신고 내역을 조회합니다. + <br><br> +" +
"PENDING(대기중), UNDER_REVIEW(검토중), REJECT(신고가 반려된 상태), APPROVE(신고가 승인되어 조치 하면 되는 상태)")
@GetMapping("/admin")
public ResponseEntity<CommonResponseDto<PagingReportInfo>> getReportByStatus(
@AuthenticationPrincipal UserDetails userDetails,
@RequestParam(required = false, defaultValue = "0") int page,
ReportStatus reportStatus){
log.info("Report status : {}", reportStatus);
String email = userDetails.getUsername();
PagingReportInfo pagingReportInfo = reportService.getReportByStatus(email, reportStatus, page);
return ResponseEntity.status(HttpStatus.OK).body(new CommonResponseDto<>(
"성공적으로 " + reportStatus + "상태에 해당하는 신고를 조회하였습니다.",
pagingReportInfo
));
}

@Operation(summary = "신고 상태 변경", description = "관리자의 권한으로 신고 상태를 변경합니다.")
@PatchMapping("/admin/update/{reportId}")
public ResponseEntity<CommonResponseDto<ReportInfo>> changeReportStatus(
@PathVariable("reportId") Long reportId,
@AuthenticationPrincipal UserDetails userDetails,
ReportStatus reportStatus){
log.info("Report status : {}", reportStatus);
String email = userDetails.getUsername();
ReportInfo reportInfo = reportService.changeReportStatus(email,reportId,reportStatus);
return ResponseEntity.status(HttpStatus.OK).body(new CommonResponseDto<>(
"성공적으로 신고 상태를 변경하였습니다.",
reportInfo
));
}
@Operation(summary = "신고 처리", description = "신고의 상태에 따라서 신고를 처리합니다.")
@GetMapping("/admin/{targetId}")
public ResponseEntity<CommonResponseDto<String>> processReportByStatus(
@PathVariable Long targetId,
@AuthenticationPrincipal UserDetails userDetails,
@RequestParam int penaltyPoint

) {
String email = userDetails.getUsername();
String result = reportService.processReportByStatus(email,targetId,penaltyPoint);
return ResponseEntity.status(HttpStatus.OK).body(new CommonResponseDto<>(
"신고 처리를 성공적으로 완료하였습니다.",
result
));
}


}
55 changes: 55 additions & 0 deletions src/main/java/me/snaptime/report/domain/Report.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package me.snaptime.report.domain;

import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import me.snaptime.common.BaseTimeEntity;
import me.snaptime.report.domain.enums.ReportReason;
import me.snaptime.report.domain.enums.ReportStatus;
import me.snaptime.report.domain.enums.ReportType;
import me.snaptime.user.domain.User;

@Entity
@Table(name = "report")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class Report extends BaseTimeEntity {

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

@ManyToOne
@JoinColumn(name = "reporter_id", nullable = false)
private User reporter;

@Enumerated(EnumType.STRING)
@Column(nullable = false)
private ReportType reportType;

@Column(nullable = false)
private Long targetId;

@Enumerated(EnumType.STRING)
@Column(nullable = false)
private ReportReason reportReason;

@Enumerated(EnumType.STRING)
@Column(nullable = false)
private ReportStatus reportStatus;

@Builder
protected Report(User reporter, ReportType reportType, Long targetId, ReportReason reportReason, ReportStatus reportStatus){
this.reporter = reporter;
this.reportType = reportType;
this.targetId = targetId;
this.reportReason = reportReason;
this.reportStatus =reportStatus;
}

public void updateStatus(ReportStatus reportStatus){
this.reportStatus= reportStatus;
}
}
19 changes: 19 additions & 0 deletions src/main/java/me/snaptime/report/domain/enums/ReportReason.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package me.snaptime.report.domain.enums;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum ReportReason {
SPAM("스팸"),
INAPPROPRIATE_CONTENT("선정적 내용"),
HATE_SPEECH("혐오 발언"),
VIOLENCE("폭력"),
ILLEGAL_CONTENT("불법 내용"),
HARASSMENT("괴롭힘"),
COPYRIGHT_INFRINGEMENT("저작권 침해"),
MISINFORMATION("거짓 정보");

private final String description;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package me.snaptime.report.domain.enums;

public enum ReportStatus {
PENDING, UNDER_REVIEW, REJECTED, APPROVED
}
5 changes: 5 additions & 0 deletions src/main/java/me/snaptime/report/domain/enums/ReportType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package me.snaptime.report.domain.enums;

public enum ReportType {
SNAP, PARENT_REPLY, CHILD_REPLY
}
24 changes: 24 additions & 0 deletions src/main/java/me/snaptime/report/dto/PagingReportInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package me.snaptime.report.dto;

import lombok.Builder;

import java.util.List;

@Builder
public record PagingReportInfo(

List<ReportInfo> reportInfoList,
long totalPages,
boolean hasNextPage,
boolean hasPreviousPage
) {
public static PagingReportInfo of(List<ReportInfo> reportInfoList, long totalPages, boolean hasNextPage, boolean hasPreviousPage)
{
return PagingReportInfo.builder()
.reportInfoList(reportInfoList)
.totalPages(totalPages)
.hasNextPage(hasNextPage)
.hasPreviousPage(hasPreviousPage)
.build();
}
}
Loading