Skip to content

Commit

Permalink
Dev (#280)
Browse files Browse the repository at this point in the history
* Perf/single chatroom: 베타테스트를 위한 채팅 DTO 수정 (#240)

* perf/singleChatroom-1: 채팅 조회 총정리, 채팅방 조회 DTO 수정

- SINGLE, AUTH : 본인이 속한 일대일 채팅방 조회

- GROUP, AUTH : 본인이 속한 그룹 채팅방 조회

- AUTH : 본인이 방장인 그룹 채팅방 조회

- 채팅방 DTO 재활용을 위한 인터페이스 화 진행

- 싱글 채팅방 조회 메서드 새로 생성
- 채팅방 조회 DTO에서 채팅들 삭제

* perf/singleChatroom-2: JPA 간단화 및 채팅 RedisDTO에 민감한 정보 제외

* perf/singleChatroom-3: chore 및 누락 Liquibase 되살리기

* perf/singleChatroom-4: Spotlessapply 적용

* perf/singleChatroom-5: @JsonIgnoreProperty 적용해 Override해서 불러오지 말아야 할 값 안 가져옴

* perf/singleChatroom-7: 중복해서 들어간 @JsonIgnoreProperty 삭제

* perf/singleChatroom-8: 중복해서 들어간 Liquibase 코드 삭제

* perf/singleChatroom-9: 채팅 응답 DTO에서 누락된 채팅 ID 표시

* perf/exceptMemberDto-1: 수정 회원 응답 DTO 적용 (MemberService 제외) (#241)

* perf/exceptMemberDto-1: 수정 회원 응답 DTO 적용 (MemberService 제외)

* perf/exceptMemberDto-2: 1차 서비스 코드 정리

* hotfix/bookmarkAndtime-1: Created 기준 시간 -> 한국 시간으로 변경 & 북마크 공개/비공개 게시글 상관없이 가능하도록 수정 (#243)

* fix/comment-toMe-notification-1: 자신이 작성한 게시글에는 댓글 작성 알림 오지 않도록 (이전 회의 사항 미 반영본) (#244)

* hotfix/chatroom-getChatError-1: 채팅방 조회시 작성자와 다름 문제 해결 (#245)

* fix/comment-toMe-notification-1: 자신이 작성한 게시글에는 댓글 작성 알림 오지 않도록 (이전 회의 사항 미 반영본)

* hotfix/chatroom-getChatError-1: 채팅방 조회시 작성자와 다름 문제 해결

* hotfix/file-presignurl-1: 누락된 presignurl 수정 코드 추가 (#251)

* hotfix/file-profileImg-1: File presignURL ID로 가져오기 작업 - ProfileImg (#253)

* Feat/single chatroom exit : 싱글 채팅방 퇴장 및 혼자 남아있을 경우 (상대방 퇴장 시)알림 구현 (#255)

* feat/singleChatroom-1: 싱글 채팅방 퇴장 구현

- 기존 채팅방 퇴장은 그룹 채팅방 퇴장만 구현되어 있음 -> 싱글 채팅방 퇴장도 추가 구현

- 그룹 채팅방은 Redisson 처리한 사항이 있어 DB 저장 작업이 필수적임 -> 구별되게 그룹 채팅방 퇴장과 싱글 채팅방 퇴장을 구분
- 채팅 퇴장 시 퇴장 채팅 저장과 Redis 발행은 기존대로 유지 (채팅 보내기와 동일하게 동작함)

* feat/singleChatroom-2: 채팅방 퇴장 시 혼자 남은 채팅방 알림구현

- 그룹, 싱글 알림 모두 구현
- 기존 알림 서비스와 동일
- Set의 members에서 한 명의 유저만 남아있을 경우 stream.findFirst() 사용함
- 사용자 언어설정에 따른 번역 알림 추가

* feat/singleChatroom-isRead-1: 싱글 채팅방 읽음 대상자(상대방) 읽었는지 표시 구현 (#256)

* feat/singleChatroom-isRead-
1: 싱글 채팅방 읽음 대상자(상대방) 읽었는지 표시 구현

- Chat 엔티티에 해당 Boolean 값인 isOtherRead 생성
- 읽음 대상자 (상대방)이 GET :chats?chatroomId={채팅방 ID}를 하면 해당 isOtherRead를 true로 바꿔줌

* hotfix/chatroom-bookmark-individual-1: 채팅방 별 북마크 조회 가능하도록 수정

* feat/singleChatroom-isRead-
2: 싱글 채팅방 퇴장 시 알림 구현 사항 되돌리기
- 이유 : 불필요

* Feat/chat authorization : 일대일 채팅 JWT Authorization 넣기  (#254)

* feat/chat-authorization-1: STOMP 시큐리티 작업

- SecurityWebSockConfig:
- SecurityConfig로 보호되지 않았던 /pub, /sub 보안 잠그기
- WebSockConfig:
- 채팅 발행하기에 앞서 Client에서 보내준 Authorization 값 STOMP Session에 포함시키기 위한 Interceptor 주입

* feat/chat-authorization-2: WebSocketInterceptor 작업

- WebSocketInterceptor:
- CONNCECT -> SEND 모두 authorization을 받아 JWTFilter의 doFilterChain 메서드가 하는 일을 수행함
- 자격증명이 마친다면 StompHeaderAccessor로 회원 이메일을 전달함

* hotfix/chatroom-exit-unsubscribe-1: 기존에 DISCONNECT 했던 채팅방을 UNSUBSCRIBE로 퇴장을 구현함 (#258)

* hotfix/chatroom-exit-unsubscribe-1: 기존에 DISCONNECT 했던 채팅방을 UNSUBSCIRBE로 퇴장을 수정함

* hotfix/chatroom-exit-unsubscribe-2: spotlessapply

* feat(채팅): 더 세밀한 채팅 관련 인증/인가 조절 구현 (#259)

개요

- 현재 SecurityWebSocketConfig에서 HttpSecurity를 사용하고 있는데, 이를
authorizationManager로 바꾸어 STOMP 명령어별로 인증/인가를 설정할 수
있도록 한다.

수정사항

- 누구나 접속해도 되는 CONNECT, UNSUB, DISCONNECT, HEARTBEAT는 풀어놓고
- MESSAGE, SUB은 인증이 될 경우에만 호출할 수 있도록 한다.
- 추가로, SEND /pub, SUBSCRIBE /sub으로의 destination은 무조건 인증된
경우만 접근할 수 있도록
- 이외의 호출은 모두 거절한다.

- csrfChannelInterceptor는 csrf 활성화를 제거하기 위한 작업. (브라우저는
어플에서 사용하지 않으므로 csrf 비활성화)

- Interceptor의 로직 같은 경우, 초기 CONNECT하는 경우에만 JWT로 해당
유저의 인증상태를 확인한다. (만료된 상황에서 확인하는 과정은 다음 PR에서
진행하도록 하겠습니다.)

- authenticated()를 AuthorizationManager에서 사용하려면, 현재 컨텍스트에
setAuthentication을 해주고, 이후의 활용을 위해 accessor.setUser까지
추가해줘야한다. 그래야만 인증이 되었을 때, 문제없이 인증을 할 수 있다.

- 참고로, Websocket 자체에서 인증 인가를, Header에서 simpUser로 진행하기
때문에, 기존에 header에 넣어줬던 userEmail을 제거하고
SocketController의 UserDetails 주입을 통해 해당 인증 정보를 가져올 수
있도록 한다. 기존의 userEmail을 이렇게 변경한 이유는, 웹소켓이 초기에
연결이 성립되고 이후에 메시지보내기 등을 사용하면 기존의 Auth 정보는
header에 저장이 되지만, 우리가 직접 넣어줬던 userEmail은 요청마다 새로
다시 넣어줘야하기 때문이다.

* fix(error): 웹소켓 에러 시에 이유 함께 보낼 수 있도록 처리 (#260)

개요

- 현재 웹소켓의 연결이 끊길 때 원인이 잘 나오지 않는 문제가 있다.
- 에러 발생 시, 원인을 전달하기 위해 StompSubProtocolHandler를 직접
작성한다.
- Interceptor에서 에러 체킹을 추가한다.

수정 사항

- 에러 발생 시, 원인을 전달하기 위해 StompSubProtocolHandler를 직접
  - 빠른 구현을 위해 링크 참고해서 일부만 수정함: https://velog.io/@jkijki12/%EC%B1%84%ED%8C%85-STOMP-JWT
- WebsocketInterceptor에서, JWT가 필요한 Command와 그렇지 않은
Command를 구분해서 알맞게 상황처리를 해준다.
  - CONNECT, SEND, MESSAGE, SUBSCRIBE는 JWT 필요
  - CONNECT의 경우에는 초기 auth 설정해줌
  - SUBSCRIBE의 경우에 destination 체킹 진행
  - SUBSCRIBE 때, 구독 권한이 있는지 확인한다.
- chatroom.getMembers().contains(member) 이 부분에서 Member 인스턴스가
달라도, id로 멤버가 포함되어있는지 체킹이 필요하기 때문에, equals와
hashcode 함께 override (Convention 따라, o 변수 사용)

* refactor/chat-exit-auth-1: 개선된 채팅 인증/인가 적용한 채팅방 퇴장 수정 (#261)

- 기존에 채팅방 퇴장하면 DISCONNECT 했던 것을 UNSUBSCRIBE로 수정
-  messagingTemplate 이용해 UNSUBSCRIBE 메시지 직접 서버에서 전송

chore
- 이전에 DISCONNECT 하지 않았어야 하는 enter 부분 코드 Exception 던지는 것으로 수정
- 불필요한 퇴장 시 빈 채팅방 확인 코드 삭제

* Revert "Feat/chatroom re enter (#264)" (#267)

This reverts commit c75de60.

* Merge/dev (#270)

* feat/chatroom-reEnter-1: 재입장 가능하도록
- 중간 테이블 chatroom_exited_member 생성

재입장 로직:
- EXIT을 하게 되면 chatroom_member에서 member이 삭제되는 것이 아닌 chatroom_exited_member에 member가 추가되는 것임

- 응답 DTO에 퇴장한 회원 정보 표시 (그룹 채팅방에 접속한 회원 수 표시 목적)

* feat/chatroom-reEnter-2: 채팅방 조회 코드 수정 및 chore

- ChatService:
- EXIT:
- 퇴장을 하게 되면 chatroom의 members에서 삭제되는 것이 아닌 exitedMembers에 추가되는 것임
- CHAT:
- 퇴장을 한 회원에게는 채팅 알림이 가지 않아야 하기 때문에 제외 코드를 추가함
- ENTER:
- 그 후 재 입장을 하게 되면 원래 있던 채팅방에 입장해야 하기 때문에 exitedMembers에서 삭제를 진행하며 입장 알림이 가도록 함

- ChatroomService:
- GET 채팅방 조회시에 퇴장한 채팅방은 포함되지 않아야 하기 때문에 filter 코드 추가함
- 퇴장한 채팅방 조회도 가능하도록 추가
- GET : /api/chatrooms?type=EXITED

chore
- 방장인 채팅방 조회:
- GET : /api/chatrooms?type=MANAGER
- Test 통과를 위한 JVM 크기 2GB로 늘림
- SWAGGER 반영 완료

* feat/chatroom-reEnter-3: 퇴장한 채팅방 접근 강화

* feat/chatroom-reEnter-4: build messaging 추가

* Merge/dev (#270) (#273)

* feat/chatroom-reEnter-1: 재입장 가능하도록
- 중간 테이블 chatroom_exited_member 생성

재입장 로직:
- EXIT을 하게 되면 chatroom_member에서 member이 삭제되는 것이 아닌 chatroom_exited_member에 member가 추가되는 것임

- 응답 DTO에 퇴장한 회원 정보 표시 (그룹 채팅방에 접속한 회원 수 표시 목적)

* feat/chatroom-reEnter-2: 채팅방 조회 코드 수정 및 chore

- ChatService:
- EXIT:
- 퇴장을 하게 되면 chatroom의 members에서 삭제되는 것이 아닌 exitedMembers에 추가되는 것임
- CHAT:
- 퇴장을 한 회원에게는 채팅 알림이 가지 않아야 하기 때문에 제외 코드를 추가함
- ENTER:
- 그 후 재 입장을 하게 되면 원래 있던 채팅방에 입장해야 하기 때문에 exitedMembers에서 삭제를 진행하며 입장 알림이 가도록 함

- ChatroomService:
- GET 채팅방 조회시에 퇴장한 채팅방은 포함되지 않아야 하기 때문에 filter 코드 추가함
- 퇴장한 채팅방 조회도 가능하도록 추가
- GET : /api/chatrooms?type=EXITED

chore
- 방장인 채팅방 조회:
- GET : /api/chatrooms?type=MANAGER
- Test 통과를 위한 JVM 크기 2GB로 늘림
- SWAGGER 반영 완료

* feat/chatroom-reEnter-3: 퇴장한 채팅방 접근 강화

* feat/chatroom-reEnter-4: build messaging 추가

* feat/chatroom-dto-add-lastChat-1: 채팅방 GET요청 시 최신 순 정렬된 마지막 채팅 DTO에 추가 (#272)

* chore(log): 버그 확인 용도로 사용한 로깅 삭제 (#275)

개요

- 꿀팁게시판 자유게시판이 섞이는 부분의 확인을 위해 로깅함수를
사용했는데 이를 삭제한다.

* fix(ws): 웹소켓 HEARTBEAT 안되는 문제 구현 (#276)

* hotfix/member-like-mapping-1: 회원정보 불러올 때 ResponseMapper 수정 (제대로 Hobbies와 Languages 불러오도록) (#278)

* Feat/chatroom exit and re enter : 퇴장 후 재 입장 코드 로직 수정 및 개선 (#277)

* feat/chatroom-exit-and-reEnter-1: 퇴장 채팅방과 회원 엔티티 간의 중간 테이블 생성

- 생성한 원인으로는 기존에 만들었던 테이블 (채팅방과 회원)으로는 reEnterTime 컬럼을 생성할 수 없었기 때문

- 퇴장 로직 설명:
- 퇴장을 하면 중간테이블인 ChatroomExitedMember가 생김
- 해당 테이블에 채팅방, 회원 reEnterTime이 생김
- 재입장 하지 않는 한 해당 테이블의 reEnterTime은 null임 (퇴장, 재입장, 퇴장 시에도 null)
- 채팅방, 회원 간에 unique해야 하는 테이블이므로 uniqueConstraints 값 설정

* feat/chatroom-exit-and-reEnter-2: 퇴장 후 재입장 및 채팅 불러오기 로직 정리

- 재입장 로직:
- 재입장 시에는 CheckPoint에 시각이 찍힘
- 이는 채팅 불러오기, 채팅방 구독 전 EXITED 채팅방 불러오기 시에 사용
- GET :/chats?chatroomId={} 시에 getChats를 할 때에 reEnterTime 이후에 유효한 채팅이 자동으로 적용되어 들어감

- docs : Liquibase 문 기존에 만들어 둔 단순 중간 테이블 삭제 후 새 테이블 생성 (이중 테이불이 생기는 경우이므로 기존 DDL update 문 삭제 후 생성을 진행함)

* feat/chatroom-exit-and-reEnter-3: Migration은 삭제가 아닌 수정을 하자

- 기존 외래키 관계 및 고유 키 drop 후 새로 중간 테이블 새로 생성
- 이전에 선언했던 단순 중간 테이블 v1.0.5.xml 되살리기

* feat/chatroom-exit-and-reEnter-4: 중간 테이블 ChatroomMember 재 선언

- ExitMember과 ActiveMember를 함께 관리

* feat/chatroom-exit-and-reEnter-5: 주요 수정 Service

- 기존 퇴장, 재입장 로직과 동일
- 채팅방의 ACTIVE 한 채팅방 회원들만 가져오는 함수 모듈화
- getSingleChatroom에 앞선 모듈화 함수를 사용하지 않은 이유로는 재입장 시에 사용하는 엔드포인트에서도 (EXITED) 사용하기 때문
- 재입장 시에만 EXITED 조건을 허용해 주기 때문에 다른 메서드에서는 ACTIVE한 상태인지 확인하는 조건이 추가됨
- 웹소켓 preSend 조건에서 사용하는 isMemberInChatroom에서는 Sub 시에 사용하기 때문에 재 입장 시에도 Sub 먼저 해야 하기 때문에 채팅방과 회원간에 관계가 없을 경우에만 Exception을 내뱉도록 수정함

* feat/chatroom-exit-and-reEnter-6: getMembers -> validMembers 메서드 이용후 contains() 메서드 이용

* feat/chatroom-exit-and-reEnter-7: chore/docs

* feat/chatroom-exit-and-reEnter-8: SUB 보안 되살리기

- 앞선 코드에서 SUB를 퇴장한 회원에 한해서는 허용해왔지만
- 퇴장한 회원 가운데에 재입장한 회원에 한해 허용하도록 엔드포인트를 하나 더 생성함 (서버에서 채팅방 회원의 status를 Active로 바꿔주는 엔드포인트)

* feat/chatroom-count-1: 채팅방 list 조회 시에 count가 보이도록 구현 (#279)

- lastHoldAt : ChatroomMember에 채팅방을 떠날 때에 TimeStamp를 기록
- 해당 값은 채팅방 뒤로가기를 누를 시에, 채팅 목록 조회 시에 업데이트 됨

- Put :/chatrooms/{chatroomId}/hold 엔드포인트 생성 :
- 해당 엔드포인트는 채팅방 안읽은 채팅 갯수를 업데이트 하기 위한 용도로 사용됨

---------

Co-authored-by: Seungho Lee <[email protected]>
  • Loading branch information
KooSuYeon and seungholee-dev authored Nov 7, 2024
1 parent 06f6ffa commit bcdad42
Show file tree
Hide file tree
Showing 24 changed files with 518 additions and 122 deletions.
35 changes: 34 additions & 1 deletion src/main/java/com/dife/api/config/MapperConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import com.dife.api.model.*;
import com.dife.api.model.dto.GroupChatroomResponseDto;
import com.dife.api.model.dto.MemberResponseDto;
import com.dife.api.model.dto.SingleChatroomResponseDto;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.modelmapper.ModelMapper;
import org.modelmapper.convention.MatchingStrategies;
Expand Down Expand Up @@ -61,8 +63,39 @@ public ModelMapper chatroomModelMapper() {
.map(GroupPurpose::getType)
.collect(Collectors.toSet()),
GroupChatroomResponseDto::setPurposes);
});

mapper.map(
src -> {
Set<ChatroomMember> members = src.getMembers();
if (members == null) {
return Collections.emptySet();
}
return members.stream()
.filter(
chatroomMember -> chatroomMember.getStatus() == ChatroomStatus.ACTIVE)
.map(ChatroomMember::getMember)
.collect(Collectors.toSet());
},
GroupChatroomResponseDto::setMembers);
});
modelMapper
.typeMap(Chatroom.class, SingleChatroomResponseDto.class)
.addMappings(
mapper -> {
mapper.map(
src -> {
Set<ChatroomMember> members = src.getMembers();
if (members == null) {
return Collections.emptySet();
}
return members.stream()
.filter(
chatroomMember -> chatroomMember.getStatus() == ChatroomStatus.ACTIVE)
.map(ChatroomMember::getMember)
.collect(Collectors.toSet());
},
SingleChatroomResponseDto::setMembers);
});
return modelMapper;
}

Expand Down
10 changes: 9 additions & 1 deletion src/main/java/com/dife/api/config/WebSockConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.web.socket.config.annotation.*;

@RequiredArgsConstructor
Expand All @@ -22,10 +24,16 @@ public void registerStompEndpoints(StompEndpointRegistry registry) {

@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/sub");
config.enableSimpleBroker("/sub").setTaskScheduler(taskScheduler());
config.setApplicationDestinationPrefixes("/pub");
}

public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.initialize();
return taskScheduler;
}

@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(webSocketInterceptor);
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/com/dife/api/config/WebSocketInterceptor.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.springframework.core.annotation.Order;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.SimpMessageType;
import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptor;
Expand Down Expand Up @@ -45,6 +46,10 @@ public Message<?> preSend(Message<?> message, MessageChannel channel) {
Set<StompCommand> jwtExpiredCheckCommands = Set.of(CONNECT, SEND, MESSAGE, SUBSCRIBE);
StompCommand currentCommand = accessor.getCommand();

if (currentCommand == null && accessor.getMessageType() == SimpMessageType.HEARTBEAT) {
return message;
}

if (jwtExpiredCheckCommands.contains(currentCommand)) {
String authToken = accessor.getFirstNativeHeader("authorization");
String jwtToken = extractJwtToken(authToken);
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/com/dife/api/controller/ChatroomController.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,20 @@ public ResponseEntity<GroupChatroomResponseDto> update(
return ResponseEntity.status(OK).body(responseDto);
}

@PutMapping("/{roomId}/status")
public ResponseEntity<Void> chatroomReEnter(
@PathVariable(name = "roomId") Long roomId, Authentication auth) {
chatroomService.chatroomReEnter(roomId, auth.getName());
return new ResponseEntity<>(OK);
}

@PutMapping("/{roomId}/hold")
public ResponseEntity<Void> chatroomHold(
@PathVariable(name = "roomId") Long roomId, Authentication auth) {
chatroomService.chatroomHold(roomId, auth.getName());
return new ResponseEntity<>(OK);
}

@GetMapping("/{roomId}/{memberId}")
public ResponseEntity<Void> kickoutMember(
@PathVariable(name = "roomId") Long roomId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,34 @@ ResponseEntity<List<ChatroomResponseDto>> getChatrooms(
ResponseEntity<ChatroomResponseDto> getChatroom(
@PathVariable(name = "id") Long id, Authentication auth) throws IOException;

@Operation(
summary = "채팅방 뒤로가기(hold) 생성 API",
description = "서버 측에서 사용자가 채팅방 뒤로가기를 했음을 인식하게 해주는 API입니다. 해당 API를 이용해 채팅 수를 계산하게 됩니다.")
@ApiResponse(
responseCode = "200",
description = "채팅방 뒤로가기 성공 예시",
content = {
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ChatroomResponseDto.class))
})
ResponseEntity<Void> chatroomHold(
@PathVariable(name = "roomId") Long roomId, Authentication auth);

@Operation(
summary = "채팅방 재입장 생성 API",
description = "서버 측에서 채팅방 Id와 Auth로 퇴장한 채팅방 재입장 허가를 해주는 API입니다.")
@ApiResponse(
responseCode = "200",
description = "채팅방 재입장 성공 예시",
content = {
@Content(
mediaType = "application/json",
schema = @Schema(implementation = ChatroomResponseDto.class))
})
ResponseEntity<Void> chatroomReEnter(
@PathVariable(name = "roomId") Long roomId, Authentication auth);

@Operation(
summary = "그룹 채팅방 필터 조회 API",
description =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.dife.api.exception;

public class ChatroomReEnterException extends IllegalArgumentException {

public ChatroomReEnterException(String message) {
super(message);
}
}
9 changes: 8 additions & 1 deletion src/main/java/com/dife/api/handler/DisconnectHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import com.dife.api.model.ChatroomSetting;
import com.dife.api.model.ChatroomType;
import com.dife.api.model.Member;
import com.dife.api.service.ChatroomService;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.SimpMessageSendingOperations;
Expand All @@ -16,6 +18,8 @@ public class DisconnectHandler {

private final SimpMessageSendingOperations messagingTemplate;

private ChatroomService chatroomService;

public boolean canEnterChatroom(
Chatroom chatroom, Member member, String sessionId, String password) {

Expand All @@ -36,7 +40,10 @@ private boolean isGroupChatroom(Chatroom chatroom) {
}

private boolean isExistsAlready(Chatroom chatroom, Member member) {
return chatroom.getMembers().contains(member);

Set<Member> memberSet = chatroomService.validChatroomMembers(chatroom);

return memberSet.contains(member);
}

private boolean isRestrictedGroupChatroom(Chatroom chatroom, String password) {
Expand Down
8 changes: 6 additions & 2 deletions src/main/java/com/dife/api/handler/NotificationHandler.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.dife.api.handler;

import com.dife.api.model.*;
import com.dife.api.service.ChatroomService;
import com.dife.api.service.NotificationService;
import java.time.LocalDateTime;
import java.util.*;
Expand All @@ -12,9 +13,12 @@
public class NotificationHandler {

private final NotificationService notificationService;
private final ChatroomService chatroomService;

public void isAlone(Chatroom chatroom, Member exitMember) {
if (chatroom.getMembers().size() < 2 && chatroom.getChatroomType() == ChatroomType.GROUP)

Set<Member> memberSet = chatroomService.validChatroomMembers(chatroom);
if (memberSet.size() < 2 && chatroom.getChatroomType() == ChatroomType.GROUP)
notificate(chatroom, exitMember);
}

Expand All @@ -33,7 +37,7 @@ private String translationDivide(Chatroom chatroom, String settingLanguage, Memb

public void notificate(Chatroom chatroom, Member exitMember) {

Set<Member> members = chatroom.getMembers();
Set<Member> members = chatroomService.validChatroomMembers(chatroom);
Member member =
members.stream()
.findFirst()
Expand Down
24 changes: 7 additions & 17 deletions src/main/java/com/dife/api/model/Chatroom.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.persistence.*;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
Expand Down Expand Up @@ -39,20 +37,12 @@ public class Chatroom extends BaseTimeEntity {
@JsonIgnore
private Member manager;

@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name = "chatroom_member",
joinColumns = @JoinColumn(name = "chatroom_id"),
inverseJoinColumns = @JoinColumn(name = "member_id"))
@JsonIgnore
private Set<Member> members = new HashSet<>();

@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name = "chatroom_exited_members",
joinColumns = @JoinColumn(name = "chatroom_id"),
inverseJoinColumns = @JoinColumn(name = "member_id"))
private Set<Member> exitedMembers = new HashSet<>();
@OneToMany(
mappedBy = "chatroom",
fetch = FetchType.EAGER,
cascade = CascadeType.ALL,
orphanRemoval = true)
private Set<ChatroomMember> members = new HashSet<>();

@OneToMany(mappedBy = "chatroom", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JsonIgnore
Expand Down
39 changes: 39 additions & 0 deletions src/main/java/com/dife/api/model/ChatroomMember.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.dife.api.model;

import jakarta.persistence.*;
import java.time.LocalDateTime;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.transaction.annotation.Transactional;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Transactional
@Entity
@Table(
name = "chatroom_member",
uniqueConstraints = {@UniqueConstraint(columnNames = {"chatroom_id", "member_id"})})
public class ChatroomMember {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne
@JoinColumn(name = "chatroom_id", nullable = false)
private Chatroom chatroom;

@ManyToOne
@JoinColumn(name = "member_id", nullable = false)
private Member member;

@Enumerated(EnumType.STRING)
private ChatroomStatus status;

private LocalDateTime lastHoldAt;
private LocalDateTime lastJoinedAt;
}
6 changes: 6 additions & 0 deletions src/main/java/com/dife/api/model/ChatroomStatus.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.dife.api.model;

public enum ChatroomStatus {
ACTIVE,
EXITED
}
8 changes: 2 additions & 6 deletions src/main/java/com/dife/api/model/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,9 @@ public class Member extends BaseTimeEntity {
@OneToMany(mappedBy = "toMember", cascade = CascadeType.ALL)
private Set<Connect> received;

@ManyToMany(mappedBy = "members")
@JsonIgnore
private Set<Chatroom> chatrooms = new HashSet<>();

@ManyToMany(mappedBy = "exitedMembers") // Chatroom 엔티티의 exitedMembers와 일치시킴
@OneToMany(mappedBy = "member")
@JsonIgnore
private Set<Chatroom> exitedChatrooms = new HashSet<>();
private Set<ChatroomMember> chatroomMembers = new HashSet<>();

@OneToMany(mappedBy = "manager")
@JsonIgnore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ public interface ChatroomResponseDto {

Set<MemberRestrictedResponseDto> getMembers();

Set<MemberRestrictedResponseDto> getExitedMembers();
String getLastChat();
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ public class GroupChatroomResponseDto implements ChatroomResponseDto {

private Set<MemberRestrictedResponseDto> members = new HashSet<>();

private Set<MemberRestrictedResponseDto> exitedMembers = new HashSet<>();

private MemberRestrictedResponseDto manager;

private String name;
Expand All @@ -52,4 +50,6 @@ public class GroupChatroomResponseDto implements ChatroomResponseDto {
private LocalDateTime modified;

private Boolean isEntered;

private String lastChat;
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ public class SingleChatroomResponseDto implements ChatroomResponseDto {
@JsonProperty("chatroom_type")
private ChatroomType chatroomType;

private Set<MemberRestrictedResponseDto> exitedMembers = new HashSet<>();

private Set<MemberRestrictedResponseDto> members = new HashSet<>();

private Long unreadChatsCount = 0L;

private String lastChat;
}
3 changes: 3 additions & 0 deletions src/main/java/com/dife/api/repository/ChatRepository.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.dife.api.repository;

import com.dife.api.model.Chat;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
Expand All @@ -10,4 +11,6 @@ public interface ChatRepository extends JpaRepository<Chat, Long> {
List<Chat> findChatsByChatroomId(Long chatroom_id);

Optional<Chat> findByChatroomIdAndId(Long chatroom_id, Long id);

List<Chat> findByChatroomIdAndCreatedAfter(Long chatroomId, LocalDateTime createdAfter);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.dife.api.repository;

import com.dife.api.model.*;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ChatroomMemberRepository extends JpaRepository<ChatroomMember, Long> {

Optional<ChatroomMember> findByChatroomAndMember(Chatroom chatroom, Member member);

List<ChatroomMember> findAllByMember(Member member);
}
Loading

0 comments on commit bcdad42

Please sign in to comment.