Skip to content
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
6 changes: 5 additions & 1 deletion src/main/java/com/moongeul/backend/api/book/entity/Book.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,9 @@ public void update(String title, String author, String bookImage, String publish
this.description = description;
this.pubdate = pubdate;
}
}

public void updateRatingStats(Double ratingAverage, Integer ratingCount) {
this.ratingAverage = ratingAverage;
this.ratingCount = ratingCount;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public ResponseEntity<ApiResponse<DoneReadBookshelfResponseDTO>> getDoneReadBook
@RequestParam(required = false, defaultValue = "10") @Min(value = 1, message = "한 페이지당 개수는 1 이상이어야 합니다.") Integer size) {

DoneReadBookshelfResponseDTO doneReadBookshelfResponseDTO =
doneReadBookshelfService.getDoneReadBooks(userDetails.getUsername(), userId, page, size);
doneReadBookshelfService.getDoneReadBooks(resolveUsername(userDetails), userId, page, size);
return ApiResponse.success(SuccessStatus.GET_DONE_READ_BOOKS_SUCCESS, doneReadBookshelfResponseDTO);
}

Expand All @@ -71,7 +71,7 @@ public ResponseEntity<ApiResponse<DoneReadBookPostListResponseDTO>> getDoneReadB
@RequestParam(defaultValue = "10") @Min(value = 1, message = "한 페이지당 개수는 1 이상이어야 합니다.") Integer size) {

DoneReadBookPostListResponseDTO doneReadBookPostListResponseDTO =
doneReadBookshelfService.getDoneReadBookPosts(userDetails.getUsername(), userId, isbn, page, size);
doneReadBookshelfService.getDoneReadBookPosts(resolveUsername(userDetails), userId, isbn, page, size);
return ApiResponse.success(SuccessStatus.GET_DONE_READ_BOOK_POSTS_SUCCESS, doneReadBookPostListResponseDTO);
}

Expand All @@ -94,7 +94,7 @@ public ResponseEntity<ApiResponse<DoneReadCalendarResponseDTO>> getDoneReadCalen
@RequestParam @Min(value = 1, message = "월은 1 이상이어야 합니다.") @Max(value = 12, message = "월은 12 이하여야 합니다.") Integer month) {

DoneReadCalendarResponseDTO doneReadCalendar = doneReadBookshelfService.getDoneReadCalendar(
userDetails.getUsername(), userId, year, month);
resolveUsername(userDetails), userId, year, month);
return ApiResponse.success(SuccessStatus.GET_DONE_READ_CALENDAR_SUCCESS, doneReadCalendar);
}

Expand All @@ -113,7 +113,7 @@ public ResponseEntity<ApiResponse<DoneReadRatingSummaryResponseDTO>> getDoneRead
@RequestParam(required = false) Long userId) {

DoneReadRatingSummaryResponseDTO doneReadRatingSummaryResponseDTO =
doneReadBookshelfService.getDoneReadRatingSummary(userDetails.getUsername(), userId);
doneReadBookshelfService.getDoneReadRatingSummary(resolveUsername(userDetails), userId);
return ApiResponse.success(SuccessStatus.GET_DONE_READ_RATING_SUMMARY_SUCCESS, doneReadRatingSummaryResponseDTO);
}

Expand Down Expand Up @@ -144,7 +144,11 @@ public ResponseEntity<ApiResponse<CategoryPostListResponseDTO>> getDoneReadRatin
@RequestParam(defaultValue = "10") @Min(value = 1, message = "한 페이지당 개수는 1 이상이어야 합니다.") Integer size) {

CategoryPostListResponseDTO categoryPostListResponseDTO =
doneReadBookshelfService.getDoneReadRatingDetail(userDetails.getUsername(), userId, range, sortBy, page, size);
doneReadBookshelfService.getDoneReadRatingDetail(resolveUsername(userDetails), userId, range, sortBy, page, size);
return ApiResponse.success(SuccessStatus.GET_DONE_READ_RATING_DETAIL_SUCCESS, categoryPostListResponseDTO);
}

private String resolveUsername(UserDetails userDetails) {
return (userDetails != null) ? userDetails.getUsername() : "anonymousUser";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ public DoneReadRatingSummaryResponseDTO getDoneReadRatingSummary(String email, L
// 읽은 책별 기록 리스트 조회
@Transactional(readOnly = true)
public DoneReadBookPostListResponseDTO getDoneReadBookPosts(String email, Long userId, String isbn, Integer page, Integer size) {
Member currentMember = getCurrentMember(email);
Member currentMember = getCurrentMemberOrNull(email);
Member targetMember = getTargetMember(currentMember, userId);
Book book = bookRepository.findByIsbn(isbn)
.orElseThrow(() -> new NotFoundException(ErrorStatus.BOOK_NOTFOUND_EXCEPTION.getMessage()));
Expand All @@ -230,7 +230,7 @@ public DoneReadBookPostListResponseDTO getDoneReadBookPosts(String email, Long u
// 읽은 책 별점 구간 상세 조회
@Transactional(readOnly = true)
public CategoryPostListResponseDTO getDoneReadRatingDetail(String email, Long userId, String range, String sortBy, Integer page, Integer size) {
Member currentMember = getCurrentMember(email);
Member currentMember = getCurrentMemberOrNull(email);
Member targetMember = getTargetMember(currentMember, userId);

int rangeIndex = findRangeIndex(range);
Expand Down Expand Up @@ -380,27 +380,36 @@ private int findRangeIndex(String range) {
}

private Member getTargetMember(String email, Long userId) {
Member currentMember = getCurrentMember(email);
Member currentMember = getCurrentMemberOrNull(email);
return getTargetMember(currentMember, userId);
}

private Member getCurrentMember(String email) {
private Member getCurrentMemberOrNull(String email) {
if (email == null || "anonymousUser".equals(email)) {
return null;
}

return memberRepository.findByEmail(email)
.orElseThrow(() -> new NotFoundException(ErrorStatus.USER_NOTFOUND_EXCEPTION.getMessage()));
}

private Member getTargetMember(Member currentMember, Long userId) {
Member targetMember = (userId == null)
? currentMember
: memberRepository.findById(userId)
.orElseThrow(() -> new NotFoundException(ErrorStatus.USER_NOTFOUND_EXCEPTION.getMessage()));
Member targetMember;
if (userId != null) {
targetMember = memberRepository.findById(userId)
.orElseThrow(() -> new NotFoundException(ErrorStatus.USER_NOTFOUND_EXCEPTION.getMessage()));
} else if (currentMember != null) {
targetMember = currentMember;
} else {
throw new NotFoundException(ErrorStatus.USER_NOTFOUND_EXCEPTION.getMessage());
}

validatePrivacyAccess(currentMember, targetMember);
return targetMember;
}

private void validatePrivacyAccess(Member currentMember, Member targetMember) {
if (currentMember.getId().equals(targetMember.getId())) {
if (currentMember != null && currentMember.getId().equals(targetMember.getId())) {
return;
}

Expand All @@ -415,6 +424,10 @@ private void validatePrivacyAccess(Member currentMember, Member targetMember) {
}

if (privacyLevel == PrivacyLevel.FOLLOWER_ONLY) {
if (currentMember == null) {
throw new ForbiddenException(ErrorStatus.PRIVACY_FORBIDDEN_EXCEPTION.getMessage());
}

FollowStatus status = followRepository.findByFollowingIdAndFollowerId(targetMember.getId(), currentMember.getId())
.map(Follow::getFollowStatus)
.orElse(FollowStatus.NONE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public ResponseEntity<ApiResponse<LoginResponseDTO>> loginWithKakao(@Valid @Requ
public ResponseEntity<ApiResponse<UserInfoDTO>> getUserInfo(
@AuthenticationPrincipal UserDetails userDetails,
@RequestParam(required = false) Long userId){
UserInfoDTO response = memberService.getUserInfo(userDetails.getUsername(), userId);
UserInfoDTO response = memberService.getUserInfo(resolveUsername(userDetails), userId);
return ApiResponse.success(SuccessStatus.GET_USERINFO_SUCCESS, response);
}

Expand Down Expand Up @@ -187,7 +187,7 @@ public ResponseEntity<ApiResponse<Void>> withdraw(@AuthenticationPrincipal UserD
public ResponseEntity<ApiResponse<PostStatsResponseDTO>> getPostStats(
@AuthenticationPrincipal UserDetails userDetails,
@RequestParam(required = false) Long userId){
PostStatsResponseDTO response = memberService.getPostStats(userDetails.getUsername(), userId);
PostStatsResponseDTO response = memberService.getPostStats(resolveUsername(userDetails), userId);
return ApiResponse.success(SuccessStatus.GET_POST_STATS_SUCCESS, response);
}

Expand Down Expand Up @@ -217,7 +217,7 @@ public ResponseEntity<ApiResponse<CategoryPostListResponseDTO>> getCategoryPostL
@RequestParam(defaultValue = "10") Integer size) {

CategoryPostListResponseDTO categoryPostListResponseDTO =
memberService.getCategoryPostList(userDetails.getUsername(), userId, categoryId, sortBy, page, size);
memberService.getCategoryPostList(resolveUsername(userDetails), userId, categoryId, sortBy, page, size);
return ApiResponse.success(SuccessStatus.GET_CATEGORY_POST_LIST_SUCCESS, categoryPostListResponseDTO);
}

Expand Down Expand Up @@ -245,7 +245,7 @@ public ResponseEntity<ApiResponse<CategoryPostListResponseDTO>> getLikedPostList
@RequestParam(defaultValue = "10") Integer size) {

CategoryPostListResponseDTO likedPostListResponseDTO =
memberService.getLikedPostList(userDetails.getUsername(), userId, sortBy, page, size);
memberService.getLikedPostList(resolveUsername(userDetails), userId, sortBy, page, size);
return ApiResponse.success(SuccessStatus.GET_LIKED_POST_LIST_SUCCESS, likedPostListResponseDTO);
}

Expand All @@ -265,10 +265,14 @@ public ResponseEntity<ApiResponse<QuestionListResponseDTO>> getMyQuestionList(
@RequestParam(defaultValue = "10") Integer size) {

QuestionListResponseDTO questionListResponseDTO =
questionService.getMyQuestionList(page, size, userDetails.getUsername(), userId);
questionService.getMyQuestionList(page, size, resolveUsername(userDetails), userId);
return ApiResponse.success(SuccessStatus.GET_MY_QUESTION_LIST_SUCCESS, questionListResponseDTO);
}

private String resolveUsername(UserDetails userDetails) {
return (userDetails != null) ? userDetails.getUsername() : "anonymousUser";
}

/*
*
* 팔로잉/팔로우 API
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,13 +169,10 @@ private Member signUp(String socialId, String email, String name, String picture
@Transactional(readOnly = true)
public UserInfoDTO getUserInfo(String email, Long userId){

Member currentMember = getMemberByEmail(email);
Member currentMember = getCurrentMemberOrNull(email);

// userId가 null이면 본인 정보 조회, 있으면 타 사용자 조회
Member member = (userId == null)
? currentMember
: memberRepository.findById(userId)
.orElseThrow(() -> new NotFoundException(ErrorStatus.USER_NOTFOUND_EXCEPTION.getMessage()));
Member member = getTargetMember(currentMember, userId);

// 팔로워 수 계산 (나를 팔로우하는 사람들 중 승인된 경우)
int followerCount = followRepository.findByFollowers(member.getId()).size();
Expand All @@ -185,7 +182,7 @@ public UserInfoDTO getUserInfo(String email, Long userId){

// 내가 해당 사용자를 팔로우했는지 여부
FollowStatus myFollowStatus = FollowStatus.NONE;
if (!currentMember.getId().equals(member.getId())) {
if (currentMember != null && !currentMember.getId().equals(member.getId())) {
myFollowStatus = followRepository.findByFollowingIdAndFollowerId(member.getId(), currentMember.getId())
.map(Follow::getFollowStatus)
.orElse(FollowStatus.NONE);
Expand Down Expand Up @@ -285,11 +282,8 @@ public void withdraw(String email, WithdrawalRequestDTO withdrawalRequestDTO) {
@Transactional(readOnly = true)
public PostStatsResponseDTO getPostStats(String email, Long userId) {

Member currentMember = getMemberByEmail(email);
Member targetMember = (userId == null)
? currentMember
: memberRepository.findById(userId)
.orElseThrow(() -> new NotFoundException(ErrorStatus.USER_NOTFOUND_EXCEPTION.getMessage()));
Member currentMember = getCurrentMemberOrNull(email);
Member targetMember = getTargetMember(currentMember, userId);

validatePrivacyAccess(currentMember, targetMember);

Expand Down Expand Up @@ -436,11 +430,8 @@ public void updateProfileImage(String email, MultipartFile profileImage) {
@Transactional(readOnly = true)
public CategoryPostListResponseDTO getCategoryPostList(String email, Long userId, Long categoryId, String sortBy, Integer page, Integer size) {

Member currentMember = getMemberByEmail(email);
Member targetMember = (userId == null)
? currentMember
: memberRepository.findById(userId)
.orElseThrow(() -> new NotFoundException(ErrorStatus.USER_NOTFOUND_EXCEPTION.getMessage()));
Member currentMember = getCurrentMemberOrNull(email);
Member targetMember = getTargetMember(currentMember, userId);

validatePrivacyAccess(currentMember, targetMember);

Expand Down Expand Up @@ -507,11 +498,8 @@ public CategoryPostListResponseDTO getCategoryPostList(String email, Long userId
@Transactional(readOnly = true)
public CategoryPostListResponseDTO getLikedPostList(String email, Long userId, String sortBy, Integer page, Integer size) {

Member currentMember = getMemberByEmail(email);
Member targetMember = (userId == null)
? currentMember
: memberRepository.findById(userId)
.orElseThrow(() -> new NotFoundException(ErrorStatus.USER_NOTFOUND_EXCEPTION.getMessage()));
Member currentMember = getCurrentMemberOrNull(email);
Member targetMember = getTargetMember(currentMember, userId);

validatePrivacyAccess(currentMember, targetMember);

Expand Down Expand Up @@ -627,7 +615,7 @@ private PostDTO.MyLikesStatus convertToMyLikesStatus(Member currentMember, Long
}

private void validatePrivacyAccess(Member currentMember, Member targetMember) {
if (currentMember.getId().equals(targetMember.getId())) {
if (currentMember != null && currentMember.getId().equals(targetMember.getId())) {
return;
}

Expand All @@ -642,6 +630,10 @@ private void validatePrivacyAccess(Member currentMember, Member targetMember) {
}

if (privacyLevel == PrivacyLevel.FOLLOWER_ONLY) {
if (currentMember == null) {
throw new ForbiddenException(ErrorStatus.PRIVACY_FORBIDDEN_EXCEPTION.getMessage());
}

FollowStatus status = followRepository.findByFollowingIdAndFollowerId(targetMember.getId(), currentMember.getId())
.map(Follow::getFollowStatus)
.orElse(FollowStatus.NONE);
Expand All @@ -652,6 +644,27 @@ private void validatePrivacyAccess(Member currentMember, Member targetMember) {
}
}

private Member getCurrentMemberOrNull(String email) {
if (email == null || "anonymousUser".equals(email)) {
return null;
}

return getMemberByEmail(email);
}

private Member getTargetMember(Member currentMember, Long userId) {
if (userId != null) {
return memberRepository.findById(userId)
.orElseThrow(() -> new NotFoundException(ErrorStatus.USER_NOTFOUND_EXCEPTION.getMessage()));
}

if (currentMember != null) {
return currentMember;
}

throw new NotFoundException(ErrorStatus.USER_NOTFOUND_EXCEPTION.getMessage());
}

/* 스토리 보관함 조회 API */
@Transactional(readOnly = true)
public MyStoryResponseDTO getMyStories(String email, Integer page, Integer size) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,11 @@ List<Post> findCalendarPostsByMemberAndReadDateBetweenOrderByReadDateAscCreatedA
@Query("SELECT p.rating FROM Post p WHERE p.member = :member AND p.rating IS NOT NULL")
List<Double> findRatingsByMember(@Param("member") Member member);

@Query("SELECT COALESCE(AVG(p.rating), 0.0) FROM Post p WHERE p.book = :book AND p.rating IS NOT NULL")
Double findAverageRatingByBook(@Param("book") Book book);

long countByBookAndRatingIsNotNull(Book book);

Page<Post> findByMemberAndRatingBetween(Member member, Double startRating, Double endRating, Pageable pageable);

@Query("SELECT p FROM Post p WHERE p.member = :member AND p.book.isbn = :isbn ORDER BY p.createdAt DESC")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ public PostIdResponseDTO createPost(PostRequestDTO postRequestDTO, String email)
doneReadBookshelfRepository.save(doneReadBookshelf);
}

updateBookRatingStats(book);

return PostIdResponseDTO.builder()
.postId(savedPost.getId())
.build();
Expand Down Expand Up @@ -284,8 +286,8 @@ private PostDTO.MyLikesStatus convertToMyLikesStatus(String email, Long postId){
public PostIdResponseDTO updatePost(Long postId, String email, PostRequestDTO postRequestDTO){

Post post = getPost(postId);
Book targetBook = post.getBook();
Category category = getCategory(postRequestDTO.getCategoryId());
Book book = getBook(post.getBook().getIsbn());

// 예외처리: 수정하는 사람과 게시글 주인이 같은지 확인 (본인의 게시글인지)
if (!post.getMember().getEmail().equals(email)) {
Expand Down Expand Up @@ -320,9 +322,11 @@ public PostIdResponseDTO updatePost(Long postId, String email, PostRequestDTO po
postRequestDTO.getContent(),
postRequestDTO.getPostVisibility(),
category,
book
targetBook
);

updateBookRatingStats(targetBook);

return PostIdResponseDTO.builder()
.postId(post.getId())
.build();
Expand All @@ -333,6 +337,7 @@ public PostIdResponseDTO updatePost(Long postId, String email, PostRequestDTO po
public void deletePost(Long postId, String email){

Post post = getPost(postId);
Book book = post.getBook();

// 예외처리: 수정하는 사람과 게시글 주인이 같은지 확인 (본인의 게시글인지)
if (!post.getMember().getEmail().equals(email)) {
Expand All @@ -344,6 +349,8 @@ public void deletePost(Long postId, String email){

// 게시글 삭제
postRepository.delete(post);

updateBookRatingStats(book);
}


Expand Down Expand Up @@ -415,6 +422,15 @@ private void decrementLikeCount(Post post, LikeType likeType) {
}
}

// 책 평점 수정 메서드
private void updateBookRatingStats(Book book) {
long ratingCount = postRepository.countByBookAndRatingIsNotNull(book);
Double ratingAverage = postRepository.findAverageRatingByBook(book);

double finalAverage = (ratingAverage == null) ? 0.0 : Math.round(ratingAverage * 10) / 10.0;
book.updateRatingStats(finalAverage, (int) ratingCount);
}

/*
* 추천
*/
Expand Down
Loading
Loading