Skip to content
Open
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
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
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import mannabom_server.manabom.domain.chat.entity.ChatRoom;
import mannabom_server.manabom.domain.chat.enums.ChatMemberStatus;
import mannabom_server.manabom.domain.chat.enums.ChatMessageType;
import mannabom_server.manabom.domain.chat.enums.ChatStatus;
import mannabom_server.manabom.domain.chat.repository.ChatMemberQueryRepository;
import mannabom_server.manabom.domain.chat.repository.ChatMemberRepository;
import mannabom_server.manabom.domain.chat.repository.ChatMessageRepository;
Expand Down Expand Up @@ -135,15 +136,75 @@ public Long joinChatRoom(Meeting meeting, User user){
return room.getId();
}

@Transactional
public Long joinMatchingChatRoom(MeetingMatch match, User user) {
ChatRoom room = chatRoomRepository.findByMatch(match)
.orElseThrow(() -> new IllegalArgumentException(
"매칭 정보와 연결된 남녀 채팅방이 존재하지 않습니다."
));

if (chatMemberRepository.existsByRoomIdAndUser_UserIdAndStatus(
room.getId(),
user.getUserId(),
ChatMemberStatus.ACTIVATE
)) {
throw new IllegalStateException("이미 해당 매칭 채팅방에 참여한 사용자입니다.");
}

chatMemberRepository.save(ChatMember.create(room, user));
return room.getId();
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

@Transactional
public void disableMeetingGroupChatRooms(MeetingMatch match) {
disableMeetingGroupChatRoom(match.getMeeting1());
disableMeetingGroupChatRoom(match.getMeeting2());
}

@Transactional
public void deactivateMeetingGroupMember(Meeting meeting, Long userId) {
ChatRoom room = chatRoomRepository.findByMeeting(meeting)
.orElseThrow(() -> new IllegalArgumentException(
"미팅과 연결된 동성 채팅방이 존재하지 않습니다."
));

chatMemberRepository.findByRoomIdAndUser_UserIdAndStatus(
room.getId(),
userId,
ChatMemberStatus.ACTIVATE
).ifPresent(ChatMember::deactivate);
}

private void disableMeetingGroupChatRoom(Meeting meeting) {
ChatRoom room = chatRoomRepository.findByMeeting(meeting)
.orElseThrow(() -> new IllegalArgumentException(
"미팅과 연결된 동성 채팅방이 존재하지 않습니다."
));
room.deactivate();
}

public Long getChatRoomId(Meeting meeting){
ChatRoom room = chatRoomRepository.findByMeeting(meeting)
.orElseThrow(()-> new IllegalArgumentException("미팅id와 연결된 채팅방: 존재하지 않은 채팅방입니다."));
return room.getId();
}

public Long getMatchingChatRoomId(MeetingMatch match) {
return chatRoomRepository.findByMatch(match)
.map(ChatRoom::getId)
.orElseThrow(() -> new IllegalArgumentException(
"매칭 정보와 연결된 남녀 채팅방이 존재하지 않습니다."
));
}

public void leaveChatRoom(Long roomId, Long userId){
ChatRoom room = chatRoomRepository.findById(roomId)
.orElseThrow(()-> new IllegalArgumentException("채팅방 나가기: 존재하지 않는 채팅방아이디 입니다."));

if (room.getChatStatus() == ChatStatus.DISABLED) {
throw new IllegalStateException("비활성화된 채팅방에서는 나갈 수 없습니다.");
}

ChatMember chatMember = chatMemberRepository.findByRoomIdAndUser_UserIdAndStatus(roomId, userId, ChatMemberStatus.ACTIVATE)
.orElseThrow(()-> new IllegalArgumentException("방에 참여중인 유저가 아닙니다."));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import mannabom_server.manabom.domain.chat.entity.ChatMessage;
import mannabom_server.manabom.domain.chat.entity.ChatRoom;
import mannabom_server.manabom.domain.chat.enums.ChatMemberStatus;
import mannabom_server.manabom.domain.chat.enums.ChatStatus;
import mannabom_server.manabom.domain.chat.repository.ChatMemberRepository;
import mannabom_server.manabom.domain.chat.repository.ChatMessageRepository;
import mannabom_server.manabom.domain.chat.repository.ChatRoomRepository;
Expand Down Expand Up @@ -54,6 +55,9 @@ public class ChatService {
public void sendMessage(ChatSendRequest request, Long userId) {
ChatRoom chatRoom = chatRoomRepository.findById(request.getRoomId())
.orElseThrow(() -> new IllegalArgumentException("존재하지 않는 채팅방입니다."));
if (chatRoom.getChatStatus() == ChatStatus.DISABLED) {
throw new IllegalStateException("비활성화된 채팅방에는 메시지를 보낼 수 없습니다.");
}
ChatMember sender = chatMemberRepository.findByRoomIdAndUser_UserIdAndStatus(request.getRoomId(), userId, ChatMemberStatus.ACTIVATE)
.orElseThrow(()-> new IllegalArgumentException("참여중인 채팅방이 아닙니다."));
User user = userRepository.findById(userId)
Expand Down Expand Up @@ -118,7 +122,12 @@ private void sendNotificationWithSSEOrPush(ChatSendRequest request, List<ChatMem
*/
@Transactional(readOnly = true)
public ChatInitialSyncResponse getInitialSync(Long userId) {
List<ChatMember> myRooms = chatMemberRepository.findAllByUser_UserIdAndStatus(userId, ChatMemberStatus.ACTIVATE);
List<ChatMember> myRooms = chatMemberRepository
.findAllByUser_UserIdAndStatusAndRoom_ChatStatus(
userId,
ChatMemberStatus.ACTIVATE,
ChatStatus.ENABLED
);

boolean hasUnreadMessages = false;
boolean hasNewRoom = false;
Expand All @@ -144,7 +153,12 @@ public ChatInitialSyncResponse getInitialSync(Long userId) {
*/
@Transactional(readOnly = true)
public List<ChatRoomListResponse> getChatRoomListSync(Long userId) {
List<ChatMember> myRooms = chatMemberRepository.findAllByUser_UserIdAndStatus(userId, ChatMemberStatus.ACTIVATE);
List<ChatMember> myRooms = chatMemberRepository
.findAllByUser_UserIdAndStatusAndRoom_ChatStatus(
userId,
ChatMemberStatus.ACTIVATE,
ChatStatus.ENABLED
);

return myRooms.stream().map(m -> {
ChatRoom room = m.getRoom();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package mannabom_server.manabom.application.meeting.dto.request;

import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.NoArgsConstructor;
import mannabom_server.manabom.domain.meeting.enums.CancellationVoteDecision;

@Getter
@NoArgsConstructor
public class MeetingCancellationVoteRequest {

@NotNull(message = "동의 또는 비동의를 선택해야 합니다.")
private CancellationVoteDecision decision;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package mannabom_server.manabom.application.meeting.dto.response;

import lombok.Builder;
import lombok.Getter;
import mannabom_server.manabom.domain.meeting.entity.MeetingCancellationRequest;
import mannabom_server.manabom.domain.meeting.entity.MeetingCancellationVote;
import mannabom_server.manabom.domain.meeting.enums.CancellationVoteDecision;
import mannabom_server.manabom.domain.meeting.enums.MeetingCancellationStatus;

import java.time.Instant;
import java.util.List;

@Getter
@Builder
public class MeetingCancellationResponse {
private Long requestId;
private Long matchId;
private Long initiatorUserId;
private MeetingCancellationStatus status;
private Instant requestedAt;
private Instant expiresAt;
private Instant completedAt;
private int totalMemberCount;
private int agreedMemberCount;
private int pendingMemberCount;
private List<MeetingCancellationVoteResponse> votes;

public static MeetingCancellationResponse of(
MeetingCancellationRequest request,
List<MeetingCancellationVote> votes
) {
int agreed = (int) votes.stream()
.filter(vote -> vote.getDecision() == CancellationVoteDecision.AGREE)
.count();
int pending = (int) votes.stream()
.filter(vote -> vote.getDecision() == CancellationVoteDecision.PENDING)
.count();

return MeetingCancellationResponse.builder()
.requestId(request.getId())
.matchId(request.getMeetingMatch().getId())
.initiatorUserId(request.getInitiator().getUserId())
.status(request.getStatus())
.requestedAt(request.getRequestedAt())
.expiresAt(request.getExpiresAt())
.completedAt(request.getCompletedAt())
.totalMemberCount(votes.size())
.agreedMemberCount(agreed)
.pendingMemberCount(pending)
.votes(votes.stream()
.map(MeetingCancellationVoteResponse::from)
.toList())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package mannabom_server.manabom.application.meeting.dto.response;

import lombok.Builder;
import lombok.Getter;
import mannabom_server.manabom.domain.meeting.entity.MeetingCancellationVote;
import mannabom_server.manabom.domain.meeting.enums.CancellationVoteDecision;

import java.time.Instant;

@Getter
@Builder
public class MeetingCancellationVoteResponse {
private Long userId;
private CancellationVoteDecision decision;
private Instant decidedAt;

public static MeetingCancellationVoteResponse from(MeetingCancellationVote vote) {
return MeetingCancellationVoteResponse.builder()
.userId(vote.getUser().getUserId())
.decision(vote.getDecision())
.decidedAt(vote.getDecidedAt())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package mannabom_server.manabom.application.meeting.scheduler;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import mannabom_server.manabom.application.meeting.service.MeetingCancellationService;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
@Slf4j
@RequiredArgsConstructor
public class MeetingCancellationScheduler {

private final MeetingCancellationService meetingCancellationService;

@Scheduled(fixedDelayString = "${meeting.cancellation.expiration-check-delay:60000}")
public void expireCancellationRequests() {
int expiredCount = meetingCancellationService.expirePendingRequests();
if (expiredCount > 0) {
log.info("만료된 미팅 전체 취소 요청 {}건을 처리했습니다.", expiredCount);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package mannabom_server.manabom.application.meeting.service;

import lombok.RequiredArgsConstructor;
import mannabom_server.manabom.domain.meeting.entity.MeetingCancellationRequest;
import mannabom_server.manabom.domain.meeting.repository.MeetingCancellationRequestRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;

@Service
@RequiredArgsConstructor
public class MeetingCancellationExpirationService {

private final MeetingCancellationRequestRepository requestRepository;

@Transactional(propagation = Propagation.REQUIRES_NEW)
public boolean expire(Long requestId, Instant now) {
MeetingCancellationRequest request = requestRepository.findByIdForUpdate(requestId)
.orElse(null);

if (request == null || !request.isExpiredAt(now)) {
return false;
}

request.expire(now);
return true;
}
}
Loading