Skip to content

Commit

Permalink
Merge pull request #82 from SanE-Seo/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
Hong-Mu authored May 5, 2024
2 parents 26ff900 + 500a801 commit 4b7e961
Show file tree
Hide file tree
Showing 14 changed files with 131 additions and 71 deletions.
2 changes: 2 additions & 0 deletions src/main/java/com/seoultech/sanEseo/SanEseoApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@EnableJpaAuditing
@SpringBootApplication
public class SanEseoApplication {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ protected boolean shouldNotFilter(HttpServletRequest request) {

skipPathList.add(new AntPathRequestMatcher("/api/posts/*", HttpMethod.GET.name()));
skipPathList.add(new AntPathRequestMatcher("/api/posts/*/likes", HttpMethod.GET.name()));

skipPathList.add(new AntPathRequestMatcher("/api/posts/*/reviews", HttpMethod.GET.name()));

skipPathList.add(new AntPathRequestMatcher("/api/districts/**", HttpMethod.GET.name()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
errorLoggerHelper.log(wrapper, e.getErrorType(), e.getMessage());
e.printStackTrace();
setErrorResponse(e.getErrorType(), e.getMessage(), response);
} catch (IllegalArgumentException e) {
errorLoggerHelper.log(wrapper, ErrorType.INVALID_INPUT_VALUE, e.getMessage());
e.printStackTrace();
setErrorResponse(ErrorType.INVALID_INPUT_VALUE, e.getMessage(), response);
} catch (Exception e) {
errorLoggerHelper.log(wrapper, ErrorType.INTERNAL_ERROR, e.getMessage());
e.printStackTrace();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public enum ErrorType {
DUPLICATE_LIKES("E009", 400),
MEMBER_NOT_LIKED("E010", 400),
AUTHOR_MISMATCH("E011", 400),
UNAUTHORIZED_ACCESS("E012", 401),
ENTITY_NOT_FOUND("E404", 404),
INVALID_INPUT_VALUE("E403", 403),
INTERNAL_ERROR("E999", 500);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,22 @@ public ResponseEntity<?> handleConstraintViolationException(ConstraintViolationE
return ApiResponse.fail(ErrorType.INVALID_INPUT_VALUE, "잘못된 값입니다.");
}

@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<?> handleIllegalArgumentException(IllegalArgumentException e, RequestWrapper request) throws IOException {
errorLoggerHelper.log(request, ErrorType.INVALID_INPUT_VALUE, e.getMessage());
e.printStackTrace();
return ApiResponse.fail(ErrorType.INVALID_INPUT_VALUE, e.getMessage());
}

@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<?> handleEntityNotFoundException(EntityNotFoundException e, RequestWrapper request) throws IOException {
errorLoggerHelper.log(request, ErrorType.ENTITY_NOT_FOUND, e.getMessage());
e.printStackTrace();
return ApiResponse.fail(ErrorType.ENTITY_NOT_FOUND, e.getMessage());
}



@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<?> handleIllegalArgumentException(MethodArgumentNotValidException e, RequestWrapper request) throws IOException {
errorLoggerHelper.log(request, ErrorType.INVALID_INPUT_VALUE, e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.seoultech.sanEseo.global.exception;

public class UnauthorizedAccessException extends BusinessException{

public UnauthorizedAccessException(String message) {
super(ErrorType.UNAUTHORIZED_ACCESS, message);
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.seoultech.sanEseo.review.application.port.ReviewPort;
import com.seoultech.sanEseo.review.application.service.GetReviewResponse;
import com.seoultech.sanEseo.review.domain.Review;
import jakarta.persistence.EntityNotFoundException;
import org.springframework.stereotype.Component;

import java.util.List;
Expand All @@ -25,28 +26,22 @@ public void createReview(Review review) {
}

@Override
public void deleteReview(Post post, Member member) {
reviewRepository.deleteByPostAndMember(post, member);
}

@Override
public void updateReview(Post post, Member member, Review review) {
reviewRepository.save(review);
public void deleteReview(Long reviewId) {
reviewRepository.deleteById(reviewId);
}

@Override
public List<GetReviewResponse> getReviewList(Long postId) {

List<GetReviewResponse> reviewResponses = reviewRepository.findByPostId(postId).stream()
.map(review -> GetReviewResponse.builder()
.reviewId(review.getId())
.memberId(review.getMember().getId())
.postId(review.getPost().getId())
.content(review.getContent())
.createDate(review.getCreateDate())
.build())
return reviewRepository.findByPostId(postId).stream()
.map(GetReviewResponse::fromEntity)
.toList();
}

return reviewResponses;
@Override
public Review findById(Long reviewId) {
return reviewRepository.findById(reviewId).orElseThrow(
() -> new EntityNotFoundException("해당 리뷰가 존재하지 않습니다.")
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,21 @@ public ReviewController(ReviewService reviewService) {
this.reviewService = reviewService;
}

@PostMapping("/reviews")
public ResponseEntity<?> createReview(@LoginMember AuthMember authMember, @RequestBody @Valid CreateReviewRequest request) {
reviewService.createReview(authMember.getId(), request);
@PostMapping("/posts/{postId}/reviews")
public ResponseEntity<?> createReview(@LoginMember AuthMember authMember, @PathVariable Long postId, @RequestBody CreateReviewRequest request) {
reviewService.createReview(authMember.getId(), postId, request);
return ApiResponse.ok("리뷰가 성공적으로 생성되었습니다.");
}

@DeleteMapping("/posts/{postId}/members/reviews")
public ResponseEntity<?> deleteReview(@LoginMember AuthMember authMember, @PathVariable Long postId) {
reviewService.deleteReview(postId, authMember.getId());
@DeleteMapping("/posts/{postId}/reviews/{reviewId}")
public ResponseEntity<?> deleteReview(@LoginMember AuthMember authMember, @PathVariable Long postId, @PathVariable Long reviewId) {
reviewService.deleteReview(authMember.getId(), postId, reviewId);
return ApiResponse.ok("리뷰가 성공적으로 삭제되었습니다.");
}

@PutMapping("/posts/{postId}/members/reviews")
public ResponseEntity<?> updateReview(@LoginMember AuthMember authMember, @PathVariable Long postId, @RequestBody UpdateReviewRequest request) {
reviewService.updateReview(postId, authMember.getId(), request);
@PutMapping("/posts/{postId}/reviews/{reviewId}")
public ResponseEntity<?> updateReview(@LoginMember AuthMember authMember, @PathVariable Long postId, @PathVariable Long reviewId, @RequestBody UpdateReviewRequest request) {
reviewService.updateReview(authMember.getId(), postId, reviewId, request);
return ApiResponse.ok("리뷰가 성공적으로 업데이트되었습니다.");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ public interface ReviewRepository extends JpaRepository<Review, Long> {

List<Review> findByPostId(Long postId);

void deleteByPostAndMember(Post post, Member member);
void deleteById(Long reviewId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
public interface ReviewPort {
void createReview(Review review);

void deleteReview(Post post, Member member);

void updateReview(Post post, Member member, Review review);
void deleteReview(Long reviewId);

List<GetReviewResponse> getReviewList(Long postId);

Review findById(Long reviewId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,21 @@
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.util.Assert;

import java.time.LocalDateTime;

@NoArgsConstructor
@Getter
public class CreateReviewRequest {
@NotNull(message = "게시글 ID는 필수입니다.")
Long postId;
@NotBlank(message = "리뷰 내용은 필수입니다.")

@NotBlank(message = "리뷰 내용은 필수 입력 값입니다.")
String content;
@NotNull(message = "리뷰 작성일은 필수입니다.")
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime createDate;

public CreateReviewRequest(Long postId, String content, LocalDateTime createDate) {
this.postId = postId;
public CreateReviewRequest(String content) {
this.content = content;
this.createDate = createDate;
}

}
Original file line number Diff line number Diff line change
@@ -1,26 +1,44 @@
package com.seoultech.sanEseo.review.application.service;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.seoultech.sanEseo.member.domain.Member;
import com.seoultech.sanEseo.review.domain.Review;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.util.Assert;

import java.time.LocalDateTime;

public record GetReviewResponse(
Long reviewId,
Long memberId,
Long postId,
String content,
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
LocalDateTime createDate
) {
@Builder
public GetReviewResponse {
Assert.notNull(reviewId, "리뷰 ID는 필수입니다.");
Assert.notNull(memberId, "사용자 ID는 필수입니다.");
Assert.notNull(postId, "게시글 ID는 필수입니다.");
Assert.hasText(content, "리뷰 내용은 필수입니다.");
Assert.notNull(createDate, "리뷰 작성일은 필수입니다.");
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class GetReviewResponse {
Long reviewId;
Long authorId;
String authorName;
String authorProfileImageUrl;
Long postId;
String content;
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
LocalDateTime createAt;
@DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
LocalDateTime updateAt;

public static GetReviewResponse fromEntity(Review review) {
Member author = review.getMember();
return GetReviewResponse.builder()
.reviewId(review.getId())
.authorId(author.getId())
.authorName(author.getName())
.authorProfileImageUrl(author.getProfile())
.postId(review.getPost().getId())
.content(review.getContent())
.createAt(review.getCreateAt())
.updateAt(review.getUpdateAt())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.seoultech.sanEseo.review.application.service;

import com.seoultech.sanEseo.global.exception.UnauthorizedAccessException;
import com.seoultech.sanEseo.member.application.port.out.MemberPort;
import com.seoultech.sanEseo.member.domain.Member;
import com.seoultech.sanEseo.post.application.port.PostPort;
Expand All @@ -25,44 +26,56 @@ class ReviewService {
}

@Transactional
public void createReview(Long memberId, CreateReviewRequest request) {
public void createReview(Long memberId, Long postId, CreateReviewRequest request) {

Post post = postPort.getPost(postId);
Member member = memberPort.loadById(memberId);
Post post = postPort.getPost(request.getPostId());

Review review = Review.builder()
.member(member)
.post(post)
.content(request.getContent())
.createDate(request.getCreateDate())
.build();

reviewPort.createReview(review);
}

@Transactional
public void deleteReview(Long postId, Long memberId) {
Member member = memberPort.loadById(memberId);
public void deleteReview(Long memberId, Long postId, Long reviewId) {
Post post = postPort.getPost(postId);
Review review = reviewPort.findById(reviewId);

if(!post.getId().equals(review.getPost().getId())) {
throw new IllegalArgumentException("해당 게시글에 존재하지 않는 리뷰입니다.");
}

reviewPort.deleteReview(post, member);
if(!review.getMember().getId().equals(memberId)) {
throw new UnauthorizedAccessException("해당 리뷰를 삭제할 권한이 없습니다.");
}

reviewPort.deleteReview(reviewId);
}

@Transactional
public void updateReview(Long postId, Long memberId, UpdateReviewRequest request) {
Member member = memberPort.loadById(memberId);
public void updateReview(Long memberId, Long postId, Long reviewId, UpdateReviewRequest request) {
Post post = postPort.getPost(postId);
Review review = reviewPort.findById(reviewId);

Review review = Review.builder()
.member(member)
.post(post)
.content(request.getContent())
.createDate(request.getCreateDate())
.build();
reviewPort.updateReview(post, member, review);
if(!post.getId().equals(review.getPost().getId())) {
throw new IllegalArgumentException("해당 게시글에 존재하지 않는 리뷰입니다.");
}

if(!review.getMember().getId().equals(memberId)) {
throw new UnauthorizedAccessException("해당 리뷰를 수정할 권한이 없습니다.");
}

review.updateContent(request.getContent());
}

public List<GetReviewResponse> getReviewList(Long postId) {

postPort.getPost(postId); // 게시글이 존재하는지 확인

return reviewPort.getReviewList(postId);
}
}
18 changes: 14 additions & 4 deletions src/main/java/com/seoultech/sanEseo/review/domain/Review.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;

@EntityListeners(AuditingEntityListener.class)
@Entity
@Getter
@NoArgsConstructor
Expand All @@ -28,14 +32,20 @@ public class Review {

private String content;

@Column(name = "create_date", nullable = false)
private LocalDateTime createDate;
@CreatedDate
private LocalDateTime createAt;

@LastModifiedDate
private LocalDateTime updateAt;

@Builder
public Review(Member member, Post post, String content, LocalDateTime createDate) {
public Review(Member member, Post post, String content) {
this.member = member;
this.post = post;
this.content = content;
this.createDate = createDate;
}

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

0 comments on commit 4b7e961

Please sign in to comment.