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
2 changes: 2 additions & 0 deletions .coderabbit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ reviews:
auto_review:
enabled: true
drafts: false
base_branches:
- ".*"
profile: "assertive"
request_changes_workflow: false
high_level_summary: true
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,5 @@ pinpoint-agent/tools/

# macOS artefacts
.DS_Store

docs/
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.project.dorumdorum.domain.room.domain.service.RoomRequestService;
import com.project.dorumdorum.domain.room.domain.service.RoomService;
import com.project.dorumdorum.domain.roommate.domain.service.RoommateService;
import com.project.dorumdorum.domain.user.domain.entity.User;
import com.project.dorumdorum.domain.user.domain.service.UserService;
import com.project.dorumdorum.global.exception.RestApiException;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -34,10 +35,12 @@ public class ApplyRoomUseCase {
* - 지원 요청을 생성하고 1:1 채팅방 생성 이벤트를 발행
*/
public String execute(String userNo, String roomNo, JoinRoomRequest request) {
userService.validateExistsById(userNo);

User applicant = userService.findById(userNo);
Room room = roomService.findById(roomNo);

if (!applicant.getGender().equals(room.getGender())) {
throw new RestApiException(GENDER_MISMATCH);
Comment thread
ydking0911 marked this conversation as resolved.
}
if (roommateService.isUserRoommate(userNo, roomNo)) {
throw new RestApiException(CANNOT_APPLY_TO_OWN_ROOM);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,21 @@
import com.project.dorumdorum.domain.room.domain.service.RoomService;
import com.project.dorumdorum.domain.roommate.domain.entity.RoomRole;
import com.project.dorumdorum.domain.roommate.domain.service.RoommateService;
import com.project.dorumdorum.domain.user.domain.entity.Gender;
import com.project.dorumdorum.domain.user.domain.service.UserService;
import com.project.dorumdorum.global.exception.RestApiException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import static com.project.dorumdorum.global.exception.code.status.RoomErrorStatus.ALREADY_JOINED_USER;

@Service
@Transactional
@RequiredArgsConstructor
public class CreateRoomUseCase {

private final UserService userService;
private final RoomService roomService;
private final RoommateService roommateService;
private final RoomRuleService roomRuleService;
Expand All @@ -29,7 +35,11 @@ public class CreateRoomUseCase {
* - 생성된 방 번호를 반환
*/
public String execute(String userNo, RoomCreateRequest request) {
Room room = roomService.create(userNo, request);
if (roommateService.existsByUserNo(userNo)) {
throw new RestApiException(ALREADY_JOINED_USER);
}
Gender gender = userService.findById(userNo).getGender();
Room room = roomService.create(userNo, gender, request);
Comment thread
ydking0911 marked this conversation as resolved.
roommateService.create(userNo, room, RoomRole.HOST);

RoomRule roomRule = roomRuleMapper.toRoomRule(room, request.rule());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.project.dorumdorum.domain.room.application.dto.request.ChecklistFilterRequest;
import com.project.dorumdorum.domain.room.application.dto.response.FindRoomsResponse;
import com.project.dorumdorum.domain.room.domain.service.RoomService;
import com.project.dorumdorum.domain.user.domain.entity.Gender;
import com.project.dorumdorum.domain.user.domain.service.UserService;
import com.project.dorumdorum.global.pagination.CursorCodec;
import com.project.dorumdorum.global.pagination.CursorPage;
import com.project.dorumdorum.global.pagination.CursorQueryParams;
Expand All @@ -18,6 +20,7 @@
@Transactional(readOnly = true)
public class FindRoomsUseCase {

private final UserService userService;
private final RoomService roomService;
private static final int LIMIT = 50;

Expand All @@ -26,10 +29,12 @@ public class FindRoomsUseCase {
* - 필터와 커서 기준으로 방 목록을 조회
* - 다음 페이지 커서를 포함한 결과를 반환
*/
public CursorPage<FindRoomsResponse> execute(ChecklistFilterRequest request) {
public CursorPage<FindRoomsResponse> execute(String userNo, ChecklistFilterRequest request) {
Gender gender = userService.findById(userNo).getGender();
CursorQueryParams params = PaginationHelper.prepareCursorQuery(request.cursor(), LIMIT);

List<FindRoomsResponse> responses = roomService.searchByCursor(
gender,
Comment thread
ydking0911 marked this conversation as resolved.
request,
params.cursorCreatedAt(),
params.cursorId(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.project.dorumdorum.domain.room.domain.entity;

import com.project.dorumdorum.domain.user.domain.entity.Gender;
import com.project.dorumdorum.global.common.BaseEntity;
import io.hypersistence.utils.hibernate.id.Tsid;
import jakarta.persistence.*;
Expand All @@ -12,8 +13,8 @@
@Builder
@Table(
indexes = {
@Index(name = "idx_room_status_created", columnList = "room_status, created_at, room_no"),
@Index(name = "idx_room_status_remaining_created", columnList = "room_status, remaining, created_at DESC, room_no DESC"),
@Index(name = "idx_room_status_gender_created", columnList = "room_status, gender, created_at DESC, room_no DESC"),
@Index(name = "idx_room_status_gender_remaining_created", columnList = "room_status, gender, remaining ASC, created_at DESC, room_no DESC"),
@Index(name = "idx_room_residence_period", columnList = "residence_period"),
@Index(name = "idx_room_host_user_no", columnList = "host_user_no")
}
Expand Down Expand Up @@ -49,6 +50,10 @@ public class Room extends BaseEntity {
@Column(nullable = false)
private String hostUserNo;

@Enumerated(EnumType.STRING)
@Column(nullable = false)
private Gender gender;

@Column(nullable = false)
@Enumerated(EnumType.STRING)
private ResidencePeriod residencePeriod; // 거주기간 (예: "학기(16주)", "반기(24주)", "계절학기")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.project.dorumdorum.domain.room.application.dto.request.ChecklistFilterRequest;
import com.project.dorumdorum.domain.room.application.dto.response.FindRoomsResponse;
import com.project.dorumdorum.domain.user.domain.entity.Gender;

import java.time.LocalDateTime;
import java.util.List;
Expand All @@ -10,6 +11,7 @@
public interface RoomQueryRepository {

List<FindRoomsResponse> findByCursor(
Gender gender,
ChecklistFilterRequest request,
LocalDateTime cursorCreatedAt,
String cursorId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.project.dorumdorum.domain.room.application.dto.response.FindRoomsResponse;
import com.project.dorumdorum.domain.room.domain.entity.Room;
import com.project.dorumdorum.domain.room.domain.repository.RoomRepository;
import com.project.dorumdorum.domain.user.domain.entity.Gender;
import com.project.dorumdorum.global.exception.RestApiException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
Expand All @@ -21,13 +22,14 @@ public class RoomService {

private final RoomRepository roomRepository;

public Room create(String userNo, RoomCreateRequest request) {
public Room create(String userNo, Gender gender, RoomCreateRequest request) {
Room entity = Room.builder()
.capacity(request.capacity())
.roomType(request.roomType())
.residencePeriod(request.residencePeriod())
.title(request.title())
.hostUserNo(userNo)
.gender(gender)
.build();

return roomRepository.save(entity);
Expand All @@ -44,13 +46,14 @@ public Room findByIdForUpdate(String roomNo) {
}

public List<FindRoomsResponse> searchByCursor(
Gender gender,
ChecklistFilterRequest request,
LocalDateTime cursorCreatedAt,
String cursorId,
Integer cursorRemaining,
int limitPlusOne
) {
return roomRepository.findByCursor(request, cursorCreatedAt, cursorId, cursorRemaining, limitPlusOne);
return roomRepository.findByCursor(gender, request, cursorCreatedAt, cursorId, cursorRemaining, limitPlusOne);
}

public FindRoomsResponse findMyRoom(String userNo) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.project.dorumdorum.domain.room.domain.entity.RoomType;
import com.project.dorumdorum.domain.room.domain.entity.RoomStatus;
import com.project.dorumdorum.domain.room.domain.repository.RoomQueryRepository;
import com.project.dorumdorum.domain.user.domain.entity.Gender;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.JPAExpressions;
import com.querydsl.jpa.impl.JPAQuery;
Expand Down Expand Up @@ -38,14 +39,15 @@ public class RoomRepositoryImpl implements RoomQueryRepository {

@Override
public List<FindRoomsResponse> findByCursor(
Gender gender,
ChecklistFilterRequest request,
LocalDateTime cursorCreatedAt,
String cursorId,
Integer cursorRemaining,
int limitPlusOne
) {
if (hasChecklistFilters(request)) {
return findByCursorWithLateral(request, cursorCreatedAt, cursorId, cursorRemaining, limitPlusOne);
return findByCursorWithLateral(gender, request, cursorCreatedAt, cursorId, cursorRemaining, limitPlusOne);
}

JPAQuery<FindRoomsResponse> q = query
Expand All @@ -67,6 +69,7 @@ public List<FindRoomsResponse> findByCursor(
.leftJoin(user).on(user.userNo.eq(room.hostUserNo))
.where(
room.roomStatus.eq(RoomStatus.CONFIRM_PENDING),
room.gender.eq(gender),
eqRoomType(request),
eqResidencePeriod(request),
eqCapacity(request),
Expand All @@ -85,6 +88,7 @@ public List<FindRoomsResponse> findByCursor(
}

private List<FindRoomsResponse> findByCursorWithLateral(
Gender gender,
ChecklistFilterRequest request,
LocalDateTime cursorCreatedAt,
String cursorId,
Expand Down Expand Up @@ -143,8 +147,10 @@ JOIN LATERAL (
LEFT JOIN users u
ON u.user_no = r.host_user_no
WHERE r.room_status = :roomStatus
AND r.gender = :gender
""");
params.put("roomStatus", RoomStatus.CONFIRM_PENDING.name());
params.put("gender", gender.name());
Comment thread
ydking0911 marked this conversation as resolved.

appendCondition(sql, params, "r.room_type", "roomType", enumName(request.roomType()));
appendCondition(sql, params, "r.residence_period", "residencePeriod", enumName(request.residencePeriod()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.project.dorumdorum.domain.room.application.dto.response.FindRoomsResponse;
import com.project.dorumdorum.domain.room.application.usecase.FindRoomsUseCase;
import com.project.dorumdorum.domain.room.ui.spec.FindRoomsApiSpec;
import com.project.dorumdorum.global.annotation.CurrentUser;
import org.springframework.http.ResponseEntity;
import com.project.dorumdorum.global.pagination.CursorPage;
import jakarta.validation.Valid;
Expand All @@ -19,8 +20,9 @@ public class FindRoomsController implements FindRoomsApiSpec {

@Override
public ResponseEntity<CursorPage<FindRoomsResponse>> loadAll(
@CurrentUser String userNo,
@Valid @RequestBody ChecklistFilterRequest request
) {
return ResponseEntity.ok(findRoomsUseCase.execute(request));
return ResponseEntity.ok(findRoomsUseCase.execute(userNo, request));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ public interface FindRoomsApiSpec {
@Operation(
summary = "방 목록 조회 API",
description = "체크리스트 및 방 조건을 기준으로 방 목록을 조회합니다. "
+ "커서 기반 페이지네이션을 지원합니다."
+ "커서 기반 페이지네이션을 지원합니다. "
+ "로그인한 사용자의 성별과 일치하는 방만 반환합니다."
)
@PostMapping("/api/rooms/search")
ResponseEntity<CursorPage<FindRoomsResponse>> loadAll(
@Parameter(hidden = true) String userNo,
@Parameter(description = "체크리스트 기반 방 검색 조건", required = true)
@Valid @RequestBody ChecklistFilterRequest request
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public class User extends BaseEntity {

private Integer age;

@Column(nullable = false)
@Enumerated(EnumType.STRING)
private Gender gender;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public enum RoomErrorStatus implements BaseCodeInterface {
CANNOT_KICK_SELF(HttpStatus.BAD_REQUEST, "ROOM012", "자기 자신은 강퇴할 수 없습니다."),
ROOM_FULL(HttpStatus.BAD_REQUEST, "ROOM014", "방 정원이 가득 찼습니다."),
INVALID_ROOM_CAPACITY(HttpStatus.BAD_REQUEST, "ROOM015", "현재 인원보다 적은 정원으로 변경할 수 없습니다."),
GENDER_MISMATCH(HttpStatus.FORBIDDEN, "ROOM016", "성별이 다른 방에는 신청할 수 없습니다."),
;

private final HttpStatus httpStatus;
Expand Down
10 changes: 8 additions & 2 deletions src/main/resources/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,16 @@ CREATE UNIQUE INDEX IF NOT EXISTS uk_device_user_device
CREATE UNIQUE INDEX IF NOT EXISTS uk_room_request_user_room_direction
ON room_request (user_no, room_no, direction);

ALTER TABLE IF EXISTS users
ALTER COLUMN gender SET NOT NULL;

DROP INDEX IF EXISTS idx_room_status_created;
DROP INDEX IF EXISTS idx_room_status_remaining_created;

CREATE INDEX IF NOT EXISTS idx_room_status_remaining_created
ON room (room_status, remaining, created_at DESC, room_no DESC);
CREATE INDEX IF NOT EXISTS idx_room_status_gender_created
ON room (room_status, gender, created_at DESC, room_no DESC);
CREATE INDEX IF NOT EXISTS idx_room_status_gender_remaining_created
ON room (room_status, gender, remaining ASC, created_at DESC, room_no DESC);
Comment thread
ydking0911 marked this conversation as resolved.

ALTER TABLE IF EXISTS chat_room
DROP CONSTRAINT IF EXISTS uk_chat_room_direct;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.project.dorumdorum.domain.roommate.domain.entity.RoomRole;
import com.project.dorumdorum.domain.roommate.domain.entity.Roommate;
import com.project.dorumdorum.domain.roommate.domain.repository.RoommateRepository;
import com.project.dorumdorum.domain.user.domain.entity.Gender;
import com.project.dorumdorum.domain.user.domain.entity.Role;
import com.project.dorumdorum.domain.user.domain.entity.User;
import com.project.dorumdorum.domain.user.domain.service.UserService;
Expand Down Expand Up @@ -117,6 +118,7 @@ void setUp() {
.title("원자성 테스트 방")
.hostUserNo(HOST_NO)
.residencePeriod(ResidencePeriod.SEMESTER)
.gender(Gender.MALE)
.build()
);

Expand Down
Loading
Loading