From 0719b3042a6ea828c8497bbdc1faf88083d1778b Mon Sep 17 00:00:00 2001 From: dldmsql Date: Sat, 6 Jan 2024 23:56:59 +0900 Subject: [PATCH 01/23] =?UTF-8?q?feat:=20=EC=8B=9D=EB=8B=B9=20=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=20=EC=8B=A0=EA=B3=A0=ED=95=98=EA=B8=B0=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/exception/ExceptionList.java | 32 +++-- .../report/controller/ReportController.java | 55 ++++++++ .../server/report/dto/ReportDto.java | 16 +++ .../server/report/entity/Report.java | 48 +++++++ .../server/report/entity/ReportReason.java | 20 +++ .../report/repository/ReportRepository.java | 17 +++ .../report/service/ReportCommServiceImpl.java | 26 ++++ .../server/report/service/ReportService.java | 9 ++ .../report/service/ReportServiceImpl.java | 53 +++++++ .../server/review/entity/Review.java | 4 + .../review/service/ReviewCommServiceImpl.java | 72 ++++++++++ .../review/service/ReviewServiceImpl.java | 52 ++++--- .../everymeal/server/user/entity/User.java | 4 + .../user/service/UserCommServiceImpl.java | 50 +++++++ .../server/user/service/UserServiceImpl.java | 40 +++--- .../user/service/WithdrawalServiceImpl.java | 21 +++ .../server/global/ControllerTestSupport.java | 7 +- .../controller/ReportControllerTest.java | 53 +++++++ .../report/service/ReportServiceImplTest.java | 131 ++++++++++++++++++ 19 files changed, 644 insertions(+), 66 deletions(-) create mode 100644 src/main/java/everymeal/server/report/controller/ReportController.java create mode 100644 src/main/java/everymeal/server/report/dto/ReportDto.java create mode 100644 src/main/java/everymeal/server/report/entity/Report.java create mode 100644 src/main/java/everymeal/server/report/entity/ReportReason.java create mode 100644 src/main/java/everymeal/server/report/repository/ReportRepository.java create mode 100644 src/main/java/everymeal/server/report/service/ReportCommServiceImpl.java create mode 100644 src/main/java/everymeal/server/report/service/ReportService.java create mode 100644 src/main/java/everymeal/server/report/service/ReportServiceImpl.java create mode 100644 src/main/java/everymeal/server/review/service/ReviewCommServiceImpl.java create mode 100644 src/main/java/everymeal/server/user/service/UserCommServiceImpl.java create mode 100644 src/main/java/everymeal/server/user/service/WithdrawalServiceImpl.java create mode 100644 src/test/java/everymeal/server/report/controller/ReportControllerTest.java create mode 100644 src/test/java/everymeal/server/report/service/ReportServiceImplTest.java diff --git a/src/main/java/everymeal/server/global/exception/ExceptionList.java b/src/main/java/everymeal/server/global/exception/ExceptionList.java index 91efef9..bc15ffa 100644 --- a/src/main/java/everymeal/server/global/exception/ExceptionList.java +++ b/src/main/java/everymeal/server/global/exception/ExceptionList.java @@ -8,27 +8,33 @@ @Getter @RequiredArgsConstructor public enum ExceptionList { - MEAL_NOT_FOUND("M0001", HttpStatus.NOT_FOUND, "Meal Not Found"), - RESTAURANT_NOT_FOUND("M0002", HttpStatus.NOT_FOUND, "등록된 식당이 아닙니다."), - UNIVERSITY_NOT_FOUND("M0003", HttpStatus.NOT_FOUND, "등록된 학교가 아닙니다."), + MEAL_NOT_FOUND("MEL0001", HttpStatus.NOT_FOUND, "Meal Not Found"), + RESTAURANT_NOT_FOUND("MEL0002", HttpStatus.NOT_FOUND, "등록된 식당이 아닙니다."), + UNIVERSITY_NOT_FOUND("MEL0003", HttpStatus.NOT_FOUND, "등록된 학교가 아닙니다."), INVALID_MEAL_OFFEREDAT_REQUEST( - "M0004", HttpStatus.BAD_REQUEST, "동일한 데이터를 갖는 식단 데이터가 이미 존재합니다."), - INVALID_REQUEST("R0001", HttpStatus.BAD_REQUEST, "Request의 Data Type이 올바르지 않습니다."), + "MEL0004", HttpStatus.BAD_REQUEST, "동일한 데이터를 갖는 식단 데이터가 이미 존재합니다."), + INVALID_REQUEST("COM0001", HttpStatus.BAD_REQUEST, "Request의 Data Type이 올바르지 않습니다."), - USER_NOT_FOUND("U0001", HttpStatus.NOT_FOUND, "등록된 유저가 아닙니다."), - USER_AUTH_TIME_OUT("U0002", HttpStatus.FORBIDDEN, "인증 시간이 만료되었습니다."), - USER_AUTH_FAIL("U0003", HttpStatus.FORBIDDEN, "인증에 실패하였습니다."), - USER_ALREADY_EXIST("U0004", HttpStatus.CONFLICT, "이미 등록된 이메일입니다."), - NICKNAME_ALREADY_EXIST("U0005", HttpStatus.CONFLICT, "이미 등록된 닉네임입니다."), + USER_NOT_FOUND("USR0001", HttpStatus.NOT_FOUND, "등록된 유저가 아닙니다."), + USER_AUTH_TIME_OUT("USR0002", HttpStatus.FORBIDDEN, "인증 시간이 만료되었습니다."), + USER_AUTH_FAIL("USR0003", HttpStatus.FORBIDDEN, "인증에 실패하였습니다."), + USER_ALREADY_EXIST("USR0004", HttpStatus.CONFLICT, "이미 등록된 이메일입니다."), + NICKNAME_ALREADY_EXIST("USR0005", HttpStatus.CONFLICT, "이미 등록된 닉네임입니다."), - TOKEN_NOT_VALID("T0001", HttpStatus.NOT_ACCEPTABLE, "해당 토큰은 유효하지 않습니다."), - TOKEN_EXPIRATION("T0002", HttpStatus.FORBIDDEN, "토큰이 만료되었습니다."), + TOKEN_NOT_VALID("TKN0001", HttpStatus.NOT_ACCEPTABLE, "해당 토큰은 유효하지 않습니다."), + TOKEN_EXPIRATION("TKN0002", HttpStatus.FORBIDDEN, "토큰이 만료되었습니다."), REVIEW_NOT_FOUND("RV0001", HttpStatus.NOT_FOUND, "등록된 리뷰가 아닙니다."), REVIEW_UNAUTHORIZED("RV0002", HttpStatus.FORBIDDEN, "해당 리뷰에 대한 권한이 없습니다."), REVIEW_ALREADY_MARKED("RV0003", HttpStatus.CONFLICT, "이미 해당 리뷰에 대한 평가를 하였습니다."), REVIEW_MARK_NOT_FOUND("RV0004", HttpStatus.NOT_FOUND, "등록된 리뷰 평가가 아닙니다."), - STORE_NOT_FOUND("S0001", HttpStatus.NOT_FOUND, "등록된 가게가 아닙니다."), + STORE_NOT_FOUND("STR0001", HttpStatus.NOT_FOUND, "등록된 가게가 아닙니다."), + + // report + REPORT_NOT_FOUND("RPT0001", HttpStatus.NOT_FOUND, "등록된 신고가 아닙니다."), + REPORT_ALREADY_EXIST("RPT0002", HttpStatus.CONFLICT, "이미 신고한 리뷰입니다."), + REPORT_REVIEW_SELF("RPT0003", HttpStatus.FORBIDDEN, "자신의 리뷰를 신고할 수 없습니다."), + REPORT_REVIEW_ALREADY("RPT0004", HttpStatus.CONFLICT, "이미 신고한 리뷰입니다."), ; public final String CODE; diff --git a/src/main/java/everymeal/server/report/controller/ReportController.java b/src/main/java/everymeal/server/report/controller/ReportController.java new file mode 100644 index 0000000..247b325 --- /dev/null +++ b/src/main/java/everymeal/server/report/controller/ReportController.java @@ -0,0 +1,55 @@ +package everymeal.server.report.controller; + + +import everymeal.server.global.dto.response.ApplicationResponse; +import everymeal.server.global.util.authresolver.Auth; +import everymeal.server.global.util.authresolver.AuthUser; +import everymeal.server.global.util.authresolver.entity.AuthenticatedUser; +import everymeal.server.report.dto.ReportDto; +import everymeal.server.report.service.ReportService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PathVariable; +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; + +@RequestMapping("/api/v1/reports") +@RequiredArgsConstructor +@RestController +public class ReportController { + + private final ReportService reportService; + + @PostMapping("/review/{reviewIdx}") + @Operation( + summary = "리뷰 신고", + description = + """ + 리뷰 신고를 진행합니다.
+ 로그인이 필요한 기능입니다. + """) + @ApiResponses({ + @ApiResponse( + responseCode = "200", + description = "리뷰 신고 성공", + content = @Content(schema = @Schema())), + }) + @Auth(require = true) + @SecurityRequirement(name = "jwt-user-auth") + public ApplicationResponse reportReview( + @Schema(description = "리뷰 아이디") @PathVariable Long reviewIdx, + @Schema(description = "리뷰 신고 사유") @RequestBody @Valid ReportDto.ReportReviewReq request, + @Parameter(hidden = true) @AuthUser AuthenticatedUser user) { + return ApplicationResponse.ok( + reportService.reportReview(reviewIdx, request, user.getIdx())); + } +} diff --git a/src/main/java/everymeal/server/report/dto/ReportDto.java b/src/main/java/everymeal/server/report/dto/ReportDto.java new file mode 100644 index 0000000..bebf2cb --- /dev/null +++ b/src/main/java/everymeal/server/report/dto/ReportDto.java @@ -0,0 +1,16 @@ +package everymeal.server.report.dto; + + +import everymeal.server.report.entity.ReportReason; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; + +public class ReportDto { + + public record ReportReviewReq( + @Schema( + description = "리뷰 신고 사유를 입력해주세요.", + allowableValues = {"UNRELATED", "PORNOGRAPHY", "PROFANITY"}) + @NotNull + ReportReason reason) {} +} diff --git a/src/main/java/everymeal/server/report/entity/Report.java b/src/main/java/everymeal/server/report/entity/Report.java new file mode 100644 index 0000000..480b5f5 --- /dev/null +++ b/src/main/java/everymeal/server/report/entity/Report.java @@ -0,0 +1,48 @@ +package everymeal.server.report.entity; + + +import everymeal.server.global.entity.BaseEntity; +import everymeal.server.review.entity.Review; +import everymeal.server.user.entity.User; +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.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Entity(name = "reports") +@Table +@NoArgsConstructor +public class Report extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long idx; + + @Enumerated(value = EnumType.STRING) + private ReportReason reason; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "reporter_idx") + private User reporter; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "review_idx") + private Review review; + + @Builder + public Report(ReportReason reason, User reporter, Review review) { + this.reason = reason; + this.reporter = reporter; + this.review = review; + } +} diff --git a/src/main/java/everymeal/server/report/entity/ReportReason.java b/src/main/java/everymeal/server/report/entity/ReportReason.java new file mode 100644 index 0000000..ee5f0c9 --- /dev/null +++ b/src/main/java/everymeal/server/report/entity/ReportReason.java @@ -0,0 +1,20 @@ +package everymeal.server.report.entity; + + +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +public enum ReportReason { + UNRELATED("해당 식당과 무관한 리뷰"), + PROFANITY("비속어 및 혐오 발언"), + PORNOGRAPHY("음란성 게시물"), + ETC("기타"); + + private String value; + + ReportReason(String value) { + this.value = value; + } +} diff --git a/src/main/java/everymeal/server/report/repository/ReportRepository.java b/src/main/java/everymeal/server/report/repository/ReportRepository.java new file mode 100644 index 0000000..b11fe72 --- /dev/null +++ b/src/main/java/everymeal/server/report/repository/ReportRepository.java @@ -0,0 +1,17 @@ +package everymeal.server.report.repository; + + +import everymeal.server.report.entity.Report; +import java.util.Optional; +import org.apache.ibatis.annotations.Param; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +public interface ReportRepository extends JpaRepository { + + @Query( + value = + "select r from reports r where r.review.idx = :reviewIdx and r.reporter.idx = :userIdx") + Optional findByReviewIdxAndUserIdx( + @Param("reviewIdx") Long reviewIdx, @Param("userIdx") Long userIdx); +} diff --git a/src/main/java/everymeal/server/report/service/ReportCommServiceImpl.java b/src/main/java/everymeal/server/report/service/ReportCommServiceImpl.java new file mode 100644 index 0000000..84b748e --- /dev/null +++ b/src/main/java/everymeal/server/report/service/ReportCommServiceImpl.java @@ -0,0 +1,26 @@ +package everymeal.server.report.service; + + +import everymeal.server.report.entity.Report; +import everymeal.server.report.repository.ReportRepository; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class ReportCommServiceImpl { + + private final ReportRepository reportRepository; + + @Transactional + public Report save(Report report) { + return reportRepository.save(report); + } + + public Optional getReportOptionalEntity(Long reviewIdx, Long userIdx) { + return reportRepository.findByReviewIdxAndUserIdx(reviewIdx, userIdx); + } +} diff --git a/src/main/java/everymeal/server/report/service/ReportService.java b/src/main/java/everymeal/server/report/service/ReportService.java new file mode 100644 index 0000000..8bbc776 --- /dev/null +++ b/src/main/java/everymeal/server/report/service/ReportService.java @@ -0,0 +1,9 @@ +package everymeal.server.report.service; + + +import everymeal.server.report.dto.ReportDto.ReportReviewReq; + +public interface ReportService { + + Boolean reportReview(Long reviewIdx, ReportReviewReq request, Long userIdx); +} diff --git a/src/main/java/everymeal/server/report/service/ReportServiceImpl.java b/src/main/java/everymeal/server/report/service/ReportServiceImpl.java new file mode 100644 index 0000000..d5ac0f4 --- /dev/null +++ b/src/main/java/everymeal/server/report/service/ReportServiceImpl.java @@ -0,0 +1,53 @@ +package everymeal.server.report.service; + + +import everymeal.server.global.exception.ApplicationException; +import everymeal.server.global.exception.ExceptionList; +import everymeal.server.report.dto.ReportDto.ReportReviewReq; +import everymeal.server.report.entity.Report; +import everymeal.server.review.entity.Review; +import everymeal.server.review.service.ReviewCommServiceImpl; +import everymeal.server.user.entity.User; +import everymeal.server.user.service.UserCommServiceImpl; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class ReportServiceImpl implements ReportService { + + private final ReviewCommServiceImpl reviewCommServiceImpl; + private final UserCommServiceImpl userCommServiceImpl; + private final ReportCommServiceImpl reportCommServiceImpl; + + @Override + @Transactional + public Boolean reportReview(Long reviewIdx, ReportReviewReq request, Long userIdx) { + // 리뷰 조회 + Review review = reviewCommServiceImpl.getReviewEntity(reviewIdx); + // 신고 유저 조회 + User reportUser = userCommServiceImpl.getUserEntity(userIdx); + // 리뷰 작성 유저 조회 + User reviewUser = review.getUser(); + // 리뷰 작성 유저와 신고 유저가 같은지 확인 + if (reviewUser.equals(reportUser)) { + throw new ApplicationException(ExceptionList.REPORT_REVIEW_SELF); + } + // 리뷰 신고 여부 확인 + if (reportCommServiceImpl.getReportOptionalEntity(reviewIdx, userIdx).isPresent()) { + throw new ApplicationException(ExceptionList.REPORT_REVIEW_ALREADY); + } + // 리뷰 신고 저장 + Report report = + Report.builder() + .reporter(reportUser) + .review(review) + .reason(request.reason()) + .build(); + reportCommServiceImpl.save(report); + + return true; + } +} diff --git a/src/main/java/everymeal/server/review/entity/Review.java b/src/main/java/everymeal/server/review/entity/Review.java index cb4e994..c0bbf49 100644 --- a/src/main/java/everymeal/server/review/entity/Review.java +++ b/src/main/java/everymeal/server/review/entity/Review.java @@ -3,6 +3,7 @@ import everymeal.server.global.entity.BaseEntity; import everymeal.server.meal.entity.Restaurant; +import everymeal.server.report.entity.Report; import everymeal.server.store.entity.Store; import everymeal.server.user.entity.User; import jakarta.persistence.CascadeType; @@ -65,6 +66,9 @@ public class Review extends BaseEntity { @JoinColumn(name = "review_idx") private List images = new ArrayList<>(); + @OneToMany(cascade = CascadeType.ALL) + private Set reports = new HashSet<>(); + @Builder public Review( String content, diff --git a/src/main/java/everymeal/server/review/service/ReviewCommServiceImpl.java b/src/main/java/everymeal/server/review/service/ReviewCommServiceImpl.java new file mode 100644 index 0000000..fcb3dd0 --- /dev/null +++ b/src/main/java/everymeal/server/review/service/ReviewCommServiceImpl.java @@ -0,0 +1,72 @@ +package everymeal.server.review.service; + + +import everymeal.server.global.exception.ApplicationException; +import everymeal.server.global.exception.ExceptionList; +import everymeal.server.review.dto.response.ReviewDto; +import everymeal.server.review.dto.response.ReviewDto.ReviewPagingVOWithCnt; +import everymeal.server.review.entity.Review; +import everymeal.server.review.entity.ReviewMark; +import everymeal.server.review.repository.ReviewMapper; +import everymeal.server.review.repository.ReviewMarkRepository; +import everymeal.server.review.repository.ReviewRepository; +import everymeal.server.user.entity.User; +import java.util.Map; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class ReviewCommServiceImpl { + + private final ReviewRepository reviewRepository; + private final ReviewMarkRepository reviewMarkRepository; + private final ReviewMapper reviewMapper; + + @Transactional + public Review save(Review review) { + return reviewRepository.save(review); + } + + public Review getReviewEntity(Long reviewIdx) { + return reviewRepository + .findById(reviewIdx) + .orElseThrow(() -> new ApplicationException(ExceptionList.REVIEW_NOT_FOUND)); + } + + public Review getReviewEntity(Long reviewIdx, User user) { + return reviewRepository + .findByIdxAndUser(reviewIdx, user) + .orElseThrow(() -> new ApplicationException(ExceptionList.REVIEW_NOT_FOUND)); + } + + public Optional getReviewOptionalEntity(Long reviewIdx) { + return reviewRepository.findById(reviewIdx); + } + + public ReviewPagingVOWithCnt getReviewPagingVOWithCnt(ReviewDto.ReviewQueryParam queryParam) { + return reviewRepository.getReview(queryParam); + } + + public Optional getReviewMarkOptionalEntity(Long reviewIdx, Long userIdx) { + return reviewMarkRepository.findByReviewIdxAndUserIdx(reviewIdx, userIdx); + } + + @Transactional + public void deleteReviewMark(ReviewMark reviewMark) { + reviewMarkRepository.delete(reviewMark); + } + + public Map getTodayReviewEntityFromMapper( + Long restaurantIdx, String offeredAt) { + return reviewMapper.findTodayReview(restaurantIdx, offeredAt); + } + + @Transactional + public Review saveAndFlush(Review review) { + return reviewRepository.saveAndFlush(review); + } +} diff --git a/src/main/java/everymeal/server/review/service/ReviewServiceImpl.java b/src/main/java/everymeal/server/review/service/ReviewServiceImpl.java index d3c4391..1318dd8 100644 --- a/src/main/java/everymeal/server/review/service/ReviewServiceImpl.java +++ b/src/main/java/everymeal/server/review/service/ReviewServiceImpl.java @@ -3,7 +3,6 @@ import static everymeal.server.global.exception.ExceptionList.RESTAURANT_NOT_FOUND; import static everymeal.server.global.exception.ExceptionList.REVIEW_ALREADY_MARKED; import static everymeal.server.global.exception.ExceptionList.REVIEW_MARK_NOT_FOUND; -import static everymeal.server.global.exception.ExceptionList.REVIEW_NOT_FOUND; import static everymeal.server.global.exception.ExceptionList.REVIEW_UNAUTHORIZED; import static everymeal.server.global.exception.ExceptionList.USER_NOT_FOUND; @@ -18,9 +17,6 @@ import everymeal.server.review.dto.response.ReviewDto.ReviewTodayGetRes; import everymeal.server.review.entity.Image; import everymeal.server.review.entity.Review; -import everymeal.server.review.repository.ReviewMapper; -import everymeal.server.review.repository.ReviewMarkRepository; -import everymeal.server.review.repository.ReviewRepository; import everymeal.server.user.entity.User; import everymeal.server.user.repository.UserRepository; import java.util.ArrayList; @@ -37,12 +33,10 @@ public class ReviewServiceImpl implements ReviewService { private final RestaurantRepository restaurantRepository; - private final ReviewRepository reviewRepository; private final UserRepository userRepository; private final Logger logger = LoggerFactory.getLogger(ReviewServiceImpl.class); - private final ReviewMarkRepository reviewMarkRepository; - private final ReviewMapper reviewMapper; + private final ReviewCommServiceImpl reviewCommServiceImpl; @Override @Transactional @@ -80,7 +74,7 @@ public Long createReview(ReviewCreateReq request, Long userIdx) { review.updateTodayReview(true); } // (4) 저장 - Review savedReview = reviewRepository.save(review); + Review savedReview = reviewCommServiceImpl.save(review); restaurant.addGrade(request.grade()); return savedReview.getIdx(); @@ -90,10 +84,8 @@ public Long createReview(ReviewCreateReq request, Long userIdx) { @Transactional public Long updateReview(ReviewCreateReq request, Long userIdx, Long reviewIdx) { // (1) 기존 리뷰 조회 - Review review = - reviewRepository - .findById(reviewIdx) - .orElseThrow(() -> new ApplicationException(REVIEW_NOT_FOUND)); + Review review = reviewCommServiceImpl.getReviewEntity(reviewIdx); + // (2) 이미지 주소 <> 이미지 객체 치환 List imageList = getImageFromString(request.imageList()); User user = @@ -119,18 +111,24 @@ public Boolean deleteReview(Long userIdx, Long reviewIdx) { userRepository .findById(userIdx) .orElseThrow(() -> new ApplicationException(USER_NOT_FOUND)); - Review review = - reviewRepository - .findByIdxAndUser(reviewIdx, user) - .orElseThrow(() -> new ApplicationException(REVIEW_NOT_FOUND)); + Review review = reviewCommServiceImpl.getReviewEntity(reviewIdx, user); // (2) 기존 데이터 삭제 review.getRestaurant().removeGrade(review.getGrade()); review.deleteEntity(); + + reviewCommServiceImpl + .getReviewMarkOptionalEntity(reviewIdx, userIdx) + .ifPresent( + reviewMark -> { + review.removeMark(user); + reviewCommServiceImpl.deleteReviewMark(reviewMark); + }); + return true; } public ReviewGetRes getReviewWithNoOffSetPaging(ReviewDto.ReviewQueryParam queryParam) { - var result = reviewRepository.getReview(queryParam); + var result = reviewCommServiceImpl.getReviewPagingVOWithCnt(queryParam); List reviewPagingList = new ArrayList<>(); for (Review vo : result.reviewList()) { List strImgList = new ArrayList<>(); @@ -156,33 +154,30 @@ public ReviewGetRes getReviewWithNoOffSetPaging(ReviewDto.ReviewQueryParam query @Transactional public Boolean markReview(Long reviewIdx, boolean isLike, Long userIdx) { // (1) 기존 리뷰 조회 - Review review = - reviewRepository - .findById(reviewIdx) - .orElseThrow(() -> new ApplicationException(REVIEW_NOT_FOUND)); + Review review = reviewCommServiceImpl.getReviewEntity(reviewIdx); User user = userRepository .findById(userIdx) .orElseThrow(() -> new ApplicationException(USER_NOT_FOUND)); // (2) 기존 데이터 수정 if (isLike) { - reviewMarkRepository - .findByReviewIdxAndUserIdx(reviewIdx, userIdx) + reviewCommServiceImpl + .getReviewMarkOptionalEntity(reviewIdx, userIdx) .ifPresentOrElse( reviewMark -> { throw new ApplicationException(REVIEW_ALREADY_MARKED); }, () -> { review.addMark(user); - reviewRepository.saveAndFlush(review); + reviewCommServiceImpl.saveAndFlush(review); }); } else { - reviewMarkRepository - .findByReviewIdxAndUserIdx(reviewIdx, userIdx) + reviewCommServiceImpl + .getReviewMarkOptionalEntity(reviewIdx, userIdx) .ifPresentOrElse( reviewMark -> { review.removeMark(user); - reviewMarkRepository.delete(reviewMark); + reviewCommServiceImpl.deleteReviewMark(reviewMark); }, () -> { throw new ApplicationException(REVIEW_MARK_NOT_FOUND); @@ -193,7 +188,8 @@ public Boolean markReview(Long reviewIdx, boolean isLike, Long userIdx) { @Override public ReviewTodayGetRes getTodayReview(Long restaurantIdx, String offeredAt) { - return ReviewDto.of(reviewMapper.findTodayReview(restaurantIdx, offeredAt)); + return ReviewDto.of( + reviewCommServiceImpl.getTodayReviewEntityFromMapper(restaurantIdx, offeredAt)); } /** diff --git a/src/main/java/everymeal/server/user/entity/User.java b/src/main/java/everymeal/server/user/entity/User.java index d80c62e..a0310ab 100644 --- a/src/main/java/everymeal/server/user/entity/User.java +++ b/src/main/java/everymeal/server/user/entity/User.java @@ -2,6 +2,7 @@ import everymeal.server.global.entity.BaseEntity; +import everymeal.server.report.entity.Report; import everymeal.server.review.entity.Review; import everymeal.server.review.entity.ReviewMark; import everymeal.server.university.entity.University; @@ -57,6 +58,9 @@ public class User extends BaseEntity { @OneToOne(mappedBy = "user") private Withdrawal withdrawal; + @OneToMany(mappedBy = "reporter") + private Set reports = new HashSet<>(); + @Builder public User(String nickname, String email, String profileImgUrl, University university) { this.nickname = nickname; diff --git a/src/main/java/everymeal/server/user/service/UserCommServiceImpl.java b/src/main/java/everymeal/server/user/service/UserCommServiceImpl.java new file mode 100644 index 0000000..ff80de0 --- /dev/null +++ b/src/main/java/everymeal/server/user/service/UserCommServiceImpl.java @@ -0,0 +1,50 @@ +package everymeal.server.user.service; + + +import everymeal.server.global.exception.ApplicationException; +import everymeal.server.global.exception.ExceptionList; +import everymeal.server.user.entity.User; +import everymeal.server.user.repository.UserRepository; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class UserCommServiceImpl { + + private final UserRepository userRepository; + + public User getUserEntity(Long userIdx) { + return userRepository + .findById(userIdx) + .orElseThrow(() -> new ApplicationException(ExceptionList.USER_NOT_FOUND)); + } + + public Optional getUserOptionalEntityByEmail(String email) { + return userRepository.findByEmail(email); + } + + public User getUserEntityByEmail(String email) { + return userRepository + .findByEmail(email) + .orElseThrow(() -> new ApplicationException(ExceptionList.USER_NOT_FOUND)); + } + + public Optional getUserOptionalEntityByNickname(String nickname) { + return userRepository.findByNickname(nickname); + } + + public User getUserEntityByNickname(String nickname) { + return userRepository + .findByNickname(nickname) + .orElseThrow(() -> new ApplicationException(ExceptionList.USER_NOT_FOUND)); + } + + @Transactional + public User save(User user) { + return userRepository.save(user); + } +} diff --git a/src/main/java/everymeal/server/user/service/UserServiceImpl.java b/src/main/java/everymeal/server/user/service/UserServiceImpl.java index 6f97fe9..7cc71ed 100644 --- a/src/main/java/everymeal/server/user/service/UserServiceImpl.java +++ b/src/main/java/everymeal/server/user/service/UserServiceImpl.java @@ -21,8 +21,6 @@ import everymeal.server.user.entity.Withdrawal; import everymeal.server.user.entity.WithdrawalReason; import everymeal.server.user.repository.UserMapper; -import everymeal.server.user.repository.UserRepository; -import everymeal.server.user.repository.WithdrawalRepository; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Map; @@ -38,12 +36,13 @@ public class UserServiceImpl implements UserService { private final UniversityRepository universityRepository; - private final UserRepository userRepository; private final JwtUtil jwtUtil; private final MailUtil mailUtil; private final S3Util s3Util; private final UserMapper userMapper; - private final WithdrawalRepository withdrawalRepository; + private final WithdrawalServiceImpl withdrawalServiceImpl; + + private final UserCommServiceImpl userCommServiceImpl; @Override @Transactional @@ -53,10 +52,10 @@ public UserLoginRes signUp(UserEmailSingReq request) { throw new ApplicationException(ExceptionList.USER_AUTH_FAIL); } String email = jwtUtil.getEmailTokenFromEmail(request.emailAuthToken()); - if (userRepository.findByEmail(email).isPresent()) { + if (userCommServiceImpl.getUserOptionalEntityByEmail(email).isPresent()) { throw new ApplicationException(ExceptionList.USER_ALREADY_EXIST); } - if (userRepository.findByNickname(request.nickname()).isPresent()) { + if (userCommServiceImpl.getUserOptionalEntityByNickname(request.nickname()).isPresent()) { throw new ApplicationException(ExceptionList.NICKNAME_ALREADY_EXIST); } @@ -72,7 +71,7 @@ public UserLoginRes signUp(UserEmailSingReq request) { .profileImgUrl(request.profileImgKey()) .university(university) .build(); - userRepository.save(user); + userCommServiceImpl.save(user); String accessToken = jwtUtil.generateAccessToken(user.getIdx()); String refreshToken = jwtUtil.generateRefreshToken(user.getIdx(), accessToken); @@ -90,10 +89,7 @@ public UserLoginRes login(UserEmailLoginReq request) { throw new ApplicationException(ExceptionList.USER_AUTH_FAIL); } String email = jwtUtil.getEmailTokenFromEmail(request.emailAuthToken()); - User user = - userRepository - .findByEmail(email) - .orElseThrow(() -> new ApplicationException(ExceptionList.USER_NOT_FOUND)); + User user = userCommServiceImpl.getUserEntityByEmail(email); String accessToken = jwtUtil.generateAccessToken(user.getIdx()); String refreshToken = jwtUtil.generateRefreshToken(user.getIdx(), accessToken); return new UserLoginRes( @@ -154,7 +150,7 @@ public Boolean verifyEmailAuth(String emailAuthToken, String emailAuthValue) { @Override public Boolean checkUser(String email) { - return userRepository.findByEmail(email).isPresent(); + return userCommServiceImpl.getUserOptionalEntityByEmail(email).isPresent(); } @Override @@ -168,12 +164,10 @@ public UserProfileRes getUserProfile(AuthenticatedUser authenticatedUser) { @Transactional public Boolean updateUserProfile( AuthenticatedUser authenticatedUser, UserProfileUpdateReq request) { - User user = - userRepository - .findById(authenticatedUser.getIdx()) - .orElseThrow(() -> new ApplicationException(ExceptionList.USER_NOT_FOUND)); + User user = userCommServiceImpl.getUserEntity(authenticatedUser.getIdx()); // 닉네임 중복 검사 - Optional duplicatedNickName = userRepository.findByNickname(request.nickName()); + Optional duplicatedNickName = + userCommServiceImpl.getUserOptionalEntityByNickname(request.nickName()); if (duplicatedNickName.isPresent() && user != duplicatedNickName.get()) { throw new ApplicationException(ExceptionList.NICKNAME_ALREADY_EXIST); } @@ -184,10 +178,7 @@ public Boolean updateUserProfile( @Override @Transactional public Boolean withdrawal(AuthenticatedUser authenticatedUser, WithdrawalReq request) { - User user = - userRepository - .findById(authenticatedUser.getIdx()) - .orElseThrow(() -> new ApplicationException(ExceptionList.USER_NOT_FOUND)); + User user = userCommServiceImpl.getUserEntity(authenticatedUser.getIdx()); Withdrawal withdrawal; if (request.withdrawalReason() != WithdrawalReason.ETC) { // 기타를 제외한 경우 withdrawal = @@ -195,14 +186,15 @@ public Boolean withdrawal(AuthenticatedUser authenticatedUser, WithdrawalReq req .withdrawalReason(request.withdrawalReason()) .user(user) .build(); - } else // 기타를 선택한 경우 - withdrawal = + } else { // 기타를 선택한 경우 + withdrawal = Withdrawal.builder() .withdrawalReason(request.withdrawalReason()) .etcReason(request.etcReason()) .user(user) .build(); - withdrawalRepository.save(withdrawal); // 탈퇴 관련 정보 저장 + } + withdrawalServiceImpl.save(withdrawal); // 탈퇴 관련 정보 저장 user.setIsDeleted(); // 논리 삭제 return true; } diff --git a/src/main/java/everymeal/server/user/service/WithdrawalServiceImpl.java b/src/main/java/everymeal/server/user/service/WithdrawalServiceImpl.java new file mode 100644 index 0000000..8cd9980 --- /dev/null +++ b/src/main/java/everymeal/server/user/service/WithdrawalServiceImpl.java @@ -0,0 +1,21 @@ +package everymeal.server.user.service; + + +import everymeal.server.user.entity.Withdrawal; +import everymeal.server.user.repository.WithdrawalRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class WithdrawalServiceImpl { + + private final WithdrawalRepository withdrawalRepository; + + @Transactional + public void save(Withdrawal withdrawal) { + withdrawalRepository.save(withdrawal); + } +} diff --git a/src/test/java/everymeal/server/global/ControllerTestSupport.java b/src/test/java/everymeal/server/global/ControllerTestSupport.java index e42e6e8..49461bf 100644 --- a/src/test/java/everymeal/server/global/ControllerTestSupport.java +++ b/src/test/java/everymeal/server/global/ControllerTestSupport.java @@ -7,6 +7,8 @@ import everymeal.server.infra.HealthCheckController; import everymeal.server.meal.controller.MealController; import everymeal.server.meal.service.MealService; +import everymeal.server.report.controller.ReportController; +import everymeal.server.report.service.ReportService; import everymeal.server.review.controller.ReviewController; import everymeal.server.review.service.ReviewService; import everymeal.server.store.controller.StoreController; @@ -27,7 +29,8 @@ UniversityController.class, HealthCheckController.class, StoreController.class, - ReviewController.class + ReviewController.class, + ReportController.class }) public abstract class ControllerTestSupport { @@ -48,4 +51,6 @@ public abstract class ControllerTestSupport { @MockBean protected UniversityService universityService; @MockBean protected ReviewService reviewService; + + @MockBean protected ReportService reportService; } diff --git a/src/test/java/everymeal/server/report/controller/ReportControllerTest.java b/src/test/java/everymeal/server/report/controller/ReportControllerTest.java new file mode 100644 index 0000000..01f3b9a --- /dev/null +++ b/src/test/java/everymeal/server/report/controller/ReportControllerTest.java @@ -0,0 +1,53 @@ +package everymeal.server.report.controller; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import everymeal.server.global.ControllerTestSupport; +import everymeal.server.global.util.authresolver.UserJwtResolver; +import everymeal.server.global.util.authresolver.entity.AuthenticatedUser; +import everymeal.server.report.dto.ReportDto; +import everymeal.server.report.dto.ReportDto.ReportReviewReq; +import everymeal.server.report.entity.ReportReason; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; + +class ReportControllerTest extends ControllerTestSupport { + + @MockBean UserJwtResolver userJwtResolver; + + @Test + void 식당리뷰_신고하기() throws Exception { + // given + ReportDto.ReportReviewReq req = new ReportReviewReq(ReportReason.UNRELATED); + + given(userJwtResolver.resolveArgument(any(), any(), any(), any())) + .willReturn(AuthenticatedUser.builder().idx(1L).build()); + + // when-then + mockMvc.perform( + post("/api/v1/reports/review/{reveiwIdx}", 1L) + .content(objectMapper.writeValueAsString(req)) + .contentType("application/json")) + .andDo(print()) + .andExpect(status().isOk()); + } + + @Test + void 식당리뷰_신고하기_신고이유_없음() throws Exception { + // given + given(userJwtResolver.resolveArgument(any(), any(), any(), any())) + .willReturn(AuthenticatedUser.builder().idx(1L).build()); + + // when-then + mockMvc.perform( + post("/api/v1/reports/review/{reveiwIdx}", 1L) + .contentType("application/json")) + .andDo(print()) + .andExpect(status().isBadRequest()); + } +} diff --git a/src/test/java/everymeal/server/report/service/ReportServiceImplTest.java b/src/test/java/everymeal/server/report/service/ReportServiceImplTest.java new file mode 100644 index 0000000..3f1e21d --- /dev/null +++ b/src/test/java/everymeal/server/report/service/ReportServiceImplTest.java @@ -0,0 +1,131 @@ +package everymeal.server.report.service; + +import static everymeal.server.meal.MealData.getRestaurant; +import static everymeal.server.meal.MealData.getRestaurantRegisterReq; +import static everymeal.server.meal.MealData.getUniversity; +import static everymeal.server.review.ReviewData.getReviewEntity; +import static everymeal.server.review.ReviewData.getUserEntity; +import static org.junit.jupiter.api.Assertions.*; + +import everymeal.server.global.IntegrationTestSupport; +import everymeal.server.global.exception.ApplicationException; +import everymeal.server.global.exception.ExceptionList; +import everymeal.server.meal.entity.Restaurant; +import everymeal.server.meal.repository.RestaurantRepository; +import everymeal.server.report.dto.ReportDto; +import everymeal.server.report.dto.ReportDto.ReportReviewReq; +import everymeal.server.report.entity.Report; +import everymeal.server.report.entity.ReportReason; +import everymeal.server.report.repository.ReportRepository; +import everymeal.server.review.entity.Review; +import everymeal.server.review.repository.ReviewRepository; +import everymeal.server.university.entity.University; +import everymeal.server.university.repository.UniversityRepository; +import everymeal.server.user.entity.User; +import everymeal.server.user.repository.UserRepository; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +class ReportServiceImplTest extends IntegrationTestSupport { + + @Autowired private ReportService reportService; + + @Autowired private ReportRepository reportRepository; + + @Autowired private UserRepository userRepository; + + @Autowired private RestaurantRepository restaurantRepository; + + @Autowired private UniversityRepository universityRepository; + + @Autowired private ReviewRepository reviewRepository; + + private University university; + private Restaurant restaurant; + private User reporter; + private User reportedUser; + private Review review; + + @BeforeEach + void setUp() { + university = universityRepository.save(getUniversity()); + restaurant = + restaurantRepository.save(getRestaurant(university, getRestaurantRegisterReq())); + reporter = userRepository.save(getUserEntity(university, 1)); + reportedUser = userRepository.save(getUserEntity(university, 2)); + review = reviewRepository.save(getReviewEntity(restaurant, reportedUser)); + } + + @AfterEach + void tearDown() { + reportRepository.deleteAllInBatch(); + reviewRepository.deleteAllInBatch(); + restaurantRepository.deleteAllInBatch(); + userRepository.deleteAllInBatch(); + universityRepository.deleteAllInBatch(); + } + + @Test + void 학생식당리뷰_신고하기_자기_자신리뷰() throws Exception { + // given + ReportDto.ReportReviewReq request = new ReportReviewReq(ReportReason.UNRELATED); + // when + ApplicationException exception = + assertThrows( + ApplicationException.class, + () -> { + reportService.reportReview( + review.getIdx(), request, reportedUser.getIdx()); + }); + // then + assertEquals(exception.getErrorCode(), ExceptionList.REPORT_REVIEW_SELF.CODE); + } + + @Test + void 학생식당리뷰_신고하기() throws Exception { + // given + ReportDto.ReportReviewReq request = new ReportReviewReq(ReportReason.UNRELATED); + // when + Boolean result = reportService.reportReview(review.getIdx(), request, reporter.getIdx()); + Report report = + reportRepository + .findByReviewIdxAndUserIdx(review.getIdx(), reporter.getIdx()) + .get(); + // then + assertTrue(result); + assertEquals(report.getReason(), request.reason()); + } + + @Test + void 학생식당리뷰_신고하기_이미_신고한_리뷰() throws Exception { + // given + ReportDto.ReportReviewReq request = new ReportReviewReq(ReportReason.UNRELATED); + reportService.reportReview(review.getIdx(), request, reporter.getIdx()); + // when + ApplicationException exception = + assertThrows( + ApplicationException.class, + () -> { + reportService.reportReview(review.getIdx(), request, reporter.getIdx()); + }); + // then + assertEquals(exception.getErrorCode(), ExceptionList.REPORT_REVIEW_ALREADY.CODE); + } + + @Test + void 학생식당리뷰_신고하기_없는_리뷰() throws Exception { + // given + ReportDto.ReportReviewReq request = new ReportReviewReq(ReportReason.UNRELATED); + // when + ApplicationException exception = + assertThrows( + ApplicationException.class, + () -> { + reportService.reportReview(0L, request, reporter.getIdx()); + }); + // then + assertEquals(exception.getErrorCode(), ExceptionList.REVIEW_NOT_FOUND.CODE); + } +} From f1c6a7f31373aabf459b5220ab8a30fd98dfcc56 Mon Sep 17 00:00:00 2001 From: dldmsql Date: Sun, 7 Jan 2024 00:19:18 +0900 Subject: [PATCH 02/23] =?UTF-8?q?refactor:=20repository=20=EC=9D=98?= =?UTF-8?q?=EC=A1=B4=20=EA=B4=80=EA=B3=84=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/meal/repository/MealMapper.java | 5 -- .../meal/service/MealCommServiceImpl.java | 35 +++++++++++ .../server/meal/service/MealServiceImpl.java | 59 ++++--------------- .../service/RestaurantCommServiceImpl.java | 40 +++++++++++++ .../meal/service/RestaurantService.java | 3 +- .../meal/service/RestaurantServiceImpl.java | 17 +++--- .../review/service/ReviewServiceImpl.java | 38 +++--------- .../resources/mybatis/mappers/MealMapper.xml | 34 ----------- 8 files changed, 106 insertions(+), 125 deletions(-) create mode 100644 src/main/java/everymeal/server/meal/service/MealCommServiceImpl.java create mode 100644 src/main/java/everymeal/server/meal/service/RestaurantCommServiceImpl.java diff --git a/src/main/java/everymeal/server/meal/repository/MealMapper.java b/src/main/java/everymeal/server/meal/repository/MealMapper.java index 58b43b9..b05f245 100644 --- a/src/main/java/everymeal/server/meal/repository/MealMapper.java +++ b/src/main/java/everymeal/server/meal/repository/MealMapper.java @@ -16,11 +16,6 @@ List> findDayList( @Param("universityName") String universityName, @Param("campusName") String campusName); - List> findWeekList( - @Param("weeklyDates") List weeklyDates, - @Param("universityName") String universityName, - @Param("campusName") String campusName); - List findAllByOfferedAtOnDateAndMealType( @Param("offeredAt") String offeredAt, @Param("mealType") String mealType, diff --git a/src/main/java/everymeal/server/meal/service/MealCommServiceImpl.java b/src/main/java/everymeal/server/meal/service/MealCommServiceImpl.java new file mode 100644 index 0000000..463e1ae --- /dev/null +++ b/src/main/java/everymeal/server/meal/service/MealCommServiceImpl.java @@ -0,0 +1,35 @@ +package everymeal.server.meal.service; + + +import everymeal.server.meal.entity.Meal; +import everymeal.server.meal.repository.MealDao; +import everymeal.server.meal.repository.MealMapper; +import java.util.List; +import java.util.Map; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class MealCommServiceImpl { + + private final MealDao mealDao; // JPQL DAO + private final MealMapper mealMapper; // MyBatis DAO + + public List getMealAllByOfferedAtOnDateAndMealType( + String offeredAt, String mealType, Long restaurantIdx) { + return mealMapper.findAllByOfferedAtOnDateAndMealType(offeredAt, mealType, restaurantIdx); + } + + @Transactional + public void saveAll(List mealList) { + mealDao.saveAll(mealList); + } + + public List> getDayList( + String offeredAt, String universityName, String campusName) { + return mealMapper.findDayList(offeredAt, universityName, campusName); + } +} diff --git a/src/main/java/everymeal/server/meal/service/MealServiceImpl.java b/src/main/java/everymeal/server/meal/service/MealServiceImpl.java index 6bc2373..d069e23 100644 --- a/src/main/java/everymeal/server/meal/service/MealServiceImpl.java +++ b/src/main/java/everymeal/server/meal/service/MealServiceImpl.java @@ -10,11 +10,6 @@ import everymeal.server.meal.controller.dto.response.RestaurantListGetRes; import everymeal.server.meal.entity.Meal; import everymeal.server.meal.entity.Restaurant; -import everymeal.server.meal.repository.MealDao; -import everymeal.server.meal.repository.MealMapper; -import everymeal.server.meal.repository.MealRepository; -import everymeal.server.university.entity.University; -import everymeal.server.university.service.UniversityService; import java.time.DayOfWeek; import java.time.LocalDate; import java.util.ArrayList; @@ -22,7 +17,6 @@ import java.util.List; import java.util.Map; import lombok.RequiredArgsConstructor; -import lombok.val; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -31,30 +25,9 @@ @Service public class MealServiceImpl implements MealService { - /** - * ============================================================================================ - * DI - * ============================================================================================ - */ - private final MealRepository mealRepository; // 기본 JPA 제공 DAO - - private final MealDao mealDao; // JPQL DAO - private final MealMapper mealMapper; // MyBatis DAO + private final MealCommServiceImpl mealCommServiceImpl; private final RestaurantService restaurantServiceImpl; - private final UniversityService universityServiceImpl; - /** - * ============================================================================================ - * 학식 식단 등록 ( 주간, 하루 모두 등록 가능 ) - * - * @param request 식단 등록 요청 DTO - * @return true - *

식당이 없는 경우, - * @throws ApplicationException 404 존재하지 않는 식당입니다.
- * REQ 데이터 중 offeredAt, Restaurant, MealType 이 동일한 데이터가 존재한다면, - * @throws ApplicationException 400 등록되어 있는 식단 데이터 보다 과거의 날짜로 등록할 수 없습니다.
- * ========================================================================================= - */ @Override @Transactional public Boolean createWeekMeal(WeekMealRegisterReq request) { @@ -66,8 +39,8 @@ public Boolean createWeekMeal(WeekMealRegisterReq request) { List mealList = new ArrayList<>(); for (MealRegisterReq req : request.registerReqList()) { // 제공날짜, 학생식당, 식사분류가 동일한 데이터가 이미 존재하면, 덮어쓰기 불가능 오류 - if (!mealMapper - .findAllByOfferedAtOnDateAndMealType( + if (!mealCommServiceImpl + .getMealAllByOfferedAtOnDateAndMealType( req.offeredAt().toString(), req.mealType(), request.restaurantIdx()) .isEmpty()) { throw new ApplicationException(ExceptionList.INVALID_MEAL_OFFEREDAT_REQUEST); @@ -77,34 +50,23 @@ public Boolean createWeekMeal(WeekMealRegisterReq request) { mealList.add(meal); } } - mealDao.saveAll(mealList); + mealCommServiceImpl.saveAll(mealList); return true; } - /** - * ============================================================================================ - * 학생식당 리스트 조회 - * - * @param universityName 학교 한글명 - * @param campusName 캠퍼스 이름 - * @return List - *

학교가 없는 경우, - * @throws ApplicationException 404 존재하지 않는 학교입니다.
- * ========================================================================================= - */ + @Override public List getRestaurantList(String universityName, String campusName) { - // 학교 등록 여부 판단 - University university = universityServiceImpl.getUniversity(universityName, campusName); // 학교와 식당 폐업 여부를 키로 조회 List restaurants = - restaurantServiceImpl.getAllByUniversityAndIsDeletedFalse(university); + restaurantServiceImpl.getAllByUniversityAndIsDeletedFalse( + universityName, campusName); return RestaurantListGetRes.of(restaurants); } @Override public Map>> getDayMealListV2( String universityName, String campusName, String offeredAt) { - var result = mealMapper.findDayList(offeredAt, universityName, campusName); + var result = mealCommServiceImpl.getDayList(offeredAt, universityName, campusName); return Map.of(offeredAt, DayMealGetRes.of(result)); } @@ -135,9 +97,10 @@ public List>>> getWeekMealList( } List>>> result = new ArrayList<>(); for (LocalDate i = monday; i.isBefore(sunday); i = i.plusDays(1)) { - val row = + Map> row = DayMealGetRes.of( - mealMapper.findDayList(i.toString(), universityName, campusName)); + mealCommServiceImpl.getDayList( + i.toString(), universityName, campusName)); result.add(Map.of(i.toString(), row)); } return result; diff --git a/src/main/java/everymeal/server/meal/service/RestaurantCommServiceImpl.java b/src/main/java/everymeal/server/meal/service/RestaurantCommServiceImpl.java new file mode 100644 index 0000000..ab06b88 --- /dev/null +++ b/src/main/java/everymeal/server/meal/service/RestaurantCommServiceImpl.java @@ -0,0 +1,40 @@ +package everymeal.server.meal.service; + +import static everymeal.server.global.exception.ExceptionList.RESTAURANT_NOT_FOUND; + +import everymeal.server.global.exception.ApplicationException; +import everymeal.server.meal.entity.Restaurant; +import everymeal.server.meal.repository.RestaurantRepository; +import everymeal.server.university.entity.University; +import java.util.List; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class RestaurantCommServiceImpl { + + private final RestaurantRepository restaurantRepository; + + public Optional getRestaurantOptionalEntity(Long restaurantIdx) { + return restaurantRepository.findById(restaurantIdx); + } + + public Restaurant getRestaurantEntity(Long restaurantIdx) { + return restaurantRepository + .findById(restaurantIdx) + .orElseThrow(() -> new ApplicationException(RESTAURANT_NOT_FOUND)); + } + + @Transactional + public Restaurant save(Restaurant restaurant) { + return restaurantRepository.save(restaurant); + } + + public List getAllByUniversityAndIsDeletedFalse(University university) { + return restaurantRepository.findAllByUniversityAndIsDeletedFalse(university); + } +} diff --git a/src/main/java/everymeal/server/meal/service/RestaurantService.java b/src/main/java/everymeal/server/meal/service/RestaurantService.java index 79a6bed..232463d 100644 --- a/src/main/java/everymeal/server/meal/service/RestaurantService.java +++ b/src/main/java/everymeal/server/meal/service/RestaurantService.java @@ -3,7 +3,6 @@ import everymeal.server.meal.controller.dto.request.RestaurantRegisterReq; import everymeal.server.meal.entity.Restaurant; -import everymeal.server.university.entity.University; import java.util.List; public interface RestaurantService { @@ -12,5 +11,5 @@ public interface RestaurantService { Boolean createRestaurant(RestaurantRegisterReq restaurantRegisterReq); - List getAllByUniversityAndIsDeletedFalse(University university); + List getAllByUniversityAndIsDeletedFalse(String universityName, String campusName); } diff --git a/src/main/java/everymeal/server/meal/service/RestaurantServiceImpl.java b/src/main/java/everymeal/server/meal/service/RestaurantServiceImpl.java index 4467be2..9776114 100644 --- a/src/main/java/everymeal/server/meal/service/RestaurantServiceImpl.java +++ b/src/main/java/everymeal/server/meal/service/RestaurantServiceImpl.java @@ -5,7 +5,6 @@ import everymeal.server.global.exception.ExceptionList; import everymeal.server.meal.controller.dto.request.RestaurantRegisterReq; import everymeal.server.meal.entity.Restaurant; -import everymeal.server.meal.repository.RestaurantRepository; import everymeal.server.university.entity.University; import everymeal.server.university.service.UniversityService; import java.util.List; @@ -18,13 +17,13 @@ @Service public class RestaurantServiceImpl implements RestaurantService { - private final RestaurantRepository restaurantRepository; + private final RestaurantCommServiceImpl restaurantCommServiceImpl; private final UniversityService universityServiceImpl; @Override public Restaurant getRestaurant(Long restaurantIdx) { - return restaurantRepository - .findById(restaurantIdx) + return restaurantCommServiceImpl + .getRestaurantOptionalEntity(restaurantIdx) .orElseThrow(() -> new ApplicationException(ExceptionList.RESTAURANT_NOT_FOUND)); } @@ -41,11 +40,15 @@ public Boolean createRestaurant(RestaurantRegisterReq restaurantRegisterReq) { .restaurantRegisterReq(restaurantRegisterReq) .university(university) .build(); - return restaurantRepository.save(restaurant).getIdx() != null; + return restaurantCommServiceImpl.save(restaurant).getIdx() != null; } @Override - public List getAllByUniversityAndIsDeletedFalse(University university) { - return restaurantRepository.findAllByUniversityAndIsDeletedFalse(university); + public List getAllByUniversityAndIsDeletedFalse( + String universityName, String campusName) { + // 학교 등록 여부 판단 + University university = universityServiceImpl.getUniversity(universityName, campusName); + + return restaurantCommServiceImpl.getAllByUniversityAndIsDeletedFalse(university); } } diff --git a/src/main/java/everymeal/server/review/service/ReviewServiceImpl.java b/src/main/java/everymeal/server/review/service/ReviewServiceImpl.java index 1318dd8..8a5c484 100644 --- a/src/main/java/everymeal/server/review/service/ReviewServiceImpl.java +++ b/src/main/java/everymeal/server/review/service/ReviewServiceImpl.java @@ -1,15 +1,13 @@ package everymeal.server.review.service; -import static everymeal.server.global.exception.ExceptionList.RESTAURANT_NOT_FOUND; import static everymeal.server.global.exception.ExceptionList.REVIEW_ALREADY_MARKED; import static everymeal.server.global.exception.ExceptionList.REVIEW_MARK_NOT_FOUND; import static everymeal.server.global.exception.ExceptionList.REVIEW_UNAUTHORIZED; -import static everymeal.server.global.exception.ExceptionList.USER_NOT_FOUND; import everymeal.server.global.exception.ApplicationException; import everymeal.server.global.util.TimeFormatUtil; import everymeal.server.meal.entity.Restaurant; -import everymeal.server.meal.repository.RestaurantRepository; +import everymeal.server.meal.service.RestaurantCommServiceImpl; import everymeal.server.review.dto.request.ReviewCreateReq; import everymeal.server.review.dto.response.ReviewDto; import everymeal.server.review.dto.response.ReviewDto.ReviewGetRes; @@ -18,12 +16,10 @@ import everymeal.server.review.entity.Image; import everymeal.server.review.entity.Review; import everymeal.server.user.entity.User; -import everymeal.server.user.repository.UserRepository; +import everymeal.server.user.service.UserCommServiceImpl; import java.util.ArrayList; import java.util.List; import lombok.RequiredArgsConstructor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -32,10 +28,8 @@ @Transactional(readOnly = true) public class ReviewServiceImpl implements ReviewService { - private final RestaurantRepository restaurantRepository; - private final UserRepository userRepository; - private final Logger logger = LoggerFactory.getLogger(ReviewServiceImpl.class); - + private final RestaurantCommServiceImpl restaurantCommServiceImpl; + private final UserCommServiceImpl userCommServiceImpl; private final ReviewCommServiceImpl reviewCommServiceImpl; @Override @@ -43,16 +37,11 @@ public class ReviewServiceImpl implements ReviewService { public Long createReview(ReviewCreateReq request, Long userIdx) { // (1) restaurant 객체 조회 Restaurant restaurant = - restaurantRepository - .findById(request.restaurantIdx()) - .orElseThrow(() -> new ApplicationException(RESTAURANT_NOT_FOUND)); + restaurantCommServiceImpl.getRestaurantEntity(request.restaurantIdx()); // (2) 이미지 주소 <> 이미지 객체 치환 List imageList = getImageFromString(request.imageList()); - User user = - userRepository - .findById(userIdx) - .orElseThrow(() -> new ApplicationException(USER_NOT_FOUND)); + User user = userCommServiceImpl.getUserEntity(userIdx); // (3) Entity 생성 ( 사진리뷰인지 분기 처리 ) Review review = @@ -88,10 +77,7 @@ public Long updateReview(ReviewCreateReq request, Long userIdx, Long reviewIdx) // (2) 이미지 주소 <> 이미지 객체 치환 List imageList = getImageFromString(request.imageList()); - User user = - userRepository - .findById(userIdx) - .orElseThrow(() -> new ApplicationException(USER_NOT_FOUND)); + User user = userCommServiceImpl.getUserEntity(userIdx); if (review.getUser() != user) { throw new ApplicationException(REVIEW_UNAUTHORIZED); } @@ -107,10 +93,7 @@ public Long updateReview(ReviewCreateReq request, Long userIdx, Long reviewIdx) @Transactional public Boolean deleteReview(Long userIdx, Long reviewIdx) { // (1) 기존 리뷰 조회 - User user = - userRepository - .findById(userIdx) - .orElseThrow(() -> new ApplicationException(USER_NOT_FOUND)); + User user = userCommServiceImpl.getUserEntity(userIdx); Review review = reviewCommServiceImpl.getReviewEntity(reviewIdx, user); // (2) 기존 데이터 삭제 review.getRestaurant().removeGrade(review.getGrade()); @@ -155,10 +138,7 @@ public ReviewGetRes getReviewWithNoOffSetPaging(ReviewDto.ReviewQueryParam query public Boolean markReview(Long reviewIdx, boolean isLike, Long userIdx) { // (1) 기존 리뷰 조회 Review review = reviewCommServiceImpl.getReviewEntity(reviewIdx); - User user = - userRepository - .findById(userIdx) - .orElseThrow(() -> new ApplicationException(USER_NOT_FOUND)); + User user = userCommServiceImpl.getUserEntity(userIdx); // (2) 기존 데이터 수정 if (isLike) { reviewCommServiceImpl diff --git a/src/main/resources/mybatis/mappers/MealMapper.xml b/src/main/resources/mybatis/mappers/MealMapper.xml index 3161aab..7049077 100644 --- a/src/main/resources/mybatis/mappers/MealMapper.xml +++ b/src/main/resources/mybatis/mappers/MealMapper.xml @@ -34,40 +34,6 @@ ORDER BY r.name ASC, operatingTime ASC -