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
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public record ChatRoomItemResponse(
Long chatRoomId,
ChatType chatType,
String chatRoomName,
String thumbnail,
Long groupId,
int participantCount,
LastMessageResponse lastMessage,
Expand All @@ -17,6 +18,7 @@ public record ChatRoomItemResponse(
public static ChatRoomItemResponse of(
ChatRoom chatRoom,
String chatRoomName,
String thumbnail,
int participantCount,
LastMessageResponse lastMessage,
int unreadCount
Expand All @@ -25,6 +27,7 @@ public static ChatRoomItemResponse of(
chatRoom.getId(),
chatRoom.getChatType(),
chatRoomName,
thumbnail,
chatRoom.getGroup() != null ? chatRoom.getGroup().getId() : null,
participantCount,
lastMessage,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public record ChatRoomResponse(
Long chatRoomId,
ChatType chatType,
String chatRoomName,
String thumbnail,
Long groupId,
int participantCount,
List<ParticipantResponse> participants,
Expand All @@ -18,12 +19,14 @@ public record ChatRoomResponse(
public static ChatRoomResponse of(
ChatRoom chatRoom,
String chatRoomName,
String thumbnail,
List<ParticipantResponse> participants
) {
return new ChatRoomResponse(
chatRoom.getId(),
chatRoom.getChatType(),
chatRoomName,
thumbnail,
chatRoom.getGroup() != null ? chatRoom.getGroup().getId() : null,
participants.size(),
participants,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,17 @@ public record ParticipantResponse(
String nickName,
String profileImage,
ParticipantStatus status,
boolean isOwner,
LocalDateTime joinedAt
) {
public static ParticipantResponse from(ChatParticipant participant) {
public static ParticipantResponse from(ChatParticipant participant, boolean isOwner) {
return new ParticipantResponse(
participant.getId(),
participant.getUser().getId(),
participant.getUser().getNickName(),
participant.getUser().getProfileImage(),
participant.getStatus(),
isOwner,
participant.getJoinedAt()
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
import team.wego.wegobackend.chat.config.ChatProperties;
import team.wego.wegobackend.chat.domain.entity.JoinType;
import team.wego.wegobackend.group.v2.application.event.GroupCreatedEvent;
import team.wego.wegobackend.group.v2.application.event.GroupJoinApprovedEvent;
import team.wego.wegobackend.group.v2.application.event.GroupJoinedEvent;
import team.wego.wegobackend.group.v2.application.event.GroupJoinKickedEvent;
import team.wego.wegobackend.group.v2.application.event.GroupLeftEvent;

@Component
Expand Down Expand Up @@ -68,6 +70,34 @@ public void handleGroupJoined(GroupJoinedEvent event) {
}
}

/**
* 모임 참여 승인 시 채팅방 자동 참여 (승인제 모임)
*/
@EventListener
@Async
public void handleGroupJoinApproved(GroupJoinApprovedEvent event) {
log.info("모임 참여 승인 이벤트 수신 - groupId: {}, targetUserId: {}",
event.groupId(), event.targetUserId());

if (!chatProperties.getAutoJoin().isEnabled()) {
log.debug("자동 참여 비활성화 - groupId: {}", event.groupId());
return;
}

try {
chatRoomService.joinChatRoomByGroup(
event.groupId(),
event.targetUserId(),
JoinType.AUTO
);
log.info("채팅방 자동 참여 완료 (승인) - groupId: {}, userId: {}",
event.groupId(), event.targetUserId());
} catch (Exception e) {
log.error("채팅방 자동 참여 실패 (승인) - groupId: {}, userId: {}",
event.groupId(), event.targetUserId(), e);
}
}

/**
* 모임 퇴장 시 채팅방 퇴장 처리 (선택 사항)
*/
Expand All @@ -89,4 +119,26 @@ public void handleGroupLeft(GroupLeftEvent event) {
event.groupId(), event.leaverUserId(), e);
}
}

/**
* 모임 추방 시 채팅방 퇴장 처리
*/
@EventListener
@Async
public void handleGroupKicked(GroupJoinKickedEvent event) {
log.info("모임 추방 이벤트 수신 - groupId: {}, targetUserId: {}",
event.groupId(), event.targetUserId());

try {
chatRoomService.leaveChatRoomByGroup(
event.groupId(),
event.targetUserId()
);
log.info("채팅방 추방 처리 완료 - groupId: {}, userId: {}",
event.groupId(), event.targetUserId());
} catch (Exception e) {
log.error("채팅방 추방 처리 실패 - groupId: {}, userId: {}",
event.groupId(), event.targetUserId(), e);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package team.wego.wegobackend.chat.application.service;

import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
Expand All @@ -24,7 +25,10 @@
import team.wego.wegobackend.chat.domain.repository.ChatMessageRepository;
import team.wego.wegobackend.chat.domain.repository.ChatParticipantRepository;
import team.wego.wegobackend.chat.domain.repository.ChatRoomRepository;
import team.wego.wegobackend.group.v2.domain.entity.GroupImageV2;
import team.wego.wegobackend.group.v2.domain.entity.GroupImageV2VariantType;
import team.wego.wegobackend.group.v2.domain.entity.GroupV2;
import team.wego.wegobackend.group.v2.domain.repository.GroupImageV2Repository;
import team.wego.wegobackend.group.v2.domain.repository.GroupV2Repository;
import team.wego.wegobackend.user.domain.User;
import team.wego.wegobackend.user.repository.UserRepository;
Expand All @@ -40,6 +44,7 @@ public class ChatRoomService {
private final ChatMessageRepository chatMessageRepository;
private final UserRepository userRepository;
private final GroupV2Repository groupV2Repository;
private final GroupImageV2Repository groupImageV2Repository;

/**
* 내 채팅방 목록 조회
Expand All @@ -49,6 +54,10 @@ public ChatRoomListResponse getMyChatRooms(Long userId) {

List<ChatRoomItemResponse> items = chatRooms.stream()
.map(chatRoom -> buildChatRoomItem(chatRoom, userId))
.sorted(Comparator.comparing(
item -> item.lastMessage() != null ? item.lastMessage().timestamp() : null, //Group 채팅의 경우 lastMessage가 비어있는 경우 존재 -> NPE 처리
Comparator.nullsLast(Comparator.reverseOrder()) // null 처리 + 최신순
))
.collect(Collectors.toList());

return ChatRoomListResponse.from(items);
Expand All @@ -61,15 +70,17 @@ public ChatRoomResponse getChatRoom(Long userId, Long roomId) {
ChatRoom chatRoom = findChatRoomById(roomId);
validateParticipant(chatRoom.getId(), userId);

Long hostId = chatRoom.getHostId();
List<ParticipantResponse> participants = chatParticipantRepository
.findActiveParticipants(roomId)
.stream()
.map(ParticipantResponse::from)
.map(p -> ParticipantResponse.from(p, isOwner(p, hostId)))
.collect(Collectors.toList());

String chatRoomName = resolveChatRoomName(chatRoom, userId);
String thumbnail = resolveThumbnail(chatRoom, userId);

return ChatRoomResponse.of(chatRoom, chatRoomName, participants);
return ChatRoomResponse.of(chatRoom, chatRoomName, thumbnail, participants);
}

/**
Expand All @@ -79,10 +90,11 @@ public ParticipantListResponse getParticipants(Long userId, Long roomId) {
ChatRoom chatRoom = findChatRoomById(roomId);
validateParticipant(chatRoom.getId(), userId);

Long hostId = chatRoom.getHostId();
List<ParticipantResponse> participants = chatParticipantRepository
.findActiveParticipants(roomId)
.stream()
.map(ParticipantResponse::from)
.map(p -> ParticipantResponse.from(p, isOwner(p, hostId)))
.collect(Collectors.toList());

return ParticipantListResponse.of(roomId, participants);
Expand Down Expand Up @@ -268,6 +280,7 @@ private void validateHost(ChatRoom chatRoom, Long userId) {

private ChatRoomItemResponse buildChatRoomItem(ChatRoom chatRoom, Long userId) {
String chatRoomName = resolveChatRoomName(chatRoom, userId);
String thumbnail = resolveThumbnail(chatRoom, userId);
int participantCount = chatParticipantRepository.countActiveParticipants(chatRoom.getId());

LastMessageResponse lastMessage = chatMessageRepository.findLatestByChatRoomId(chatRoom.getId())
Expand All @@ -279,19 +292,21 @@ private ChatRoomItemResponse buildChatRoomItem(ChatRoom chatRoom, Long userId) {

int unreadCount = calculateUnreadCount(chatRoom.getId(), userId);

return ChatRoomItemResponse.of(chatRoom, chatRoomName, participantCount, lastMessage, unreadCount);
return ChatRoomItemResponse.of(chatRoom, chatRoomName, thumbnail, participantCount, lastMessage, unreadCount);
}

private ChatRoomResponse buildChatRoomResponse(ChatRoom chatRoom, Long userId) {
String chatRoomName = resolveChatRoomName(chatRoom, userId);
String thumbnail = resolveThumbnail(chatRoom, userId);

Long hostId = chatRoom.getHostId();
List<ParticipantResponse> participants = chatParticipantRepository
.findActiveParticipants(chatRoom.getId())
.stream()
.map(ParticipantResponse::from)
.map(p -> ParticipantResponse.from(p, isOwner(p, hostId)))
.collect(Collectors.toList());

return ChatRoomResponse.of(chatRoom, chatRoomName, participants);
return ChatRoomResponse.of(chatRoom, chatRoomName, thumbnail, participants);
}

private String resolveChatRoomName(ChatRoom chatRoom, Long userId) {
Expand All @@ -308,6 +323,39 @@ private String resolveChatRoomName(ChatRoom chatRoom, Long userId) {
.orElse("알 수 없음");
}

private String resolveThumbnail(ChatRoom chatRoom, Long userId) {
if (chatRoom.getChatType() == ChatType.GROUP && chatRoom.getGroup() != null) {
// 그룹 채팅: 그룹의 첫 번째 이미지의 THUMBNAIL_100_100 variant
List<GroupImageV2> images = groupImageV2Repository
.findAllByGroupIdWithVariants(chatRoom.getGroup().getId());

if (images.isEmpty()) {
return null;
}

return images.get(0).getVariants().stream()
.filter(v -> v.getType() == GroupImageV2VariantType.THUMBNAIL_100_100)
.findFirst()
.map(v -> v.getImageUrl())
.orElse(null);
}

// DM인 경우 상대방 프로필 이미지 반환
return chatParticipantRepository.findActiveParticipants(chatRoom.getId())
.stream()
.filter(p -> !p.getUser().getId().equals(userId))
.findFirst()
.map(p -> p.getUser().getProfileImage())
.orElse(null);
}

private boolean isOwner(ChatParticipant participant, Long hostId) {
if (hostId == null) {
return false;
}
return participant.getUser().getId().equals(hostId);
}

private int calculateUnreadCount(Long roomId, Long userId) {
return chatParticipantRepository.findByChatRoomIdAndUserId(roomId, userId)
.filter(ChatParticipant::isActive)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ public Message<?> preSend(Message<?> message, MessageChannel channel) {
}
}

//TODO: StompCommand.SUBSCRIBE 분기 처리 로직 추가 (그룹 채팅 참여 검증 로직)

return message;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import lombok.NoArgsConstructor;
import team.wego.wegobackend.common.entity.BaseTimeEntity;
import team.wego.wegobackend.group.v2.domain.entity.GroupV2;
import team.wego.wegobackend.user.domain.User;

@Entity
@Table(name = "chat_room")
Expand Down Expand Up @@ -87,6 +88,20 @@ public boolean isDmChat() {
return chatType == ChatType.DM;
}

public boolean isHost(User user) {
if (!isGroupChat() || group == null) {
return false;
}
return group.getHost().getId().equals(user.getId());
}

public Long getHostId() {
if (!isGroupChat() || group == null) {
return null;
}
return group.getHost().getId();
}

public void addParticipant(ChatParticipant participant) {
this.participants.add(participant);
participant.assignToChatRoom(this);
Expand All @@ -96,4 +111,5 @@ public void addMessage(ChatMessage message) {
this.messages.add(message);
message.assignToChatRoom(this);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,16 @@ public record GetGroupV2Response(
LocalDateTime createdAt,
LocalDateTime updatedAt,
MyMembership myMembership, // 로그인 아니면 null
List<JoinedMember> joinedMembers // Host면 전체, 아니면 ATTEND만
List<JoinedMember> joinedMembers, // Host면 전체, 아니면 ATTEND만
Long chatRoomId // 채팅방 참여를 위한 ID
) {

public static GetGroupV2Response of(
GroupV2 group,
List<GroupImageV2> images,
List<GroupUserV2> users,
Long userIdOrNull
Long userIdOrNull,
Long chatRoomId
) {
// 태그
List<String> tagNames = group.getGroupTags().stream()
Expand Down Expand Up @@ -106,7 +108,8 @@ public static GetGroupV2Response of(
group.getCreatedAt(),
group.getUpdatedAt(),
myMembership,
joinedMembers
joinedMembers,
chatRoomId
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,8 @@ public GetGroupV2Response getGroup(Long userId, Long groupId) {
List<GroupImageV2> images = groupImageV2Repository.findAllByGroupIdWithVariants(groupId);
List<GroupUserV2> users = groupUserV2Repository.findAllByGroupIdWithUser(groupId);

return GetGroupV2Response.of(group, images, users, userId);
Long chatRoomId = group.getChatRoom() != null ? group.getChatRoom().getId() : null;

return GetGroupV2Response.of(group, images, users, userId, chatRoomId);
}
}
4 changes: 3 additions & 1 deletion src/main/java/team/wego/wegobackend/user/domain/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,11 @@ public class User extends BaseTimeEntity {
@Column(name = "provider")
private ProviderType provider;

@Builder.Default
@OneToMany(mappedBy = "follower")
private List<Follow> followings = new ArrayList<>();

@Builder.Default
@OneToMany(mappedBy = "followee")
private List<Follow> followers = new ArrayList<>();

Expand Down Expand Up @@ -168,7 +170,7 @@ public void updateNotificationEnabled(Boolean flag) {

public void updatedeleted(Boolean flag) {
this.deleted = flag;
}
} //HARD DELETE로 변경

public void updateMbti(String mbti) {
this.mbti = mbti;
Expand Down
Loading