From 68214cc4866499028e6e69c326ff70e946bb2547 Mon Sep 17 00:00:00 2001 From: zjhj0814 Date: Mon, 29 Dec 2025 14:46:14 +0900 Subject: [PATCH 1/3] =?UTF-8?q?refactor(migration):=20=EB=A0=88=EA=B1=B0?= =?UTF-8?q?=EC=8B=9C=20book=5Frecommend=20=ED=85=8C=EC=9D=B4=EB=B8=94=20?= =?UTF-8?q?=EB=93=9C=EB=A1=AD=20=EB=A7=88=EC=9D=B4=EA=B7=B8=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/db/migration/V20251129__drop_book_recommend.sql | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/main/resources/db/migration/V20251129__drop_book_recommend.sql diff --git a/src/main/resources/db/migration/V20251129__drop_book_recommend.sql b/src/main/resources/db/migration/V20251129__drop_book_recommend.sql new file mode 100644 index 00000000..3d3ceca2 --- /dev/null +++ b/src/main/resources/db/migration/V20251129__drop_book_recommend.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS book_recommend; \ No newline at end of file From 52150c4a3f02e590466c0f0160ae4b297ebb4e43 Mon Sep 17 00:00:00 2001 From: zjhj0814 Date: Mon, 29 Dec 2025 14:47:35 +0900 Subject: [PATCH 2/3] =?UTF-8?q?refactor(bookRecommend):=20=EC=B1=85=20?= =?UTF-8?q?=EC=B6=94=EC=B2=9C=20=EB=A0=88=EA=B1=B0=EC=8B=9C=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 사용하지 않는 책 추천 관련 코드 삭제 --- .../converter/ClubManagementConverter.java | 47 +------- .../internal/entity/BookRecommend.java | 56 --------- .../internal/entity/ClubMember.java | 26 +--- .../excepetion/ClubManagementErrorStatus.java | 3 - .../repository/BookRecommendRepository.java | 7 -- .../BookRecommendRepositoryCustom.java | 9 -- .../BookRecommendRepositoryCustomImpl.java | 43 ------- .../service/ClubManagementQueryFacade.java | 71 +---------- .../ClubBookRecommendCommandService.java | 82 ------------- .../query/ClubBookRecommendQueryService.java | 34 ------ .../ClubRecommendationController.java | 111 ------------------ .../web/dto/ClubRequestDTO.java | 29 +---- .../web/dto/ClubResponseDTO.java | 31 +---- 13 files changed, 20 insertions(+), 529 deletions(-) delete mode 100644 src/main/java/checkmo/clubManagement/internal/entity/BookRecommend.java delete mode 100644 src/main/java/checkmo/clubManagement/internal/repository/BookRecommendRepository.java delete mode 100644 src/main/java/checkmo/clubManagement/internal/repository/BookRecommendRepositoryCustom.java delete mode 100644 src/main/java/checkmo/clubManagement/internal/repository/BookRecommendRepositoryCustomImpl.java delete mode 100644 src/main/java/checkmo/clubManagement/internal/service/command/ClubBookRecommendCommandService.java delete mode 100644 src/main/java/checkmo/clubManagement/internal/service/query/ClubBookRecommendQueryService.java delete mode 100644 src/main/java/checkmo/clubManagement/web/controller/ClubRecommendationController.java diff --git a/src/main/java/checkmo/clubManagement/internal/converter/ClubManagementConverter.java b/src/main/java/checkmo/clubManagement/internal/converter/ClubManagementConverter.java index 18f74443..00dec387 100644 --- a/src/main/java/checkmo/clubManagement/internal/converter/ClubManagementConverter.java +++ b/src/main/java/checkmo/clubManagement/internal/converter/ClubManagementConverter.java @@ -1,20 +1,19 @@ package checkmo.clubManagement.internal.converter; -import static checkmo.clubManagement.ClubManagementExternalDTO.BasicInfo; -import static checkmo.clubManagement.ClubManagementExternalDTO.MembershipInfo; - -import checkmo.book.BookExternalDTO; -import checkmo.clubManagement.internal.entity.BookRecommend; import checkmo.clubManagement.internal.entity.Club; import checkmo.clubManagement.internal.entity.ClubMember; import checkmo.clubManagement.web.dto.ClubRequestDTO; import checkmo.clubManagement.web.dto.ClubResponseDTO; import checkmo.member.MemberExternalDTO; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import lombok.AccessLevel; -import lombok.NoArgsConstructor; + +import static checkmo.clubManagement.ClubManagementExternalDTO.BasicInfo; +import static checkmo.clubManagement.ClubManagementExternalDTO.MembershipInfo; @NoArgsConstructor(access = AccessLevel.PRIVATE) public class ClubManagementConverter { @@ -94,38 +93,4 @@ public static ClubResponseDTO.ClubDetail toClubDetailDTO(Club club, boolean isSt .build(); } - public static BookRecommend toBookRecommend( - ClubRequestDTO.CreateBookRecommend request, - String bookId, - ClubMember clubMember - ) { - return BookRecommend.builder() - .title(request.getTitle()) - .content(request.getContent()) - .rate(request.getRate()) - .tag(request.getTag()) - .clubMember(clubMember) - .bookId(bookId) - .build(); - } - - public static ClubResponseDTO.BookRecommendDetail toBookRecommendDetailDTO( - BookRecommend bookRecommend, - BookExternalDTO.BasicInfo bookInfo, - MemberExternalDTO.BasicInfo authorInfo, - String currentMemberNickname, - boolean isStaff - ) { - return ClubResponseDTO.BookRecommendDetail.builder() - .id(bookRecommend.getId()) - .title(bookRecommend.getTitle()) - .content(bookRecommend.getContent()) - .rate(bookRecommend.getRate()) - .tag(bookRecommend.getTag()) - .bookInfo(bookInfo) - .authorInfo(authorInfo) - .isAuthor(authorInfo.getNickname().equals(currentMemberNickname)) - .isStaff(isStaff) - .build(); - } } diff --git a/src/main/java/checkmo/clubManagement/internal/entity/BookRecommend.java b/src/main/java/checkmo/clubManagement/internal/entity/BookRecommend.java deleted file mode 100644 index a891ebc7..00000000 --- a/src/main/java/checkmo/clubManagement/internal/entity/BookRecommend.java +++ /dev/null @@ -1,56 +0,0 @@ -package checkmo.clubManagement.internal.entity; - -import checkmo.common.BaseEntity; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -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 lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Getter -@Builder -@AllArgsConstructor -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@Entity -public class BookRecommend extends BaseEntity { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - private String title; - - @Column(columnDefinition = "TEXT") - private String content; - - private double rate; - - private String tag; // 추천 태그 - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "club_member_id") - private ClubMember clubMember; - - @Column(name = "book_id", nullable = false) - private String bookId; - - public void updateRecommendInfo(String title, String content, double rate, String tag) { - this.title = title; - this.content = content; - this.rate = rate; - this.tag = tag; - } - - public boolean isWriter(Long clubMemberId) { - return this.clubMember.getId().equals(clubMemberId); - } - -} diff --git a/src/main/java/checkmo/clubManagement/internal/entity/ClubMember.java b/src/main/java/checkmo/clubManagement/internal/entity/ClubMember.java index 4f32690f..3e6a2081 100644 --- a/src/main/java/checkmo/clubManagement/internal/entity/ClubMember.java +++ b/src/main/java/checkmo/clubManagement/internal/entity/ClubMember.java @@ -1,26 +1,8 @@ package checkmo.clubManagement.internal.entity; import checkmo.common.BaseEntity; -import jakarta.persistence.CascadeType; -import jakarta.persistence.Column; -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.OneToMany; -import java.util.ArrayList; -import java.util.List; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; +import jakarta.persistence.*; +import lombok.*; @Getter @Builder @@ -47,10 +29,6 @@ public class ClubMember extends BaseEntity { @Column(name = "member_id", nullable = false) private String memberId; - @Builder.Default - @OneToMany(mappedBy = "clubMember", cascade = CascadeType.ALL) - private List bookRecommends = new ArrayList<>(); - public boolean isStaff() { return this.clubMemberStatus == ClubMemberStatus.STAFF; } diff --git a/src/main/java/checkmo/clubManagement/internal/excepetion/ClubManagementErrorStatus.java b/src/main/java/checkmo/clubManagement/internal/excepetion/ClubManagementErrorStatus.java index 190359b7..79407f57 100644 --- a/src/main/java/checkmo/clubManagement/internal/excepetion/ClubManagementErrorStatus.java +++ b/src/main/java/checkmo/clubManagement/internal/excepetion/ClubManagementErrorStatus.java @@ -22,9 +22,6 @@ public enum ClubManagementErrorStatus implements BaseErrorCode { CLUB_STAFF_CANNOT_LEAVE(HttpStatus.FORBIDDEN, "CLUB_MEMBER_405", "운영진은 클럽을 탈퇴할 수 없습니다."), CLUB_MEMBER_IS_NOT_ACTIVE(HttpStatus.FORBIDDEN, "CLUB_MEMBER_406", "해당 클럽 회원은 활성화 상태(STAFF, MEMBER)가 아닙니다."), - // 책 추천, - CLUB_BOOK_RECOMMEND_NOT_FOUND(HttpStatus.NOT_FOUND, "BOOK_RECOMMEND_400", "추천 책을 찾을 수 없습니다."), - CLUB_BOOK_RECOMMEND_FORBIDDEN(HttpStatus.FORBIDDEN, "BOOK_RECOMMEND_401", "해당 추천 책에 대한 권한이 없습니다."), ; private final HttpStatus httpStatus; diff --git a/src/main/java/checkmo/clubManagement/internal/repository/BookRecommendRepository.java b/src/main/java/checkmo/clubManagement/internal/repository/BookRecommendRepository.java deleted file mode 100644 index 00010904..00000000 --- a/src/main/java/checkmo/clubManagement/internal/repository/BookRecommendRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package checkmo.clubManagement.internal.repository; - -import checkmo.clubManagement.internal.entity.BookRecommend; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface BookRecommendRepository extends JpaRepository, BookRecommendRepositoryCustom { -} diff --git a/src/main/java/checkmo/clubManagement/internal/repository/BookRecommendRepositoryCustom.java b/src/main/java/checkmo/clubManagement/internal/repository/BookRecommendRepositoryCustom.java deleted file mode 100644 index 13917704..00000000 --- a/src/main/java/checkmo/clubManagement/internal/repository/BookRecommendRepositoryCustom.java +++ /dev/null @@ -1,9 +0,0 @@ -package checkmo.clubManagement.internal.repository; - -import checkmo.clubManagement.internal.entity.BookRecommend; -import java.util.List; - -public interface BookRecommendRepositoryCustom { - - List getBookRecommendsAndClubMemberByClubIdAndCursor(Long clubId, Long cursorId, Integer size); -} diff --git a/src/main/java/checkmo/clubManagement/internal/repository/BookRecommendRepositoryCustomImpl.java b/src/main/java/checkmo/clubManagement/internal/repository/BookRecommendRepositoryCustomImpl.java deleted file mode 100644 index 96337ef0..00000000 --- a/src/main/java/checkmo/clubManagement/internal/repository/BookRecommendRepositoryCustomImpl.java +++ /dev/null @@ -1,43 +0,0 @@ -package checkmo.clubManagement.internal.repository; - -import static checkmo.clubManagement.internal.entity.QBookRecommend.bookRecommend; - -import checkmo.clubManagement.internal.entity.BookRecommend; -import com.querydsl.core.BooleanBuilder; -import com.querydsl.jpa.impl.JPAQuery; -import com.querydsl.jpa.impl.JPAQueryFactory; -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Repository; - -@RequiredArgsConstructor -@Repository -public class BookRecommendRepositoryCustomImpl implements BookRecommendRepositoryCustom { - private final JPAQueryFactory queryFactory; - - @Override - public List getBookRecommendsAndClubMemberByClubIdAndCursor( - Long clubId, - Long cursorId, - Integer size - ) { - BooleanBuilder predicate = new BooleanBuilder(); - predicate.and(bookRecommend.clubMember.club.id.eq(clubId)); - - if (cursorId != null) { - predicate.and(bookRecommend.id.lt(cursorId)); - } - - JPAQuery query = queryFactory.selectFrom(bookRecommend) - .join(bookRecommend.clubMember) - .fetchJoin() - .where(predicate) - .orderBy(bookRecommend.id.desc()); - - if (size != null) { - query.limit(size); - } - - return query.fetch(); - } -} diff --git a/src/main/java/checkmo/clubManagement/internal/service/ClubManagementQueryFacade.java b/src/main/java/checkmo/clubManagement/internal/service/ClubManagementQueryFacade.java index 35b94036..f4d00dd5 100644 --- a/src/main/java/checkmo/clubManagement/internal/service/ClubManagementQueryFacade.java +++ b/src/main/java/checkmo/clubManagement/internal/service/ClubManagementQueryFacade.java @@ -1,45 +1,38 @@ package checkmo.clubManagement.internal.service; -import static checkmo.clubManagement.ClubManagementExternalDTO.BasicInfo; - -import checkmo.book.BookAPI; -import checkmo.book.BookExternalDTO; import checkmo.clubManagement.internal.converter.ClubManagementConverter; -import checkmo.clubManagement.internal.entity.BookRecommend; import checkmo.clubManagement.internal.entity.Club; import checkmo.clubManagement.internal.entity.ClubMember; import checkmo.clubManagement.internal.entity.ClubMember.ClubMemberStatus; import checkmo.clubManagement.internal.excepetion.ClubManagementErrorStatus; import checkmo.clubManagement.internal.excepetion.ClubManagementException; -import checkmo.clubManagement.internal.service.query.ClubBookRecommendQueryService; import checkmo.clubManagement.internal.service.query.ClubManagementQueryService; import checkmo.clubManagement.internal.service.query.ClubMemberQueryService; import checkmo.clubManagement.web.dto.ClubRequestDTO; import checkmo.clubManagement.web.dto.ClubResponseDTO; -import checkmo.clubManagement.web.dto.ClubResponseDTO.BookRecommendDetail; import checkmo.clubManagement.web.dto.ClubResponseDTO.ClubDetail; import checkmo.common.template.CursorPagingHelper; import checkmo.common.template.CursorResult; import checkmo.member.MemberAPI; import checkmo.member.MemberExternalDTO; -import java.util.List; -import java.util.Map; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import java.util.List; +import java.util.Map; + +import static checkmo.clubManagement.ClubManagementExternalDTO.BasicInfo; + @Service @RequiredArgsConstructor public class ClubManagementQueryFacade { - // 페이징 기본 크기 상수 private static final int DEFAULT_PAGE_SIZE = 10; private final MemberAPI memberAPI; - private final BookAPI bookAPI; private final ClubManagementQueryService clubManagementQueryService; private final ClubMemberQueryService clubMemberQueryService; - private final ClubBookRecommendQueryService clubBookRecommendQueryService; public ClubResponseDTO.ClubList retrieveClubList( String memberId, @@ -198,60 +191,6 @@ private List extractMemberIds(List clubMembers) { .toList(); } - public ClubResponseDTO.BookRecommendList retrieveBookRecommedList(Long clubId, Long cursorId, String memberId) { - clubManagementQueryService.validateClub(clubId); - ClubMember clubMember = clubMemberQueryService.validateClubMember(clubId, memberId); - String nickname = memberAPI.fetchMemberBasicInfo(memberId).getNickname(); - - CursorResult bookRecommendCursorResult = CursorPagingHelper.getPage( - pageSize -> clubBookRecommendQueryService.retrieveBookRecommends(clubId, cursorId, pageSize), - BookRecommend::getId, - DEFAULT_PAGE_SIZE - ); - List bookRecommends = bookRecommendCursorResult.content(); - - List bookRecommendDetails = bookRecommends.stream() - .map(bookRecommend -> { - var bookInfo = bookAPI.fetchBookBasicInfo(bookRecommend.getBookId()); - var authorInfo = memberAPI.fetchMemberBasicInfo(bookRecommend.getClubMember().getMemberId()); - return ClubManagementConverter.toBookRecommendDetailDTO(bookRecommend, bookInfo, authorInfo, - nickname, clubMember.isStaff()); - }).toList(); - - return ClubResponseDTO.BookRecommendList.builder() - .bookRecommendList(bookRecommendDetails) - .hasNext(bookRecommendCursorResult.hasNext()) - .nextCursor(bookRecommendCursorResult.nextCursor()) - .pageSize(bookRecommendDetails.size()) - .build(); - } - - public ClubResponseDTO.BookRecommendDetail retrieveBookRecommendDetail( - Long clubId, - Long bookRecommendId, - String memberId - ) { - ClubMember clubMember = clubMemberQueryService.validateClubMember(clubId, memberId); - - BookRecommend bookRecommend = clubBookRecommendQueryService.retrieveBookRecommend(clubId, bookRecommendId, - memberId); - - // 외부 도메인 정보 조회 (Facade에서 처리) - BookExternalDTO.BasicInfo bookInfo = bookAPI.fetchBookBasicInfo(bookRecommend.getBookId()); - MemberExternalDTO.BasicInfo authorInfo - = memberAPI.fetchMemberBasicInfo(bookRecommend.getClubMember().getMemberId()); - MemberExternalDTO.BasicInfo currentMemberInfo = memberAPI.fetchMemberBasicInfo(memberId); - - // 4. DTO 변환 후 반환 - return ClubManagementConverter.toBookRecommendDetailDTO( - bookRecommend, - bookInfo, - authorInfo, - currentMemberInfo.getNickname(), - clubMember.isStaff() - ); - } - public Boolean isClubMemberStaff(Long clubId, String memberId) { clubManagementQueryService.validateClub(clubId); ClubMember clubMember = clubMemberQueryService.validateClubMember(clubId, memberId); diff --git a/src/main/java/checkmo/clubManagement/internal/service/command/ClubBookRecommendCommandService.java b/src/main/java/checkmo/clubManagement/internal/service/command/ClubBookRecommendCommandService.java deleted file mode 100644 index a9a88993..00000000 --- a/src/main/java/checkmo/clubManagement/internal/service/command/ClubBookRecommendCommandService.java +++ /dev/null @@ -1,82 +0,0 @@ -package checkmo.clubManagement.internal.service.command; - -import checkmo.book.BookAPI; -import checkmo.clubManagement.internal.converter.ClubManagementConverter; -import checkmo.clubManagement.internal.entity.BookRecommend; -import checkmo.clubManagement.internal.entity.ClubMember; -import checkmo.clubManagement.internal.excepetion.ClubManagementErrorStatus; -import checkmo.clubManagement.internal.excepetion.ClubManagementException; -import checkmo.clubManagement.internal.repository.BookRecommendRepository; -import checkmo.clubManagement.internal.service.query.ClubManagementQueryService; -import checkmo.clubManagement.internal.service.query.ClubMemberQueryService; -import checkmo.clubManagement.web.dto.ClubRequestDTO; -import jakarta.transaction.Transactional; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor -public class ClubBookRecommendCommandService { - - // Domain level 1 - private final BookAPI bookAPI; - - private final ClubManagementQueryService clubManagementQueryService; - private final ClubMemberQueryService clubMemberQueryService; - - private final BookRecommendRepository bookRecommendRepository; - - @Transactional - public Long recommendBook(Long clubId, String memberId, ClubRequestDTO.CreateBookRecommend request) { - clubManagementQueryService.validateClub(clubId); - ClubMember clubMember = clubMemberQueryService.validateClubMember(clubId, memberId); - - String bookId = bookAPI.fetchOrCreateBook(request.getBookDetail()); - - BookRecommend bookRecommend = ClubManagementConverter.toBookRecommend(request, bookId, clubMember); - - BookRecommend savedRecommend = bookRecommendRepository.save(bookRecommend); - - return savedRecommend.getId(); - } - - @Transactional - public Long updateBookRecommend( - Long clubId, - String memberId, - Long bookRecommendId, - ClubRequestDTO.UpdateBookRecommend request - ) { - clubManagementQueryService.validateClub(clubId); - ClubMember clubMember = clubMemberQueryService.validateClubMember(clubId, memberId); - - // 2. 추천 책 조회 및 존재 여부 검증 - BookRecommend bookRecommend = bookRecommendRepository.findById(bookRecommendId) - .orElseThrow( - () -> new ClubManagementException(ClubManagementErrorStatus.CLUB_BOOK_RECOMMEND_NOT_FOUND)); - if (!bookRecommend.isWriter(clubMember.getId())) { - throw new ClubManagementException(ClubManagementErrorStatus.CLUB_BOOK_RECOMMEND_FORBIDDEN); - } - - bookRecommend.updateRecommendInfo(request.getTitle(), request.getContent(), request.getRate(), - request.getTag()); - - return bookRecommend.getId(); - } - - @Transactional - public void deleteBookRecommend(Long clubId, String memberId, Long bookRecommendId) { - clubManagementQueryService.validateClub(clubId); - ClubMember clubMember = clubMemberQueryService.validateClubMember(clubId, memberId); - - BookRecommend bookRecommend = bookRecommendRepository.findById(bookRecommendId) - .orElseThrow( - () -> new ClubManagementException(ClubManagementErrorStatus.CLUB_BOOK_RECOMMEND_NOT_FOUND)); - if (!bookRecommend.isWriter(clubMember.getId())) { - throw new ClubManagementException(ClubManagementErrorStatus.CLUB_BOOK_RECOMMEND_FORBIDDEN); - } - - bookRecommendRepository.delete(bookRecommend); - } - -} diff --git a/src/main/java/checkmo/clubManagement/internal/service/query/ClubBookRecommendQueryService.java b/src/main/java/checkmo/clubManagement/internal/service/query/ClubBookRecommendQueryService.java deleted file mode 100644 index cf2d2d08..00000000 --- a/src/main/java/checkmo/clubManagement/internal/service/query/ClubBookRecommendQueryService.java +++ /dev/null @@ -1,34 +0,0 @@ -package checkmo.clubManagement.internal.service.query; - -import checkmo.clubManagement.internal.entity.BookRecommend; -import checkmo.clubManagement.internal.excepetion.ClubManagementErrorStatus; -import checkmo.clubManagement.internal.excepetion.ClubManagementException; -import checkmo.clubManagement.internal.repository.BookRecommendRepository; -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@RequiredArgsConstructor -@Transactional(readOnly = true) -public class ClubBookRecommendQueryService { - - private final ClubManagementQueryService clubManagementQueryService; - private final ClubMemberQueryService clubMemberQueryService; - - private final BookRecommendRepository bookRecommendRepository; - - public BookRecommend retrieveBookRecommend(Long clubId, Long bookRecommendId, String memberId) { - clubManagementQueryService.validateClub(clubId); - clubMemberQueryService.validateClubMember(clubId, memberId); - - return bookRecommendRepository.findById(bookRecommendId) - .orElseThrow( - () -> new ClubManagementException(ClubManagementErrorStatus.CLUB_BOOK_RECOMMEND_NOT_FOUND)); - } - - public List retrieveBookRecommends(Long clubId, Long cursorId, Integer size) { - return bookRecommendRepository.getBookRecommendsAndClubMemberByClubIdAndCursor(clubId, cursorId, size); - } -} diff --git a/src/main/java/checkmo/clubManagement/web/controller/ClubRecommendationController.java b/src/main/java/checkmo/clubManagement/web/controller/ClubRecommendationController.java deleted file mode 100644 index 5d2ec20d..00000000 --- a/src/main/java/checkmo/clubManagement/web/controller/ClubRecommendationController.java +++ /dev/null @@ -1,111 +0,0 @@ -package checkmo.clubManagement.web.controller; - -import checkmo.authentication.CurrentId; -import checkmo.clubManagement.internal.service.ClubManagementQueryFacade; -import checkmo.clubManagement.internal.service.command.ClubBookRecommendCommandService; -import checkmo.clubManagement.web.dto.ClubRequestDTO; -import checkmo.clubManagement.web.dto.ClubResponseDTO; -import checkmo.common.apiPayload.ApiResponse; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PatchMapping; -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.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/api/clubs/{clubId}/recommendations") -@RequiredArgsConstructor -@Tag(name = "모임 추천 책", description = "독서 모임 내 책 추천 및 관리 API") -public class ClubRecommendationController { - - private final ClubManagementQueryFacade clubManagementQueryFacade; - private final ClubBookRecommendCommandService clubBookRecommendCommandService; - - @Operation(summary = "추천 책 작성", description = "특정 모임에 추천 책을 작성합니다.") - @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "성공"), - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "입력 값이 유효하지 않음") - }) - @PostMapping - public ApiResponse createRecommendation( - @PathVariable Long clubId, - @CurrentId String memberId, - @RequestBody @Valid ClubRequestDTO.CreateBookRecommend request - ) { - Long bookRecommendId = clubBookRecommendCommandService.recommendBook(clubId, memberId, request); - return ApiResponse.onSuccess(bookRecommendId + "가 정상적으로 추천되었습니다."); - } - - @Operation(summary = "추천 책 전체 조회", description = "해당 독서모임의 추천 책 목록을 커서 기반으로 조회합니다.") - @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "성공"), - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "클럽을 찾을 수 없음") - }) - @GetMapping - public ApiResponse getAllRecommendations( - @PathVariable Long clubId, - @RequestParam(required = false) Long cursorId, - @CurrentId String memberId - ) { - return ApiResponse.onSuccess(clubManagementQueryFacade.retrieveBookRecommedList(clubId, cursorId, memberId)); - } - - @Operation(summary = "추천 책 상세 조회", description = "추천 책 ID를 기반으로 상세 정보를 조회합니다.") - @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "성공"), - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "추천 책 또는 클럽을 찾을 수 없음") - }) - @GetMapping("/{recommendId}") - public ApiResponse getRecommendationDetail( - @PathVariable Long clubId, - @PathVariable Long recommendId, - @CurrentId String memberId - ) { - return ApiResponse.onSuccess( - clubManagementQueryFacade.retrieveBookRecommendDetail(clubId, recommendId, memberId)); - } - - @Operation(summary = "추천 책 수정", description = "추천 책의 소개 이유, 별점, 태그를 수정합니다. 책 자체는 변경할 수 없습니다.") - @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "성공"), - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "추천 책 또는 클럽을 찾을 수 없음"), - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "403", description = "작성자가 아님") - }) - @PatchMapping("/{recommendId}") - public ApiResponse updateRecommendation( - @PathVariable Long clubId, - @PathVariable Long recommendId, - @CurrentId String memberId, - @RequestBody @Valid ClubRequestDTO.UpdateBookRecommend request - ) { - Long updatedBookRecommend = clubBookRecommendCommandService.updateBookRecommend(clubId, memberId, recommendId, - request); - return ApiResponse.onSuccess(updatedBookRecommend + "가 정상적으로 수정되었습니다."); - } - - @Operation(summary = "추천 책 삭제", description = "추천 책을 삭제합니다. 작성자만 삭제할 수 있습니다.") - @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "성공"), - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "403", description = "작성자가 아님"), - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "추천 책 또는 클럽을 찾을 수 없음") - }) - @DeleteMapping("/{recommendId}") - public ApiResponse deleteRecommendation( - @PathVariable Long clubId, - @PathVariable Long recommendId, - @CurrentId String memberId - ) { - clubBookRecommendCommandService.deleteBookRecommend(clubId, memberId, recommendId); - return ApiResponse.onSuccess("책 추천이 정상적으로 삭제되었습니다."); - } - -} diff --git a/src/main/java/checkmo/clubManagement/web/dto/ClubRequestDTO.java b/src/main/java/checkmo/clubManagement/web/dto/ClubRequestDTO.java index 106b737f..325d8965 100644 --- a/src/main/java/checkmo/clubManagement/web/dto/ClubRequestDTO.java +++ b/src/main/java/checkmo/clubManagement/web/dto/ClubRequestDTO.java @@ -1,13 +1,13 @@ package checkmo.clubManagement.web.dto; -import checkmo.book.BookExternalDTO; import checkmo.clubManagement.internal.entity.Club; import checkmo.clubManagement.internal.entity.ClubInterestCategory; import jakarta.validation.constraints.NotBlank; -import java.util.List; import lombok.Getter; import lombok.NoArgsConstructor; +import java.util.List; + public class ClubRequestDTO { //TODO: 파라미터 @@ -15,9 +15,9 @@ public class ClubRequestDTO { /** * 클럽 검색 필터 * - * @param keyword 검색 키워드 - * @param name 클럽명 필터링 여부 (0: 선택 안함, 1: 선택해서 검색) - * @param region 지역 필터링 여부 (0: 선택 안함, 1: 선택해서 검색) + * @param keyword 검색 키워드 + * @param name 클럽명 필터링 여부 (0: 선택 안함, 1: 선택해서 검색) + * @param region 지역 필터링 여부 (0: 선택 안함, 1: 선택해서 검색) * @param participants 대상 필터링 여부 (0: 선택 안함, 1: 선택해서 검색) */ public record ClubSearchFilter(String keyword, Integer name, Integer region, Integer participants) { @@ -60,23 +60,4 @@ public static class ClubDetail { private String insta; private String kakao; } - - @Getter - @NoArgsConstructor - public static class CreateBookRecommend { - private String title; - private BookExternalDTO.BookCreate bookDetail; - private String content; - private double rate; - private String tag; - } - - @Getter - @NoArgsConstructor - public static class UpdateBookRecommend { - private String title; - private String content; - private double rate; - private String tag; - } } diff --git a/src/main/java/checkmo/clubManagement/web/dto/ClubResponseDTO.java b/src/main/java/checkmo/clubManagement/web/dto/ClubResponseDTO.java index 3ae56a9a..91cad325 100644 --- a/src/main/java/checkmo/clubManagement/web/dto/ClubResponseDTO.java +++ b/src/main/java/checkmo/clubManagement/web/dto/ClubResponseDTO.java @@ -1,15 +1,15 @@ package checkmo.clubManagement.web.dto; -import checkmo.book.BookExternalDTO; import checkmo.clubManagement.internal.entity.Club; import checkmo.clubManagement.internal.entity.ClubInterestCategory; import checkmo.member.MemberExternalDTO; -import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import java.util.List; + public class ClubResponseDTO { @Getter @@ -100,31 +100,4 @@ public static class ClubMember { private String joinMessage; // 회원의 가입 메시지, ClubMemberStatus가 PENDING인 경우에만 사용됨 private String clubMemberStatus; } - - @Getter - @NoArgsConstructor - @AllArgsConstructor - @Builder - public static class BookRecommendList { - private List bookRecommendList; - private boolean hasNext; - private Long nextCursor; - private int pageSize; - } - - @Getter - @NoArgsConstructor - @AllArgsConstructor - @Builder - public static class BookRecommendDetail { - private Long id; - private String title; - private String content; - private double rate; - private String tag; // 추천 태그 - private BookExternalDTO.BasicInfo bookInfo; - private MemberExternalDTO.BasicInfo authorInfo; - private boolean isAuthor; - private boolean isStaff; - } } From 4b576e717deb98d94a06a909c45d3be57d5da11f Mon Sep 17 00:00:00 2001 From: zjhj0814 Date: Tue, 30 Dec 2025 13:58:09 +0900 Subject: [PATCH 3/3] =?UTF-8?q?refactor(meetingCalendar):=20=ED=81=B4?= =?UTF-8?q?=EB=9F=BD=20=EC=A0=95=EA=B8=B0=EB=AA=A8=EC=9E=84=20=EC=BA=98?= =?UTF-8?q?=EB=A6=B0=EB=8D=94=20=EC=A1=B0=ED=9A=8C=20=EB=A0=88=EA=B1=B0?= =?UTF-8?q?=EC=8B=9C=20=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/ClubMeetingQueryFacade.java | 44 +++---------------- .../web/controller/ClubMeetingController.java | 32 +------------- 2 files changed, 7 insertions(+), 69 deletions(-) diff --git a/src/main/java/checkmo/clubMeeting/internal/service/ClubMeetingQueryFacade.java b/src/main/java/checkmo/clubMeeting/internal/service/ClubMeetingQueryFacade.java index d7802c5a..2ffcf37e 100644 --- a/src/main/java/checkmo/clubMeeting/internal/service/ClubMeetingQueryFacade.java +++ b/src/main/java/checkmo/clubMeeting/internal/service/ClubMeetingQueryFacade.java @@ -6,12 +6,7 @@ import checkmo.clubManagement.ClubManagementAPI; import checkmo.clubManagement.ClubManagementExternalDTO.MembershipInfo; import checkmo.clubMeeting.internal.converter.ClubMeetingConverter; -import checkmo.clubMeeting.internal.entity.BookReview; -import checkmo.clubMeeting.internal.entity.ClubMemberTeam; -import checkmo.clubMeeting.internal.entity.Meeting; -import checkmo.clubMeeting.internal.entity.Team; -import checkmo.clubMeeting.internal.entity.TeamTopic; -import checkmo.clubMeeting.internal.entity.Topic; +import checkmo.clubMeeting.internal.entity.*; import checkmo.clubMeeting.internal.exception.ClubMeetingErrorStatus; import checkmo.clubMeeting.internal.exception.ClubMeetingException; import checkmo.clubMeeting.internal.service.query.ClubBookReviewQueryService; @@ -21,37 +16,28 @@ import checkmo.clubMeeting.web.dto.bookshelf.BookShelfResponseDTO; import checkmo.clubMeeting.web.dto.bookshelf.BookShelfResponseDTO.BookShelfDetail; import checkmo.clubMeeting.web.dto.meeting.MeetingResponseDTO; -import checkmo.clubMeeting.web.dto.meeting.MeetingResponseDTO.MeetingInfo; import checkmo.common.template.CursorPagingHelper; import checkmo.common.template.CursorResult; import checkmo.member.MemberAPI; import checkmo.member.MemberExternalDTO; import checkmo.member.MemberExternalDTO.BasicInfo; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + @Service @RequiredArgsConstructor public class ClubMeetingQueryFacade { - // 페이징 기본 크기 상수 private static final int DEFAULT_PAGE_SIZE = 10; private static final int TOPIC_PREVIEW_SIZE_FOR_BOOKSHELF = 3; private static final int TOPIC_PREVIEW_SIZE_FOR_MEETING = 4; - // Domain level 2 - private final MemberAPI memberAPI; - - // Domain level 1 private final BookAPI bookAPI; - + private final MemberAPI memberAPI; private final ClubManagementAPI clubManagementAPI; private final ClubMeetingQueryService clubMeetingQueryService; @@ -300,24 +286,6 @@ public MeetingResponseDTO.TeamTopic retrieveTeamTopic(Long meetingId, Integer te .build(); } - public MeetingResponseDTO.CalendarMeeting retrieveCalendarMeeting( - Long clubId, - int year, - int month, - String memberId - ) { - clubManagementAPI.validateClub(clubId); - MembershipInfo clubMembershipInfoInfo = clubManagementAPI.fetchMembershipInfo(clubId, memberId); - - List meetings = clubMeetingQueryService.retrieveMeetings(clubId, year, month, memberId); - - List meetingInfoDTOList = toMeetingInfoDTOList(meetings); - return MeetingResponseDTO.CalendarMeeting.builder() - .meetingInfoList(meetingInfoDTOList) - .membershipInfo(clubMembershipInfoInfo) - .build(); - } - public MeetingResponseDTO.MeetingMemberList retrieveMeetingMemberList( Long meetingId, Long cursorId, diff --git a/src/main/java/checkmo/clubMeeting/web/controller/ClubMeetingController.java b/src/main/java/checkmo/clubMeeting/web/controller/ClubMeetingController.java index 371f88a8..0d16b5df 100644 --- a/src/main/java/checkmo/clubMeeting/web/controller/ClubMeetingController.java +++ b/src/main/java/checkmo/clubMeeting/web/controller/ClubMeetingController.java @@ -14,19 +14,10 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; -import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; import lombok.RequiredArgsConstructor; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PatchMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; @RestController @RequestMapping() @@ -120,27 +111,6 @@ public ApiResponse getMeetingDetail( return ApiResponse.onSuccess(meetingDetail); } - @Operation(summary = "독서모임 캘린더 조회 API", description = "독서모임의 모임 캘린더를 조회합니다.") - @Parameters({ - @Parameter(name = "clubId", description = "독서클럽 ID", required = true, example = "1"), - @Parameter(name = "year", description = "조회하고자 하는 연도", required = true, example = "2023"), - @Parameter(name = "month", description = "조회하고자 하는 달", required = true, example = "10") - }) - @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "성공"), - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "403", description = "해당 클럽의 회원이 아닙니다."), - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "독서클럽을 찾을 수 없습니다."), - }) - @GetMapping("/api/clubs/{clubId}/calendar") - public ApiResponse getClubCalendar( - @PathVariable Long clubId, - @RequestParam @Min(2000) @Max(2050) int year, - @RequestParam @Min(1) @Max(12) int month, - @CurrentId String memberId - ) { - return ApiResponse.onSuccess(clubMeetingQueryFacade.retrieveCalendarMeeting(clubId, year, month, memberId)); - } - @Operation(summary = "독서 동아리 회원 중 참여 인원 페이지네이션 조회 API", description = "[모임] 페이지 - 독서클럽의 모든 회원 정보(STAFF, MEMBER)와 함께, 해당 미팅에 배정된 팀 번호까지 페이지네이션 조회합니다. " + "만약 팀 번호가 null이면 아직 아무 팀에도 배정되지 않은 것입니다.")