Skip to content

Commit

Permalink
feature: 채팅 readCount 처리(#48)
Browse files Browse the repository at this point in the history
feature: 채팅 readCount 처리(#48)
  • Loading branch information
Lee-Dahyeon authored Nov 16, 2024
2 parents d7e437b + 6c3301b commit d34f861
Show file tree
Hide file tree
Showing 19 changed files with 226 additions and 26 deletions.
7 changes: 3 additions & 4 deletions .github/workflows/prod-deploy-container.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,9 @@ jobs:
- name: Push Docker image to Docker Hub
run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_IMAGE_NAME }}

# EC2 서버에 Docker Compose로 배포
- name: Deploy to server
uses: appleboy/[email protected]
id: deploy
# SSH 비밀 키 설정
- name: Install SSH Key
uses: webfactory/[email protected]
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USER }}
Expand Down
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ dependencies {
testImplementation 'com.h2database:h2'
implementation 'org.springframework.boot:spring-boot-starter-websocket'
implementation 'org.webjars:stomp-websocket:2.3.4'

}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.hyunsolution.dangu.chatlog.chatlogRepository;

import com.hyunsolution.dangu.chatlog.Chatlog;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface ChatlogRepository extends JpaRepository<Chatlog, Long> {

@Modifying
@Query(
"UPDATE Chatlog c SET c.readCount=:readCount WHERE c.user.id=:userId AND c.workspace.id=:workspaceId")
void updateCount(
@Param("userId") Long userId,
@Param("workspaceId") Long workspaceId,
@Param("readCount") int readCount);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.hyunsolution.dangu.chatlog.service;

import com.hyunsolution.dangu.chatlog.chatlogRepository.ChatlogRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
public class ChatlogService {
private final ChatlogRepository chatlogRepository;

// 채팅방별 사용자의 읽은 채팅 개수 업데이트
@Transactional
public void updateReadCount(Long chatRoomId, Long userPk, int messageCnt) {
chatlogRepository.updateCount(chatRoomId, userPk, messageCnt);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,22 @@
import com.hyunsolution.dangu.chatting.dto.response.ChatMessageDetailResponse;
import com.hyunsolution.dangu.chatting.dto.response.ChatMessageResponse;
import com.hyunsolution.dangu.chatting.service.ChatService;
import com.hyunsolution.dangu.common.apiResponse.ApiResponse;
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.handler.annotation.DestinationVariable;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@Controller
@RestController
@RequiredArgsConstructor
public class ChatController {
private final ChatService chatService;
Expand All @@ -33,4 +38,12 @@ public ChatMessageResponse sendChatMessage(

return new ChatMessageResponse("success", response, null);
}

@Operation(summary = "채팅방 나가기", description = "채팅방을 나갈 시 해당 채팅방의 전체 메세지 개수를 저장합니다.")
@PostMapping("/chat/{chatRoomId}/exit")
public ApiResponse exitChat(
@PathVariable Long chatRoomId, @RequestHeader("Authorization") Long userPk) {
chatService.readMessageCnt(userPk, chatRoomId);
return ApiResponse.success(true);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package com.hyunsolution.dangu.chatting.domain;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface ChatRepository extends JpaRepository<Chatting, Long> {}
public interface ChatRepository extends JpaRepository<Chatting, Long> {

@Query("SELECT COUNT(c) FROM Chatlog c WHERE c.workspace.id=:roomId")
int countMessageByRoomId(@Param("roomId") Long roomId);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.hyunsolution.dangu.chatting.service;

import com.hyunsolution.dangu.chatlog.service.ChatlogService;
import com.hyunsolution.dangu.chatting.domain.ChatRepository;
import com.hyunsolution.dangu.chatting.domain.Chatting;
import com.hyunsolution.dangu.chatting.dto.response.ChatMessageDetailResponse;
Expand All @@ -19,6 +20,7 @@ public class ChatService {
private final ChatRepository chatRepository;
private final WorkspaceRepository workspaceRepository;
private final UserRepository userRepository;
private final ChatlogService chatlogService;

@Transactional
public ChatMessageDetailResponse sendMessage(Long chatRoomId, String message, Long userPk) {
Expand All @@ -39,4 +41,12 @@ public ChatMessageDetailResponse sendMessage(Long chatRoomId, String message, Lo
new ChatMessageDetailResponse(message, user.getUid(), chatMessage.getCreatedAt());
return detailResponse;
}

@Transactional
public void readMessageCnt(Long chatRoomId, Long userPk) {
// 채팅방 나갈 시점에서의 메세지 개수 조회
int messageCnt = chatRepository.countMessageByRoomId(chatRoomId);
// chatlog 테이블 속 readCount 업데이트
chatlogService.updateReadCount(chatRoomId, userPk, messageCnt);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.hyunsolution.dangu.common.config.webSocket;

import io.swagger.v3.oas.annotations.Operation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class WebSocketSwaggerDocsController {
@Operation(
summary = "WebSocket 연결 정보",
description =
"""
WebSocket URL, 구독 경로 및 발행 경로 안내
- WebSocket 접속 URL: wss://54.221.244.36:8080/chat
- STOMP 구독 주소: /topic/chat/{chatRoomId}
- 메시지 전송 주소: /app/chat/{chatRoomId}
""")
@GetMapping("/websocket/info") // 스웨거 웹소켓관련 정보 제공을 위한 api
public void getWebSocketInfo() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.hyunsolution.dangu.common.apiResponse.ApiResponse;
import com.hyunsolution.dangu.participant.domain.ParticipantRepository;
import com.hyunsolution.dangu.participant.dto.response.EnterChatRoomResponse;
import com.hyunsolution.dangu.participant.service.ParticipantService;
import com.hyunsolution.dangu.user.domain.UserRepository;
import com.hyunsolution.dangu.workspace.domain.WorkspaceRepository;
Expand All @@ -21,6 +22,7 @@ public class ParticipantController {
private final WorkspaceRepository workspaceRepository;
private final ParticipantService participantService;

//사용자 매칭 버튼 클릭
@PostMapping("/participant/matching/{roomNumber}")
public ApiResponse<?> matching(
@Parameter(hidden = true) @RequestHeader("Authorization") Long id,
Expand All @@ -30,4 +32,13 @@ public ApiResponse<?> matching(
participantService.changeMatching(id, workspaceId);
return ApiResponse.success(null);
}

// 사용자 채팅방 입장
@PostMapping("/participant/{roomNumber}")
public ApiResponse<EnterChatRoomResponse> enterChatRoom(
@Parameter(hidden = true) @RequestHeader("Authorization") Long id,
@PathVariable("roomNumber") Long workspaceId) {
EnterChatRoomResponse response = participantService.sendEnteringMessage(id, workspaceId);
return ApiResponse.success(response);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ public interface ParticipantRepository extends JpaRepository<Participant, Long>
"SELECT p from Participant p join p.workspace w where p.user.id =:id and p.workspace.id=:workspaceId")
Optional<Participant> findByUserIdAndWorkspaceId(
@Param("id") Long id, @Param("workspaceId") Long workspaceId);

List<Participant> findByWorkspaceId(Long workspaceId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.hyunsolution.dangu.participant.dto.response;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@AllArgsConstructor
@NoArgsConstructor
public class EnterChatRoomResponse {
private String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.hyunsolution.dangu.participant.exception;

import com.hyunsolution.dangu.common.exception.BaseErrorCode;
import com.hyunsolution.dangu.common.exception.ExceptionDto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
@AllArgsConstructor
public enum ParticipantError implements BaseErrorCode {
PARTICIPANT_NOT_FOUND("PARTICIPANT_400_1", HttpStatus.BAD_REQUEST, "해당 채팅방 참여자를 찾을 수 없습니다.");

private final String code;
private final HttpStatus httpStatus;
private final String message;

@Override
public ExceptionDto getErrorReason() {
return ExceptionDto.builder().code(code).message(message).httpStatus(httpStatus).build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.hyunsolution.dangu.participant.exception;

import com.hyunsolution.dangu.common.exception.CustomException;

public class ParticipantNotFoundException extends CustomException {
public static final ParticipantNotFoundException EXCEPTION = new ParticipantNotFoundException();

private ParticipantNotFoundException() {
super(ParticipantError.PARTICIPANT_NOT_FOUND);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@

import com.hyunsolution.dangu.participant.domain.Participant;
import com.hyunsolution.dangu.participant.domain.ParticipantRepository;
import com.hyunsolution.dangu.participant.dto.response.EnterChatRoomResponse;
import com.hyunsolution.dangu.participant.exception.ParticipantNotFoundException;
import com.hyunsolution.dangu.user.domain.User;
import com.hyunsolution.dangu.user.domain.UserRepository;
import com.hyunsolution.dangu.workspace.domain.Workspace;
import com.hyunsolution.dangu.workspace.domain.WorkspaceRepository;
import java.util.List;
import java.util.NoSuchElementException;
import com.hyunsolution.dangu.workspace.exception.WorkspaceNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -24,27 +27,48 @@ public void changeMatching(Long id, Long workspaceId) {
Participant participantOptional =
participantRepository
.findByUserIdAndWorkspaceId(id, workspaceId)
.orElseThrow(() -> new NoSuchElementException("Participant not found"));
.orElseThrow(() -> ParticipantNotFoundException.EXCEPTION);

participantOptional.accept();

// participant테이블에서 roomNumber로 들어온 숫자를 통해 누가 있는지 파악
List<Long> participantIds =
participantRepository.findParticipantIdByWorkspaceId(workspaceId);
List<Long> participantIds = participantRepository.findParticipantIdByWorkspaceId(workspaceId);

// 방안에 모든 참가자가 "확정"버튼을 눌렀는지 확인
for (Long participant : participantIds) {
boolean mathingCheck =
participantRepository.existsByIdAndParticipantMatchTrue(participant);
boolean mathingCheck = participantRepository.existsByIdAndParticipantMatchTrue(participant);
if (!mathingCheck) {
return;
}
}
// 게임방 테이블 속 매칭 결과를 true로 바꿈
Workspace workspace1 =
workspaceRepository
.findById(workspaceId)
.orElseThrow(() -> new NoSuchElementException("Workspace not found"));
Workspace workspace1 = workspaceRepository.findById(workspaceId).orElseThrow(()-> WorkspaceNotFoundException.EXCEPTION);
workspace1.acceptFinal();
}

// 채팅방 입장 메시지 전송
public EnterChatRoomResponse sendEnteringMessage(Long id, Long workspaceId) {
User user = userRepository.findById(id).orElseThrow();
Workspace workspace = workspaceRepository.findById(workspaceId).orElseThrow();
String message;
// 기존 채팅방에 1명(방장)만 존재하며 & 입장자가 방장이 아닐때 입장 메시지를 보낸다.
if (participantRepository.findByWorkspaceId(workspaceId).size() != 2
&& workspaceRepository.findById(workspaceId).get().getCreator().getId() != id) {

// 입장자 participant 테이블에 저장
Participant participant =
Participant.builder()
.user(user)
.workspace(workspace)
.participantMatch(false)
.build();
participantRepository.save(participant);

String userName = userRepository.findById(id).get().getUid();
message = userName + "님이 입장하셨습니다.";
} else {
message = "";
}
return new EnterChatRoomResponse(message);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package com.hyunsolution.dangu.user.domain;

import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUid(String uid);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.hyunsolution.dangu.participant.domain.Participant;
import com.hyunsolution.dangu.user.domain.User;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.*;
Expand All @@ -14,6 +13,8 @@
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.hyunsolution.dangu.workspace.exception;

import com.hyunsolution.dangu.common.exception.BaseErrorCode;
import com.hyunsolution.dangu.common.exception.ExceptionDto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
@AllArgsConstructor
public enum WorkspaceError implements BaseErrorCode {
WORKSPACE_NOT_FOUND("WORKSAPCE_400_1", HttpStatus.BAD_REQUEST, "채팅방을 찾을 수 없습니다.");

private final String code;
private final HttpStatus httpStatus;
private final String message;

@Override
public ExceptionDto getErrorReason() {
return ExceptionDto.builder().code(code).message(message).httpStatus(httpStatus).build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.hyunsolution.dangu.workspace.exception;

import com.hyunsolution.dangu.common.exception.CustomException;

public class WorkspaceNotFoundException extends CustomException {
public static final WorkspaceNotFoundException EXCEPTION = new WorkspaceNotFoundException();

private WorkspaceNotFoundException() {
super(WorkspaceError.WORKSPACE_NOT_FOUND);
}
}
Loading

0 comments on commit d34f861

Please sign in to comment.