Skip to content

Commit

Permalink
Refact/#207 chatroom domain (#214)
Browse files Browse the repository at this point in the history
* [LOG] 채팅 웹 소켓 로그 추가

* [FEAT] ChatRoom User 매핑 테이블 구현

* [REFACT] 채팅방 ID UUID 타입 변경

* [REFACT] 채팅방 생성 로직 추가

* [REFACT] 채팅방 조회 검증 로직 리펙토링

* [REFACT] 채팅방 리스트 페이지네이션 적용 및 쿼리 최적화

* [RENAME] `projectJoinRequestRes` -> `ProjectJoinRequestRes`

* [FEAT] flyway V2 추가

* [REFACT] 채팅방 리스트 조회 로직 변경

---------

Co-authored-by: happyjamy <[email protected]>
Co-authored-by: JIN-076 <[email protected]>
  • Loading branch information
3 people authored Mar 6, 2024
1 parent 772f66e commit bde6dfe
Show file tree
Hide file tree
Showing 29 changed files with 369 additions and 220 deletions.
21 changes: 21 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
services:
mogakgo-db:
image: mysql:8.2.0
container_name: mogakgo-mysql
environment:
MYSQL_ROOT_PASSWORD: root!
MYSQL_DATABASE: mogakgo
ports:
- "3306:3306"
mogakgo-redis:
image: redis:latest
container_name: mogakgo-redis
ports:
- "6379:6379"
mogakgo-mongodb:
image: mongo:latest
container_name: mogakgo-mongodb
environment:
MONGI_INIT_DATABSE: mogakgo
ports:
- "27017:27017"
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import jakarta.validation.constraints.NotNull;
import java.util.Objects;
import lombok.Getter;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.lang.Nullable;

Expand All @@ -17,7 +16,7 @@ public class CursorPaginationInfoReq {
private final int pageSize;

@Nullable
private final Sort.Direction sortOrder;
private final Direction sortOrder;

public CursorPaginationInfoReq(@Nullable Long cursorId, int pageSize, Direction sortOrder) {
this.cursorId = cursorId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import org.springframework.http.ResponseEntity;

@Tag(name = "Chat", description = "채팅 관련 API")
Expand All @@ -38,7 +37,14 @@ public interface ChatSwagger {
examples = @ExampleObject(name = "E020301", value = SwaggerUserErrorExamples.USER_NOT_FOUND)
))
})
ResponseEntity<List<ChatRoomPublicRes>> getChatRoomList(@Parameter(hidden = true) Long userId);
@Parameters({
@Parameter(name = "cursorId", description = "기준이 되는 커서 ID", example = "1"),
@Parameter(name = "pageSize", description = "요청할 데이터 크기", example = "5", required = true),
@Parameter(name = "sortOrder", description = "정렬 방향", example = "ASC"),
})
ResponseEntity<CursorPaginationResult<ChatRoomPublicRes>> getChatRoomList(
@Parameter(hidden = true) Long userId,
@Parameter(hidden = true) CursorPaginationInfoReq pageable);

@Operation(summary = "채팅방 상세 조회", description = "채팅방의 상세 정보를 조회하는 API")
@ApiResponses(value = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
import io.oeid.mogakgo.core.properties.swagger.error.SwaggerProjectErrorExamples;
import io.oeid.mogakgo.core.properties.swagger.error.SwaggerUserErrorExamples;
import io.oeid.mogakgo.domain.geo.domain.enums.Region;
import io.oeid.mogakgo.domain.project.presentation.dto.req.ProjectCreateReq;
import io.oeid.mogakgo.domain.project.presentation.dto.res.ProjectDensityRankRes;
import io.oeid.mogakgo.domain.project.presentation.dto.res.ProjectDetailAPIRes;
import io.oeid.mogakgo.domain.project.presentation.dto.req.ProjectCreateReq;
import io.oeid.mogakgo.domain.project.presentation.dto.res.ProjectIdRes;
import io.oeid.mogakgo.domain.project.presentation.dto.res.ProjectInfoAPIRes;
import io.oeid.mogakgo.domain.project_join_req.presentation.dto.res.projectJoinRequestRes;
import io.oeid.mogakgo.domain.project_join_req.presentation.dto.res.ProjectJoinRequestRes;
import io.oeid.mogakgo.exception.dto.ErrorResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
Expand Down Expand Up @@ -168,7 +168,7 @@ ResponseEntity<CursorPaginationResult<ProjectDetailAPIRes>> getRandomOrderedProj
@Parameter(name = "pageSize", description = "요청할 데이터 크기", example = "5", required = true),
@Parameter(name = "sortOrder", description = "정렬 방향", example = "ASC"),
})
ResponseEntity<CursorPaginationResult<projectJoinRequestRes>> getJoinRequest(
ResponseEntity<CursorPaginationResult<ProjectJoinRequestRes>> getJoinRequest(
@Parameter(hidden = true) Long userId,
@Parameter(description = "프로젝트 ID", required = true) Long id,
@Parameter(hidden = true) CursorPaginationInfoReq pageable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,19 @@

import io.oeid.mogakgo.common.base.CursorPaginationInfoReq;
import io.oeid.mogakgo.common.base.CursorPaginationResult;
import io.oeid.mogakgo.domain.chat.application.dto.req.ChatRoomCreateReq;
import io.oeid.mogakgo.domain.chat.application.dto.res.ChatDataRes;
import io.oeid.mogakgo.domain.chat.application.dto.res.ChatRoomCreateRes;
import io.oeid.mogakgo.domain.chat.application.dto.res.ChatRoomDataRes;
import io.oeid.mogakgo.domain.chat.application.dto.res.ChatRoomPublicRes;
import io.oeid.mogakgo.domain.chat.entity.ChatRoom;
import io.oeid.mogakgo.domain.chat.infrastructure.ChatRepository;
import io.oeid.mogakgo.domain.chat.infrastructure.ChatRoomRoomJpaRepository;
import io.oeid.mogakgo.domain.chat.infrastructure.ChatUserJpaRepository;
import io.oeid.mogakgo.domain.matching.exception.MatchingException;
import io.oeid.mogakgo.domain.project.domain.entity.Project;
import io.oeid.mogakgo.domain.project.exception.ProjectException;
import io.oeid.mogakgo.domain.project.infrastructure.ProjectJpaRepository;
import io.oeid.mogakgo.domain.user.application.UserCommonService;
import io.oeid.mogakgo.domain.user.domain.User;
import io.oeid.mogakgo.exception.code.ErrorCode404;
import java.util.List;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
Expand All @@ -31,55 +28,59 @@ public class ChatService {

private final UserCommonService userCommonService;
private final ChatRoomRoomJpaRepository chatRoomRepository;
private final ChatUserJpaRepository chatUserRepository;
private final ChatRepository chatRepository;
private final ProjectJpaRepository projectRepository;

// 채팅방 리스트 조회
// TODO 마지막 채팅 기록 가져오기 구현
public List<ChatRoomPublicRes> findAllChatRoomByUserId(Long userId) {
findUserById(userId);
return chatRoomRepository.findAllChatRoomByUserId(userId);
public CursorPaginationResult<ChatRoomPublicRes> findAllChatRoomByUserId(Long userId,
CursorPaginationInfoReq pageable) {
log.info("findAllChatRoomByUserId - userId: {}", userId);
var chatRoomList = chatRoomRepository.getChatRoomList(userId, pageable.getCursorId(),
pageable.getPageSize());
var result = chatRoomList.stream().map(
chatRoom -> {
var user = chatRoom.getOppositeUser(userId);
ChatRoomPublicRes res = ChatRoomPublicRes.of(chatRoom, user);
var chatMessage = chatRepository.findLastChatByCollection(
chatRoom.getId().toString());
chatMessage.ifPresent(
message -> res.addLastMessage(message.getMessage(), message.getCreatedAt()));
return res;
}
).toList();
return CursorPaginationResult.fromDataWithExtraItemForNextCheck(result,
pageable.getPageSize());
}

// 채팅방 생성
@Transactional
public ChatRoomCreateRes createChatRoom(Long creatorId, ChatRoomCreateReq request) {
Project project = projectRepository.findById(request.getProjectId())
.orElseThrow(() -> new MatchingException(ErrorCode404.PROJECT_NOT_FOUND));
User creator = findUserById(creatorId);
User sender = findUserById(request.getSenderId());
ChatRoom chatRoom = chatRoomRepository.save(
ChatRoom.builder().project(project).creator(creator).sender(sender).build());
chatRepository.createCollection(chatRoom.getId());
return ChatRoomCreateRes.from(chatRoom);
public void createChatRoom(Project project, User creator, User sender) {
ChatRoom chatRoom = chatRoomRepository.save(new ChatRoom(project));
chatUserRepository.save(chatRoom.join(creator));
chatUserRepository.save(chatRoom.join(sender));
chatRepository.createCollection(chatRoom.getId().toString());
}

@Transactional
public void leaveChatroom(Long userId, String chatRoomId) {
var user = findUserById(userId);
var chatRoom = findChatRoomById(chatRoomId);

chatRoom.leaveUser(user);
// 채팅방 비활성화
chatRoom.closeChat();

chatRoom.leave(user);
}

// 채팅방 조회
public CursorPaginationResult<ChatDataRes> findAllChatInChatRoom(Long userId, String chatRoomId, CursorPaginationInfoReq pageable) {
var user = findUserById(userId);
var chatRoom = findChatRoomById(chatRoomId);
chatRoom.validateContainsUser(user);
public CursorPaginationResult<ChatDataRes> findAllChatInChatRoom(Long userId, String chatRoomId,
CursorPaginationInfoReq pageable) {
verifyChatUser(chatRoomId, userId);
return chatRepository.findAllByCollection(chatRoomId, pageable);
}

public ChatRoomDataRes findChatRoomDetailData(Long userId, String chatRoomId) {
var user = findUserById(userId);
var chatRoom = findChatRoomById(chatRoomId);
chatRoom.validateContainsUser(user);
var project = projectRepository.findById(chatRoom.getProject().getId())
.orElseThrow(() -> new ProjectException(ErrorCode404.PROJECT_NOT_FOUND));
return ChatRoomDataRes.from(project.getMeetingInfo());
log.info("findChatRoomDetailData - userId: {}, chatRoomId: {}", userId, chatRoomId);
verifyChatUser(chatRoomId, userId);
return chatRoomRepository.getChatDetailData(userId, UUID.fromString(chatRoomId));
}

private ChatRoom findChatRoomById(String chatRoomId) {
Expand All @@ -91,4 +92,14 @@ private User findUserById(Long userId) {
return userCommonService.getUserById(userId);
}

private void verifyChatUser(String chatRoomIdStr, Long userId) {
log.info("verifyChatUser - chatRoomId: {}, userId: {}", chatRoomIdStr, userId);
UUID chatRoomId = UUID.fromString(chatRoomIdStr);
chatUserRepository.findByChatRoomIdAndUserId(chatRoomId, userId)
.ifPresentOrElse(null,
() -> {
throw new MatchingException(ErrorCode404.CHAT_USER_NOT_FOUND);
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@
import io.oeid.mogakgo.domain.chat.entity.enums.ChatStatus;
import io.oeid.mogakgo.domain.chat.exception.ChatException;
import io.oeid.mogakgo.domain.chat.infrastructure.ChatRepository;
import io.oeid.mogakgo.domain.chat.infrastructure.ChatRoomRoomJpaRepository;
import io.oeid.mogakgo.domain.user.application.UserCommonService;
import io.oeid.mogakgo.domain.user.domain.User;
import io.oeid.mogakgo.domain.chat.infrastructure.ChatUserJpaRepository;
import io.oeid.mogakgo.exception.code.ErrorCode400;
import io.oeid.mogakgo.exception.code.ErrorCode404;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
Expand All @@ -22,28 +21,26 @@
@Service
public class ChatWebSocketService {

private final ChatRoomRoomJpaRepository chatRoomJpaRepository;
private final ChatUserJpaRepository chatUserRepository;
private final ChatRepository chatRepository;
private final ChatIdSequenceGeneratorService sequenceGeneratorService;
private final UserCommonService userCommonService;

public ChatDataRes handleChatMessage(Long userId, String roomId, ChatReq request) {
log.info("handleChatMessage userId: {}, roomId: {}", userId, roomId);
User user = userCommonService.getUserById(userId);
verifyChatRoomByRoomIdAndUser(roomId, user);
verifyChatRoomByRoomIdAndUser(roomId, userId);
ChatMessage chatMessage = chatRepository.save(
ChatMessage.builder().id(sequenceGeneratorService.generateSequence(roomId))
.senderId(user.getId())
.senderId(userId)
.messageType(request.getMessageType())
.message(request.getMessage())
.build(), roomId);
return ChatDataRes.from(chatMessage);
}

private void verifyChatRoomByRoomIdAndUser(String roomId, User user) {
log.info("verifyChatRoomByRoomIdAndUser - roomId: {}, UserId: {}", roomId, user.getId());
ChatRoom chatRoom = chatRoomJpaRepository.findByIdAndUser(roomId, user)
.orElseThrow(() -> new ChatException(ErrorCode404.CHAT_ROOM_NOT_FOUND));
private void verifyChatRoomByRoomIdAndUser(String roomId, Long userId) {
log.info("verifyChatRoomByRoomIdAndUser - roomId: {}, UserId: {}", roomId, userId);
ChatRoom chatRoom = chatUserRepository.findByChatRoomIdAndUserId(UUID.fromString(roomId), userId)
.orElseThrow(() -> new ChatException(ErrorCode404.CHAT_ROOM_NOT_FOUND)).getChatRoom();
if (chatRoom.getStatus().equals(ChatStatus.CLOSED)) {
throw new ChatException(ErrorCode400.CHAT_ROOM_CLOSED);
}
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
package io.oeid.mogakgo.domain.chat.application.dto.res;

import io.oeid.mogakgo.domain.chat.application.vo.ChatUserInfo;
import io.oeid.mogakgo.domain.project.domain.entity.vo.MeetingInfo;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.LocalDateTime;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Schema(description = "채팅방 프로젝트 정보")
@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor
public class ChatRoomDataRes {

Expand All @@ -25,13 +23,16 @@ public class ChatRoomDataRes {
@Schema(description = "프로젝트 종료 시간")
private LocalDateTime meetEndTime;

public static ChatRoomDataRes from(MeetingInfo meetingInfo) {
private ChatUserInfo chatUserInfo;

public ChatRoomDataRes(MeetingInfo meetingInfo, ChatUserInfo chatUserInfo) {
var meetLocation = meetingInfo.getMeetLocation();
return new ChatRoomDataRes(
meetingInfo.getMeetDetail(),
meetingInfo.getMeetStartTime(),
meetLocation.getX(),
meetLocation.getY(),
meetingInfo.getMeetEndTime());
this.meetDetail = meetingInfo.getMeetDetail();
this.meetStartTime = meetingInfo.getMeetStartTime();
this.meetLocationLatitude = meetLocation.getX();
this.meetLocationLongitude = meetLocation.getY();
this.meetEndTime = meetingInfo.getMeetEndTime();
this.chatUserInfo = chatUserInfo;
}

}
Loading

0 comments on commit bde6dfe

Please sign in to comment.