Skip to content

Commit

Permalink
Merge pull request #687 from woowacourse-teams/fix/#684
Browse files Browse the repository at this point in the history
채팅 알림 버그픽스
  • Loading branch information
pricelees authored Oct 21, 2024
2 parents 051eaf6 + 325112c commit 9f15539
Show file tree
Hide file tree
Showing 24 changed files with 368 additions and 213 deletions.
41 changes: 18 additions & 23 deletions backend/src/main/java/mouda/backend/chat/business/ChatService.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.springframework.transaction.annotation.Transactional;

import lombok.RequiredArgsConstructor;
import mouda.backend.chat.domain.Chat;
import mouda.backend.chat.domain.ChatOwnership;
import mouda.backend.chat.domain.ChatRoom;
import mouda.backend.chat.domain.Chats;
Expand All @@ -19,12 +20,10 @@
import mouda.backend.chat.presentation.request.LastReadChatRequest;
import mouda.backend.chat.presentation.request.PlaceConfirmRequest;
import mouda.backend.chat.presentation.response.ChatFindUnloadedResponse;
import mouda.backend.chat.util.DateTimeFormatter;
import mouda.backend.darakbangmember.domain.DarakbangMember;
import mouda.backend.moim.domain.Moim;
import mouda.backend.moim.implement.finder.MoimFinder;
import mouda.backend.moim.implement.writer.MoimWriter;
import mouda.backend.notification.domain.NotificationType;

@Service
@Transactional
Expand All @@ -37,21 +36,6 @@ public class ChatService {
private final MoimFinder moimFinder;
private final ChatNotificationSender chatNotificationSender;

public void createChat(
long darakbangId,
long chatRoomId,
ChatCreateRequest request,
DarakbangMember darakbangMember
) {
ChatRoom chatRoom = chatRoomFinder.read(darakbangId, chatRoomId, darakbangMember);

String content = request.content();
chatWriter.append(chatRoom.getId(), content, darakbangMember);

chatNotificationSender.sendChatNotification(darakbangId, chatRoom, content, darakbangMember,
NotificationType.NEW_CHAT);
}

@Transactional(readOnly = true)
public ChatFindUnloadedResponse findUnloadedChats(
long darakbangId, long recentChatId, long chatRoomId, DarakbangMember darakbangMember
Expand All @@ -64,6 +48,19 @@ public ChatFindUnloadedResponse findUnloadedChats(
return ChatFindUnloadedResponse.toResponse(chatsWithAuthor);
}

public void createChat(
long darakbangId,
long chatRoomId,
ChatCreateRequest request,
DarakbangMember darakbangMember
) {
ChatRoom chatRoom = chatRoomFinder.read(darakbangId, chatRoomId, darakbangMember);

Chat appendedChat = chatWriter.append(chatRoom.getId(), request.content(), darakbangMember);

chatNotificationSender.sendChatNotification(darakbangId, chatRoom, appendedChat);
}

public void confirmPlace(long darakbangId, long chatRoomId, PlaceConfirmRequest request,
DarakbangMember darakbangMember) {
ChatRoom chatRoom = chatRoomFinder.readMoimChatRoom(darakbangId, chatRoomId);
Expand All @@ -72,10 +69,9 @@ public void confirmPlace(long darakbangId, long chatRoomId, PlaceConfirmRequest
Moim moim = moimFinder.read(chatRoom.getTargetId(), darakbangId);
moimWriter.confirmPlace(moim, darakbangMember, place);

chatWriter.appendPlaceTypeChat(chatRoom.getId(), place, darakbangMember);
Chat appendedChat = chatWriter.appendPlaceTypeChat(chatRoom.getId(), place, darakbangMember);

chatNotificationSender.sendChatNotification(darakbangId, chatRoom, place, darakbangMember,
NotificationType.MOIM_PLACE_CONFIRMED);
chatNotificationSender.sendChatNotification(darakbangId, chatRoom, appendedChat);
}

public void confirmDateTime(long darakbangId, long chatRoomId, DateTimeConfirmRequest request,
Expand All @@ -87,10 +83,9 @@ public void confirmDateTime(long darakbangId, long chatRoomId, DateTimeConfirmRe
LocalTime time = request.time();
moimWriter.confirmDateTime(moim, darakbangMember, date, time);

chatWriter.appendDateTimeTypeChat(chatRoom.getId(), date, time, darakbangMember);
Chat appendedChat = chatWriter.appendDateTimeTypeChat(chatRoom.getId(), date, time, darakbangMember);

chatNotificationSender.sendChatNotification(darakbangId, chatRoom, DateTimeFormatter.formatDateTime(date, time),
darakbangMember, NotificationType.MOIM_TIME_CONFIRMED);
chatNotificationSender.sendChatNotification(darakbangId, chatRoom, appendedChat);
}

public void updateLastReadChat(
Expand Down
12 changes: 9 additions & 3 deletions backend/src/main/java/mouda/backend/chat/domain/Author.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,20 @@
@Getter
public class Author {

private final long id;
private final long darakbangMemberId;
private final long memberId;
private final String nickname;
private final String profile;

@Builder
public Author(long id, String nickname, String profile) {
this.id = id;
public Author(long darakbangMemberId, long memberId, String nickname, String profile) {
this.darakbangMemberId = darakbangMemberId;
this.memberId = memberId;
this.nickname = nickname;
this.profile = profile;
}

public boolean isNotSameMember(long darakbangMemberId, long memberId) {
return this.darakbangMemberId != darakbangMemberId || this.memberId != memberId;
}
}
2 changes: 1 addition & 1 deletion backend/src/main/java/mouda/backend/chat/domain/Chat.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ public Chat(long id, String content, Author author, LocalDate date, LocalTime ti
}

public boolean isMine(long darakbangMemberId) {
return author.getId() == darakbangMemberId;
return author.getDarakbangMemberId() == darakbangMemberId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ public enum ChatErrorMessage {
CHATROOM_NOT_FOUND("존재하지 않는 채팅방입니다."),
BET_DARAKBANG_MEMBER_NOT_FOUND("참여하지 않은 안내면진다입니다."),
INVALID_CHATROOM_TYPE("잘못된 채팅 방 타입입니다."),
UNAUTHORIZED("권한이 없습니다.");
UNAUTHORIZED("권한이 없습니다."),

INVALID_DATE_TIME_FORMAT("날짜와 시간 형식이 올바르지 않습니다."),
;

private final String message;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import lombok.RequiredArgsConstructor;
import mouda.backend.bet.implement.BetDarakbangMemberWriter;
import mouda.backend.chat.domain.Chat;
import mouda.backend.chat.domain.ChatRoom;
import mouda.backend.chat.domain.ChatRoomType;
import mouda.backend.chat.entity.ChatEntity;
Expand All @@ -23,7 +24,7 @@ public class ChatWriter {
private final ChamyoWriter chamyoWriter;
private final BetDarakbangMemberWriter betDarakbangMemberWriter;

public void appendPlaceTypeChat(long chatRoomId, String content, DarakbangMember darakbangMember) {
public Chat appendPlaceTypeChat(long chatRoomId, String content, DarakbangMember darakbangMember) {
ChatEntity chatEntity = ChatEntity.builder()
.chatRoomId(chatRoomId)
.content(content)
Expand All @@ -32,10 +33,10 @@ public void appendPlaceTypeChat(long chatRoomId, String content, DarakbangMember
.darakbangMember(darakbangMember)
.chatType(ChatType.PLACE)
.build();
chatRepository.save(chatEntity);
return chatRepository.save(chatEntity).toChat();
}

public void appendDateTimeTypeChat(long chatRoomId, LocalDate date, LocalTime time,
public Chat appendDateTimeTypeChat(long chatRoomId, LocalDate date, LocalTime time,
DarakbangMember darakbangMember) {
ChatEntity chatEntity = ChatEntity.builder()
.chatRoomId(chatRoomId)
Expand All @@ -45,10 +46,10 @@ public void appendDateTimeTypeChat(long chatRoomId, LocalDate date, LocalTime ti
.darakbangMember(darakbangMember)
.chatType(ChatType.DATETIME)
.build();
chatRepository.save(chatEntity);
return chatRepository.save(chatEntity).toChat();
}

public void append(long chatRoomId, String content, DarakbangMember darakbangMember) {
public Chat append(long chatRoomId, String content, DarakbangMember darakbangMember) {
ChatEntity chatEntity = ChatEntity.builder()
.chatRoomId(chatRoomId)
.content(content)
Expand All @@ -57,7 +58,7 @@ public void append(long chatRoomId, String content, DarakbangMember darakbangMem
.darakbangMember(darakbangMember)
.chatType(ChatType.BASIC)
.build();
chatRepository.save(chatEntity);
return chatRepository.save(chatEntity).toChat();
}

public void updateLastReadChat(ChatRoom chatRoom, DarakbangMember darakbangMember, long lastReadChatId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,26 @@

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import mouda.backend.bet.domain.Bet;
import mouda.backend.bet.implement.BetFinder;
import mouda.backend.chat.domain.Chat;
import mouda.backend.chat.domain.ChatRoom;
import mouda.backend.chat.domain.ChatRoomType;
import mouda.backend.chat.entity.ChatType;
import mouda.backend.chat.util.ChatDateTimeFormatter;
import mouda.backend.common.config.UrlConfig;
import mouda.backend.darakbangmember.domain.DarakbangMember;
import mouda.backend.darakbang.domain.Darakbang;
import mouda.backend.darakbang.implement.DarakbangFinder;
import mouda.backend.moim.domain.Moim;
import mouda.backend.moim.implement.finder.ChatRecipientFinder;
import mouda.backend.moim.implement.finder.MoimFinder;
import mouda.backend.notification.domain.NotificationEvent;
import mouda.backend.notification.domain.NotificationType;
import mouda.backend.notification.domain.Recipient;
import mouda.backend.notification.exception.NotificationErrorMessage;
import mouda.backend.notification.exception.NotificationException;

@Component
@EnableConfigurationProperties(UrlConfig.class)
Expand All @@ -33,48 +35,50 @@ public class ChatNotificationSender {
private final ApplicationEventPublisher eventPublisher;
private final MoimFinder moimFinder;
private final BetFinder betFinder;
private final DarakbangFinder darakbangFinder;

public void sendChatNotification(
long darakbangId, ChatRoom chatRoom, String content, DarakbangMember sender, NotificationType notificationType
long darakbangId, ChatRoom chatRoom, Chat appendedChat
) {
ChatRoomType chatRoomType = chatRoom.getType();
long chatRoomId = chatRoom.getId();

if (chatRoomType == ChatRoomType.BET) {
Bet bet = betFinder.find(darakbangId, chatRoom.getTargetId());
sendBetNotification(bet, content, sender, notificationType);
sendBetNotification(bet, appendedChat, chatRoomId);
return;
}

Moim moim = moimFinder.read(chatRoom.getTargetId(), darakbangId);
sendMoimNotification(moim, content, sender, notificationType, chatRoomId);
sendMoimNotification(moim, appendedChat, chatRoomId);
}

private void sendBetNotification(
Bet bet, String content, DarakbangMember sender, NotificationType notificationType
private void sendMoimNotification(
Moim moim, Chat chat, long chatRoomId
) {
List<Recipient> recipients = chatRecipientFinder.getBetChatNotificationRecipients(bet.getId(), sender);
long darakbangId = bet.getDarakbangId();
long chatRoomId = bet.getId();
List<Recipient> recipients = chatRecipientFinder.getMoimChatNotificationRecipients(moim.getId(),
chat.getAuthor());
long darakbangId = moim.getDarakbangId();

publishEvent(notificationType, bet.getTitle(), content, sender, recipients, darakbangId, chatRoomId);
publishEvent(darakbangId, chatRoomId, moim.getTitle(), chat, recipients);
}

private void sendMoimNotification(
Moim moim, String content, DarakbangMember sender, NotificationType notificationType, long chatRoomId
) {
List<Recipient> recipients = chatRecipientFinder.getMoimChatNotificationRecipients(moim.getId(), sender);
long darakbangId = moim.getDarakbangId();
private void sendBetNotification(Bet bet, Chat chat, long chatRoomId) {
List<Recipient> recipients = chatRecipientFinder.getBetChatNotificationRecipients(bet.getId(),
chat.getAuthor());
long darakbangId = bet.getDarakbangId();

publishEvent(notificationType, moim.getTitle(), content, sender, recipients, darakbangId, chatRoomId);
publishEvent(darakbangId, chatRoomId, bet.getTitle(), chat, recipients);
}

private void publishEvent(
NotificationType notificationType, String title, String content, DarakbangMember sender,
List<Recipient> recipients, long darakbangId, long chatRoomId
) {
private void publishEvent(long darakbangId, long chatRoomId, String title, Chat chat, List<Recipient> recipients) {
Darakbang darakbang = darakbangFinder.findById(darakbangId);
ChatNotification chatNotification = ChatNotification.create(darakbang.getName(), title, chat);

NotificationEvent notificationEvent = NotificationEvent.chatEvent(
notificationType,
title,
ChatNotificationMessage.create(content, sender, notificationType),
chatNotification.getType(),
darakbang.getName(),
chatNotification.getMessage(),
urlConfig.getChatRoomUrl(darakbangId, chatRoomId),
recipients,
darakbangId,
Expand All @@ -84,25 +88,43 @@ private void publishEvent(
eventPublisher.publishEvent(notificationEvent);
}

static class ChatNotificationMessage {
@Getter
@RequiredArgsConstructor
static class ChatNotification {

private final String title;
private final NotificationType type;
private final String message;

public static ChatNotification create(String darakbangName, String title, Chat chat) {
ChatType chatType = chat.getChatType();
String content = chat.getContent();

public static String create(String content, DarakbangMember sender, NotificationType type) {
if (type.isConfirmedType()) {
return confirmedChatMessage(content, type);
if (chatType == ChatType.PLACE) {
String message = "'" + title + "'" + " 장소가 '" + content + "' 으로 확정되었어요!";
return placeConfirmChat(darakbangName, message);
}
if (type == NotificationType.NEW_CHAT) {
return sender.getNickname() + ": " + content;
if (chatType == ChatType.DATETIME) {
String parsedDateTime = ChatDateTimeFormatter.formatDateTime(content);
String message = "'" + title + "'" + "시간이 '" + parsedDateTime + "' 으로 확정되었어요!";
return dateTimeConfirmChat(darakbangName, message);
}
throw new NotificationException(
HttpStatus.BAD_REQUEST, NotificationErrorMessage.NOT_ALLOWED_NOTIFICATION_TYPE
);

String authorNickname = chat.getAuthor().getNickname();
String message = authorNickname + ": " + content;
return basicChat(title, message);
}

private static String confirmedChatMessage(String content, NotificationType type) {
if (type == NotificationType.MOIM_PLACE_CONFIRMED) {
return "장소가 '" + content + "' 로 확정되었어요!";
}
return "시간이 '" + content + "' 로 확정되었어요!";
private static ChatNotification placeConfirmChat(String title, String message) {
return new ChatNotification(title, NotificationType.MOIM_PLACE_CONFIRMED, message);
}

private static ChatNotification dateTimeConfirmChat(String title, String message) {
return new ChatNotification(title, NotificationType.MOIM_TIME_CONFIRMED, message);
}

private static ChatNotification basicChat(String title, String message) {
return new ChatNotification(title, NotificationType.NEW_CHAT, message);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package mouda.backend.chat.util;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

import org.springframework.http.HttpStatus;

import lombok.NoArgsConstructor;
import mouda.backend.chat.exception.ChatErrorMessage;
import mouda.backend.chat.exception.ChatException;

/**
* 채팅방에서 날짜와 시간이 확정될 때 알림 메시지에 사용되는 날짜 / 시간 형식 변환을 위한 유틸리티 클래스
*/
@NoArgsConstructor(access = lombok.AccessLevel.PRIVATE)
public class ChatDateTimeFormatter {

private static final String DATETIME_DELIMITER = " ";
private static final int DATE_PART = 0;
private static final int TIME_PART = 1;

public static String formatDateTime(String dateTime) {
LocalDateTime localDateTime = parseDateTime(dateTime);
StringBuilder formattedDateTime = new StringBuilder();

int year = localDateTime.getYear();
if (year > LocalDate.now().getYear()) {
formattedDateTime.append(year).append("년 ");
}

return formattedDateTime
.append(localDateTime.getMonthValue()).append("월 ")
.append(localDateTime.getDayOfMonth()).append("일 ")
.append(localDateTime.getHour()).append("시 ")
.append(localDateTime.getMinute()).append("분")
.toString();
}

private static LocalDateTime parseDateTime(String dateTime) {
try {
String[] dateTimeParts = dateTime.split(DATETIME_DELIMITER);
LocalDate date = LocalDate.parse(dateTimeParts[DATE_PART]);
LocalTime time = LocalTime.parse(dateTimeParts[TIME_PART]);

return LocalDateTime.of(date, time);
} catch (Exception e) {
throw new ChatException(HttpStatus.BAD_REQUEST, ChatErrorMessage.INVALID_DATE_TIME_FORMAT);
}
}
}
Loading

0 comments on commit 9f15539

Please sign in to comment.