Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
3a43f64
[refactor] RecentSearchCreateManager Component로 변경 (#114)
buzz0331 Jul 31, 2025
010d27c
[feat] 책 전체 페이지수 및 총평 가능 여부 조회 api 구현 (#117)
buzz0331 Jul 31, 2025
c8406a1
[docs] 책 전체 페이지수 및 총평 가능 여부 조회 api 명세 (#117)
buzz0331 Jul 31, 2025
a382e97
[refactor] ErrorCode 통합 (#117)
buzz0331 Jul 31, 2025
1c1ed31
[refactor] 안쓰는 클래스 삭제 (#117)
buzz0331 Jul 31, 2025
f73d37a
[feat] 테스트용 메서드 어노테이션 (#117)
buzz0331 Jul 31, 2025
c64fdb2
[feat] ErrorCode HttpStatus 수정 (#117)
buzz0331 Jul 31, 2025
11e6a62
[feat] RoomShowMineQueryDto -> RoomQueryDto (#117)
buzz0331 Jul 31, 2025
26ccbd5
[feat] 함수형 인터페이스 패키지 분리 (#117)
buzz0331 Jul 31, 2025
eff5577
[feat] 필요한 dto 및 인터페이스 정의 (#117)
buzz0331 Jul 31, 2025
aade72a
[feat] 쿼리 선언 (#117)
buzz0331 Jul 31, 2025
966c81b
[feat] 서비스 구현 (#117)
buzz0331 Jul 31, 2025
1229f68
[feat] 마감임박 및 인기 방 조회 api (#117)
buzz0331 Jul 31, 2025
9c9f1e9
[refactor] 유저가 참여한 방은 조회되지 않도록 필터링 조건 추가 (#117)
buzz0331 Jul 31, 2025
b1b0eaf
[test] 마감임박/인기있는 모임방 조회 api 통합 테스트 (#117)
buzz0331 Jul 31, 2025
73a05b4
[refactor] 메서드 추출 (#117)
buzz0331 Jul 31, 2025
b949ef1
[refactor] 헬퍼 서비스 어노테이션 정의 (#117)
buzz0331 Jul 31, 2025
603d159
[feat] Transaction(readOnly) 어노테이션 (#117)
buzz0331 Jul 31, 2025
8ce0cd1
[refactor] 중복 검증 제거 (#117)
buzz0331 Jul 31, 2025
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
15 changes: 15 additions & 0 deletions src/main/java/konkuk/thip/common/annotation/HelperService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package konkuk.thip.common.annotation;

import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Service;

import java.lang.annotation.*;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Service
public @interface HelperService {

@AliasFor(annotation = Service.class)
String value() default "";
}
Comment on lines +8 to +15
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ public enum ErrorCode implements ResponseCode {
* 140000 : roomParticipant error
*/
ROOM_PARTICIPANT_NOT_FOUND(HttpStatus.NOT_FOUND, 140000, "존재하지 않는 RoomParticipant (방과 사용자 관계) 입니다."),
USER_NOT_BELONG_TO_ROOM(HttpStatus.BAD_REQUEST, 140001, "현재 모임방에 속하지 않는 유저입니다."),
ROOM_PARTICIPANT_ROLE_NOT_MATCH(HttpStatus.BAD_REQUEST, 140002, "일치하는 방에서의 사용자 역할이 없습니다."),
ROOM_JOIN_TYPE_NOT_MATCH(HttpStatus.BAD_REQUEST, 140003, "일치하는 방 참여 상태가 없습니다."),
USER_CANNOT_JOIN_OR_CANCEL(HttpStatus.BAD_REQUEST, 140004, "존재하지 않는 방은 참여하기 또는 취소하기가 불가능합니다."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,16 @@ public enum SwaggerResponseDescription {
))),
ROOM_PLAYING_DETAIL(new LinkedHashSet<>(Set.of(
BOOK_NOT_FOUND,
ROOM_NOT_FOUND
ROOM_NOT_FOUND,
ROOM_ACCESS_FORBIDDEN
))),
ROOM_GET_BOOK_PAGE(new LinkedHashSet<>(Set.of(
ROOM_NOT_FOUND,
BOOK_NOT_FOUND,
ROOM_ACCESS_FORBIDDEN
))),
ROOM_GET_DEADLINE_POPULAR(new LinkedHashSet<>(Set.of(
CATEGORY_NOT_MATCH
))),


Expand All @@ -101,7 +110,7 @@ public enum SwaggerResponseDescription {
USER_NOT_FOUND,
ROOM_NOT_FOUND,
BOOK_NOT_FOUND,
USER_NOT_BELONG_TO_ROOM
ROOM_ACCESS_FORBIDDEN
))),

// Vote
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package konkuk.thip.recentSearch.application.service.manager;

import konkuk.thip.common.annotation.HelperService;
import konkuk.thip.recentSearch.adapter.out.jpa.RecentSearchType;
import konkuk.thip.recentSearch.application.port.out.RecentSearchCommandPort;
import konkuk.thip.recentSearch.application.port.out.RecentSearchQueryPort;
import konkuk.thip.recentSearch.domain.RecentSearch;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@HelperService
@RequiredArgsConstructor
public class RecentSearchCreateManager {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public RecordSearchResponse search(RecordSearchQuery recordSearchQuery) {

Book book = bookCommandPort.findBookByRoomId(recordSearchQuery.roomId());
RoomParticipant roomParticipant = roomParticipantCommandPort.findByUserIdAndRoomIdOptional(recordSearchQuery.userId(), recordSearchQuery.roomId())
.orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_BELONG_TO_ROOM));
.orElseThrow(() -> new BusinessException(ErrorCode.ROOM_ACCESS_FORBIDDEN));

// cursor 파싱
Cursor cursor = Cursor.from(recordSearchQuery.nextCursor(), DEFAULT_PAGE_SIZE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public class RoomQueryController {
private final RoomGetMemberListUseCase roomGetMemberListUseCase;
private final RoomShowPlayingDetailViewUseCase roomShowPlayingDetailViewUseCase;
private final RoomShowMineUseCase roomShowMineUseCase;
private final RoomGetBookPageUseCase roomGetBookPageUseCase;
private final RoomGetDeadlinePopularUseCase roomGetDeadlinePopularUsecase;

@Operation(
summary = "방 검색",
Expand Down Expand Up @@ -123,4 +125,31 @@ public BaseResponse<RoomShowMineResponse> getMyRooms(
@RequestParam(value = "cursor", required = false) final String cursor) {
return BaseResponse.ok(roomShowMineUseCase.getMyRooms(userId, type, cursor));
}

@Operation(
summary = "책 전체 페이지수 및 총평 가능 여부 조회 (in 기록 작성 화면)",
description = "방 참여자가 책 기록을 남길 수 있는 최대 책 페이지 수와 총평 작성 가능 여부를 조회합니다."
)
@ExceptionDescription(ROOM_GET_BOOK_PAGE)
@GetMapping("/rooms/{roomId}/book-page")
public BaseResponse<RoomGetBookPageResponse> getBookPage(
@Parameter(description = "방 ID", example = "1") @PathVariable("roomId") final Long roomId,
@Parameter(hidden = true) @UserId final Long userId
) {
return BaseResponse.ok(roomGetBookPageUseCase.getBookPage(roomId, userId));
}

@Operation(
summary = "마감 임박 및 인기 방 조회",
description = "카테고리별로 마감 임박 방과 인기 방을 조회합니다."
)
@ExceptionDescription(ROOM_GET_DEADLINE_POPULAR)
@GetMapping("/rooms")
public BaseResponse<RoomGetDeadlinePopularResponse> getDeadlineAndPopularRoomList(
@Parameter(description = "카테고리 이름 (default : 문학)", example = "과학/IT")
@RequestParam(value = "category", defaultValue = "문학") final String category,
@Parameter(hidden = true) @UserId final Long userId
) {
return BaseResponse.ok(roomGetDeadlinePopularUsecase.getDeadlineAndPopularRoomList(category, userId));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package konkuk.thip.room.adapter.in.web.response;

public record RoomGetBookPageResponse(
int totalBookPage,
boolean isOverviewPossible
) {
public static RoomGetBookPageResponse of(int totalBookPage, boolean isOverviewPossible) {
return new RoomGetBookPageResponse(totalBookPage, isOverviewPossible);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package konkuk.thip.room.adapter.in.web.response;

import java.util.List;

public record RoomGetDeadlinePopularResponse(
List<RoomDto> deadlineRoomList,
List<RoomDto> popularRoomList
) {
public record RoomDto(
Long roomId,
String bookImageUrl,
String roomName,
int memberCount,
String deadlineDate
) {
}

public static RoomGetDeadlinePopularResponse of(List<RoomDto> deadlineRoomList, List<RoomDto> popularRoomList) {
return new RoomGetDeadlinePopularResponse(deadlineRoomList, popularRoomList);
}
}
14 changes: 12 additions & 2 deletions src/main/java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntity.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package konkuk.thip.room.adapter.out.jpa;

import com.google.common.annotations.VisibleForTesting;
import jakarta.persistence.*;
import konkuk.thip.book.adapter.out.jpa.BookJpaEntity;
import konkuk.thip.common.entity.BaseJpaEntity;
Expand All @@ -8,7 +9,6 @@

import java.time.LocalDate;

//TODO 방에 이방에 참여중인 인원수 추가
@Entity
@Table(name = "rooms")
@Getter
Expand Down Expand Up @@ -70,8 +70,18 @@ public RoomJpaEntity updateFrom(Room room) {
return this;
}

// 테스트 메서드 편의용
@VisibleForTesting
public void updateMemberCount(int memberCount) {
this.memberCount = memberCount;
}

@VisibleForTesting
public void updateStartDate(LocalDate localDate) {
this.startDate = localDate;
}

@VisibleForTesting
public void updateIsPublic(boolean isPublic) {
this.isPublic = isPublic;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

import konkuk.thip.common.util.Cursor;
import konkuk.thip.common.util.CursorBasedList;
import konkuk.thip.room.adapter.in.web.response.RoomRecruitingDetailViewResponse;
import konkuk.thip.room.adapter.in.web.response.RoomGetHomeJoinedListResponse;
import konkuk.thip.room.adapter.in.web.response.RoomRecruitingDetailViewResponse;
import konkuk.thip.room.adapter.in.web.response.RoomSearchResponse;
import konkuk.thip.room.adapter.out.mapper.RoomMapper;
import konkuk.thip.room.adapter.out.persistence.function.RoomQueryFunction;
import konkuk.thip.room.adapter.out.persistence.repository.RoomJpaRepository;
import konkuk.thip.room.application.port.out.RoomQueryPort;
import konkuk.thip.room.application.port.out.dto.RoomShowMineQueryDto;
import konkuk.thip.room.application.port.out.dto.RoomQueryDto;
import konkuk.thip.room.domain.Category;
import konkuk.thip.room.domain.Room;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
Expand All @@ -23,7 +24,6 @@
public class RoomQueryPersistenceAdapter implements RoomQueryPort {

private final RoomJpaRepository roomJpaRepository;
private final RoomMapper roomMapper;

@Override
public int countRecruitingRoomsByBookAndStartDateAfter(Long bookId, LocalDate currentDate) {
Expand All @@ -46,36 +46,31 @@ public Page<RoomGetHomeJoinedListResponse.RoomSearchResult> searchHomeJoinedRoom
}

@Override
public CursorBasedList<RoomShowMineQueryDto> findRecruitingRoomsUserParticipated(Long userId, Cursor cursor) {
public CursorBasedList<RoomQueryDto> findRecruitingRoomsUserParticipated(Long userId, Cursor cursor) {
return findRooms(userId, cursor, roomJpaRepository::findRecruitingRoomsUserParticipated);
}

@Override
public CursorBasedList<RoomShowMineQueryDto> findPlayingRoomsUserParticipated(Long userId, Cursor cursor) {
public CursorBasedList<RoomQueryDto> findPlayingRoomsUserParticipated(Long userId, Cursor cursor) {
return findRooms(userId, cursor, roomJpaRepository::findPlayingRoomsUserParticipated);
}

@Override
public CursorBasedList<RoomShowMineQueryDto> findPlayingAndRecruitingRoomsUserParticipated(Long userId, Cursor cursor) {
public CursorBasedList<RoomQueryDto> findPlayingAndRecruitingRoomsUserParticipated(Long userId, Cursor cursor) {
return findRooms(userId, cursor, roomJpaRepository::findPlayingAndRecruitingRoomsUserParticipated);
}

@Override
public CursorBasedList<RoomShowMineQueryDto> findExpiredRoomsUserParticipated(Long userId, Cursor cursor) {
public CursorBasedList<RoomQueryDto> findExpiredRoomsUserParticipated(Long userId, Cursor cursor) {
return findRooms(userId, cursor, roomJpaRepository::findExpiredRoomsUserParticipated);
}

@FunctionalInterface
private interface RoomQueryFunction {
List<RoomShowMineQueryDto> apply(Long userId, LocalDate lastLocalDate, Long lastId, int pageSize);
}

private CursorBasedList<RoomShowMineQueryDto> findRooms(Long userId, Cursor cursor, RoomQueryFunction queryFunction) {
private CursorBasedList<RoomQueryDto> findRooms(Long userId, Cursor cursor, RoomQueryFunction queryFunction) {
LocalDate lastLocalDate = cursor.isFirstRequest() ? null : cursor.getLocalDate(0);
Long lastId = cursor.isFirstRequest() ? null : cursor.getLong(1);
int pageSize = cursor.getPageSize();

List<RoomShowMineQueryDto> dtos = queryFunction.apply(userId, lastLocalDate, lastId, pageSize);
List<RoomQueryDto> dtos = queryFunction.apply(userId, lastLocalDate, lastId, pageSize);
return CursorBasedList.of(dtos, pageSize, roomShowMineQueryDto -> {
Cursor nextCursor = new Cursor(List.of(
roomShowMineQueryDto.endDate().toString(),
Expand All @@ -84,4 +79,16 @@ private CursorBasedList<RoomShowMineQueryDto> findRooms(Long userId, Cursor curs
return nextCursor.toEncodedString();
});
}

@Override
public List<RoomQueryDto> findRoomsByCategoryOrderByDeadline(Category category, int limit, Long userId) {
return roomJpaRepository.findRoomsByCategoryOrderByStartDateAsc(category.getValue(), limit, userId);
}

@Override
public List<RoomQueryDto> findRoomsByCategoryOrderByPopular(Category category, int limit, Long userId) {
return roomJpaRepository.findRoomsByCategoryOrderByMemberCount(category.getValue(), limit, userId);
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package konkuk.thip.room.adapter.out.persistence.function;

import konkuk.thip.room.application.port.out.dto.RoomQueryDto;

import java.time.LocalDate;
import java.util.List;

@FunctionalInterface
public interface RoomQueryFunction {
List<RoomQueryDto> apply(Long userId, LocalDate lastLocalDate, Long lastId, int pageSize);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import konkuk.thip.room.adapter.in.web.response.RoomRecruitingDetailViewResponse;
import konkuk.thip.room.adapter.in.web.response.RoomGetHomeJoinedListResponse;
import konkuk.thip.room.adapter.in.web.response.RoomSearchResponse;
import konkuk.thip.room.application.port.out.dto.RoomShowMineQueryDto;
import konkuk.thip.room.application.port.out.dto.RoomQueryDto;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

Expand All @@ -19,11 +19,15 @@ public interface RoomQueryRepository {

Page<RoomGetHomeJoinedListResponse.RoomSearchResult> searchHomeJoinedRooms(Long userId, LocalDate today, Pageable pageable);

List<RoomShowMineQueryDto> findRecruitingRoomsUserParticipated(Long userId, LocalDate dateCursor, Long roomIdCursor, int pageSize);
List<RoomQueryDto> findRecruitingRoomsUserParticipated(Long userId, LocalDate dateCursor, Long roomIdCursor, int pageSize);

List<RoomShowMineQueryDto> findPlayingRoomsUserParticipated(Long userId, LocalDate dateCursor, Long roomIdCursor, int pageSize);
List<RoomQueryDto> findPlayingRoomsUserParticipated(Long userId, LocalDate dateCursor, Long roomIdCursor, int pageSize);

List<RoomShowMineQueryDto> findPlayingAndRecruitingRoomsUserParticipated(Long userId, LocalDate dateCursor, Long roomIdCursor, int pageSize);
List<RoomQueryDto> findPlayingAndRecruitingRoomsUserParticipated(Long userId, LocalDate dateCursor, Long roomIdCursor, int pageSize);

List<RoomShowMineQueryDto> findExpiredRoomsUserParticipated(Long userId, LocalDate dateCursor, Long roomIdCursor, int pageSize);
List<RoomQueryDto> findExpiredRoomsUserParticipated(Long userId, LocalDate dateCursor, Long roomIdCursor, int pageSize);

List<RoomQueryDto> findRoomsByCategoryOrderByStartDateAsc(String category, int limit, Long userId);

List<RoomQueryDto> findRoomsByCategoryOrderByMemberCount(String category, int limit, Long userId);
}
Loading