Skip to content

Commit

Permalink
✨ [FEATURE] 리뷰 신고 & 관리자 신고 조회 (#99)
Browse files Browse the repository at this point in the history
✨ [FEATURE] 리뷰 신고 & 관리자 신고 조회 (#99)
  • Loading branch information
gomin0 authored Aug 1, 2024
2 parents 7f83e18 + c42ff95 commit 6d1e715
Show file tree
Hide file tree
Showing 11 changed files with 263 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package umc.unimade.domain.review.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.web.bind.annotation.*;
import org.springframework.data.domain.Pageable;
import umc.unimade.domain.review.dto.ReviewReportResponse;
import umc.unimade.domain.review.dto.ReviewReportsResponse;
import umc.unimade.domain.review.service.ReviewReportQueryService;
import umc.unimade.global.common.ApiResponse;

@RestController
@RequestMapping("/admin/report")
@Tag(name = "Admin_report", description = "관리자-리뷰 신고 관련 API")
@RequiredArgsConstructor
public class AdminReviewController {

private final ReviewReportQueryService reviewReportQueryService;

// TODO: 신고 처리 여부에 따라 조회
@Operation(summary = "리뷰 신고 목록 조회", description = "유저 role이 관리자인 사람만 가능")
@GetMapping()
public ApiResponse<Page<ReviewReportsResponse>> getReports(
@RequestParam(name = "page", defaultValue = "0") int page,
@RequestParam(name = "size", defaultValue = "10") int size) {
Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createdAt"));
Page<ReviewReportsResponse> responses = reviewReportQueryService.getReports(pageable);
return ApiResponse.onSuccess(responses);
}

@Operation(summary = "리뷰 신고 개별 조회", description = "유저 role이 관리자인 사람만 가능")
@GetMapping("/{reviewReportId}")
public ApiResponse<ReviewReportResponse> getReport(@PathVariable Long reviewReportId) {
ReviewReportResponse response = reviewReportQueryService.getReport(reviewReportId);
return ApiResponse.onSuccess(response);
}

// TODO: 관리자의 신고 처리 추가
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,32 @@
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import umc.unimade.domain.accounts.entity.Buyer;
import umc.unimade.domain.accounts.repository.BuyerRepository;
import umc.unimade.domain.review.dto.ReviewReportRequest;
import umc.unimade.domain.review.dto.ReviewReportResponse;
import umc.unimade.domain.review.dto.ReviewCreateRequest;
import umc.unimade.domain.review.dto.ReviewResponse;
import umc.unimade.domain.review.service.ReviewCommandService;
import umc.unimade.domain.review.service.ReviewQueryService;
import umc.unimade.global.common.ApiResponse;
import umc.unimade.global.common.ErrorCode;
import umc.unimade.domain.accounts.exception.UserExceptionHandler;
import umc.unimade.global.security.UserId;

import java.util.List;

@RestController
@RequestMapping("/api/review")
@Tag(name = "Review", description = "리뷰 관련 API")
@RequiredArgsConstructor
public class ReviewController {
private final ReviewCommandService reviewCommandService;
private final ReviewQueryService reviewQueryService;
//임시로 추가
private final BuyerRepository buyerRepository;

@Tag(name = "Review", description = "리뷰 관련 API")
@Operation(summary = "리뷰 생성, buyerId는 나중에 뺄게요!")
@PostMapping(value = "/{productId}/{buyerId}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<ApiResponse<Void>> createReview(@PathVariable Long productId,
Expand All @@ -50,7 +50,6 @@ public ResponseEntity<ApiResponse<Void>> createReview(@PathVariable Long product
}
}

@Tag(name = "Review", description = "리뷰 관련 API")
@Operation(summary = "리뷰 상세 내용 불러오기 ")
@GetMapping("/{reviewId}")
//To do : user 토큰 추가
Expand All @@ -63,8 +62,8 @@ public ResponseEntity<ApiResponse<ReviewResponse>> getReview(@PathVariable Long
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ApiResponse.onFailure(ErrorCode.BUYER_NOT_FOUND.getCode(), ErrorCode.BUYER_NOT_FOUND.getMessage()));
}
}
@Tag(name = "Review", description = "리뷰 관련 API")
@Operation(summary = "리뷰 삭제하기, description = buyerId 나중에 뺄게요! ")

@Operation(summary = "리뷰 삭제하기", description = "buyerId 나중에 뺄게요! ")
@DeleteMapping("/{reviewId}/{buyerId}")
public ResponseEntity<ApiResponse<Void>> deleteReview(@PathVariable Long reviewId,
@PathVariable Long buyerId) {
Expand All @@ -79,13 +78,19 @@ public ResponseEntity<ApiResponse<Void>> deleteReview(@PathVariable Long reviewI
}
}



// 임시로 추가
private Buyer findBuyerById(Long buyerId) {
return buyerRepository.findById(buyerId)
.orElseThrow(() -> new UserExceptionHandler(ErrorCode.BUYER_NOT_FOUND));
}

// TODO: seller 받아 오기
@Operation(summary = "리뷰 신고하기", description = "seller가 자신의 상품에 달린 리뷰를 신고")
@PostMapping("/{reviewId}/report")
public ApiResponse<ReviewReportResponse> reportReview(@PathVariable Long reviewId, @RequestBody ReviewReportRequest request) {
ReviewReportResponse response = reviewCommandService.reportReview(reviewId, request);
return ApiResponse.onSuccess(response);
}
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package umc.unimade.domain.review.dto;

import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import umc.unimade.domain.accounts.entity.Seller;
import umc.unimade.domain.review.entity.ReportType;
import umc.unimade.domain.review.entity.Review;
import umc.unimade.domain.review.entity.ReviewReport;

@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ReviewReportRequest {

@NotNull
private ReportType type;
private String description;

public ReviewReport toEntity(Review review, Seller seller) {
return ReviewReport.builder()
.review(review)
.seller(seller)
.type(type)
.description(description)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package umc.unimade.domain.review.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import umc.unimade.domain.review.entity.ReportType;
import umc.unimade.domain.review.entity.Review;
import umc.unimade.domain.review.entity.ReviewReport;

@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ReviewReportResponse {

private Long reportId;
private Long reviewId;
private Long buyerId;
private Long sellerId;
private ReportType type;
private String reviewTitle;
private String reviewContent;
private String description;

public static ReviewReportResponse from(ReviewReport report) {
Review review = report.getReview();
return ReviewReportResponse.builder()
.reportId(report.getId())
.reviewId(review.getId())
.buyerId(review.getBuyer().getId())
.sellerId(report.getSeller().getId())
.type(report.getType())
.reviewTitle(review.getTitle())
.reviewContent(review.getContent())
.description(report.getDescription())
.build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package umc.unimade.domain.review.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import umc.unimade.domain.review.entity.Review;
import umc.unimade.domain.review.entity.ReviewReport;

@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ReviewReportsResponse {

private Long reportId;
private Long reviewId;
private String reviewTitle;

public static ReviewReportsResponse from(ReviewReport report) {
Review review = report.getReview();
return ReviewReportsResponse.builder()
.reportId(report.getId())
.reviewId(review.getId())
.reviewTitle(review.getTitle())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package umc.unimade.domain.review.entity;

public enum ReportType {
OPTION_1,
OPTION_2,
OPTION_3,
ECT
}
34 changes: 34 additions & 0 deletions src/main/java/umc/unimade/domain/review/entity/ReviewReport.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package umc.unimade.domain.review.entity;

import jakarta.persistence.*;
import lombok.*;
import umc.unimade.domain.accounts.entity.Seller;
import umc.unimade.global.common.BaseEntity;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Builder
@Table(name = "review_report")
public class ReviewReport extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "review_report_id", nullable = false)
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "review_id", nullable = false)
private Review review;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "seller_id", nullable = false)
private Seller seller;

@Enumerated(EnumType.STRING)
@Column(name = "type", nullable = false)
private ReportType type;

@Column(name = "description")
private String description;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package umc.unimade.domain.review.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import umc.unimade.domain.review.entity.ReviewReport;

public interface ReviewReportRepository extends JpaRepository<ReviewReport, Long> {
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,16 @@
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import umc.unimade.domain.accounts.entity.Buyer;
import umc.unimade.domain.accounts.entity.Seller;
import umc.unimade.domain.accounts.exception.SellerExceptionHandler;
import umc.unimade.domain.accounts.repository.SellerRepository;
import umc.unimade.domain.products.repository.ProductRepository;
import umc.unimade.domain.products.entity.Products;
import umc.unimade.domain.review.dto.ReviewReportRequest;
import umc.unimade.domain.review.dto.ReviewReportResponse;
import umc.unimade.domain.review.entity.ReviewReport;
import umc.unimade.domain.review.exception.ReviewExceptionHandler;
import umc.unimade.domain.review.repository.ReviewReportRepository;
import umc.unimade.domain.review.repository.ReviewRepository;
import umc.unimade.domain.review.dto.ReviewCreateRequest;
import umc.unimade.domain.review.entity.Review;
Expand All @@ -24,6 +31,8 @@ public class ReviewCommandService {
private final ReviewRepository reviewRepository;
private final ProductRepository productRepository;
private final S3Provider s3Provider;
private final SellerRepository sellerRepository;
private final ReviewReportRepository reviewReportRepository;

@Transactional
public void createReview(Long productId, Buyer buyer, ReviewCreateRequest reviewCreateRequest, List<MultipartFile> images) {
Expand Down Expand Up @@ -57,4 +66,21 @@ private Review findReviewById(Long reviewId){
return reviewRepository.findById(reviewId)
.orElseThrow(() -> new ReviewExceptionHandler(ErrorCode.REVIEW_NOT_FOUND));
}

@Transactional
public ReviewReportResponse reportReview(Long reviewId, ReviewReportRequest request) {

Review review = reviewRepository.findById(reviewId)
.orElseThrow(() -> new ReviewExceptionHandler(ErrorCode.REVIEW_NOT_FOUND));

// TODO: 컨트롤러에서 seller 받아오기
Seller seller = sellerRepository.findById(1L)
.orElseThrow(() -> new SellerExceptionHandler(ErrorCode.SELLER_NOT_FOUND));


ReviewReport report = request.toEntity(review, seller);
reviewReportRepository.save(report);

return ReviewReportResponse.from(report);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package umc.unimade.domain.review.service;

import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import umc.unimade.domain.review.dto.ReviewReportResponse;
import umc.unimade.domain.review.dto.ReviewReportsResponse;
import umc.unimade.domain.review.entity.ReviewReport;
import umc.unimade.domain.review.exception.ReviewExceptionHandler;
import umc.unimade.domain.review.repository.ReviewReportRepository;
import umc.unimade.global.common.ErrorCode;

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class ReviewReportQueryService {

private final ReviewReportRepository reviewReportRepository;

public Page<ReviewReportsResponse> getReports(Pageable pageable) {
Page<ReviewReport> reports = reviewReportRepository.findAll(pageable);
return reports.map(ReviewReportsResponse::from);
}

public ReviewReportResponse getReport(Long reviewReportId) {
ReviewReport report = reviewReportRepository.findById(reviewReportId)
.orElseThrow(() -> new ReviewExceptionHandler(ErrorCode.REPORT_NOT_FOUND));
return ReviewReportResponse.from(report);
}
}
1 change: 1 addition & 0 deletions src/main/java/umc/unimade/global/common/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public enum ErrorCode implements BaseErrorCode {
REVIEW_NOT_FOUND(HttpStatus.NOT_FOUND, "REVIEW4000", "리뷰를 찾을 수 없습니다."),
INVALID_RATING_STAR(HttpStatus.BAD_REQUEST, "REVIEW4001", "별점은 0점 이상이어야합니다"),
REVIEW_DELETE_NOT_OWNER(HttpStatus.FORBIDDEN,"REVIEW4003","리뷰를 삭제할 권한이 없습니다."),
REPORT_NOT_FOUND(HttpStatus.NOT_FOUND, "REVIEW4004", "리뷰 신고를 찾을 수 없습니다."),


// QnA 관련 에러
Expand Down

0 comments on commit 6d1e715

Please sign in to comment.