Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

채팅 알림 버그픽스 #687

Open
wants to merge 12 commits into
base: develop-backend
Choose a base branch
from
Open
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
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