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 @@ -26,62 +26,59 @@ public class PartyNotificationService {
private final NotificationLogService notificationLogService;
private final NotificationTransactionHelper notificationTransactionHelper;

//
@Transactional
public void sendApprovalNotification(Long targetUserId, Long partyId) {
String title = "🎉 파티 참여 승인";
String detail = "파티 참여가 승인되었습니다! 지금 확인하세요.";
notificationLogService.saveLog(targetUserId, NotificationType.PARTY_APPROVAL.name(), title, detail);
public void sendNewPartyRequestNotification(Long managerId, String requesterNickname, String partyTitle, Long partyId) {
String title = String.format("🍽️ [%s]님이 참여 요청했어요", requesterNickname);
String detail = String.format("‘[%s]’ 파티 승인 여부를 확인해 주세요", partyTitle);

List<String> tokens = fcmTokenService.getTokensAndLogIfEmpty(targetUserId);
notificationLogService.saveLog(managerId, NotificationType.PARTY_NEW_REQUEST.name(), title, detail);

List<String> tokens = fcmTokenService.getTokensAndLogIfEmpty(managerId);
if (tokens.isEmpty()) {
return;
}

NotificationMulticastRequest request =
partyMessageManager.createApprovalRequest(tokens, partyId, title, detail);
partyMessageManager.createNewPartyRequest(tokens, partyId, title, detail);

BatchResponse response = fcmNotificationSender.send(request);
notificationTransactionHelper.handleBatchResponse(response, tokens);
}

//
@Transactional
public void sendRejectionNotification(Long targetUserId, Long partyId) {
String title = "🚨 파티 참여 거절";
String detail = "죄송합니다. 파티 참여가 거절되었습니다.";
notificationLogService.saveLog(targetUserId, NotificationType.PARTY_REJECTION.name(), title, detail);
public void sendApprovalNotification(Long targetUserId, String partyTitle, Long partyId) {
// 참여 승인 (파티원에게 전송)
String title = String.format("🍽️ ‘[%s]’ 파티 승인 완료!", partyTitle);
String detail = "파티 채팅방에 입장했어요";

notificationLogService.saveLog(targetUserId, NotificationType.PARTY_APPROVAL.name(), title, detail);

List<String> tokens = fcmTokenService.getTokensAndLogIfEmpty(targetUserId);
if (tokens.isEmpty()) {
return;
}
if (tokens.isEmpty()) return;

NotificationMulticastRequest request =
partyMessageManager.createRejectionRequest(tokens, partyId, title, detail);
partyMessageManager.createApprovalRequest(tokens, partyId, title, detail);

BatchResponse response = fcmNotificationSender.send(request);
notificationTransactionHelper.handleBatchResponse(response, tokens);
}

/**
* 아래 메서드들 파티장,파티멤버의 알림 내용 다른지에 따라 추후 수정 필요
*/

//
@Transactional
public void sendAutoCloseNotification(List<Long> memberIds, Long partyId, Long managerId) {
String title = "🎉 파티 자동 마감";
String memberDetail = "참여 인원이 모두 차서 파티가 마감되었습니다.";
String managerDetail = "축하합니다! 목표 인원 달성으로 파티가 자동 마감되었습니다.";
public void sendRejectionNotification(Long targetUserId, String partyTitle, Long partyId) {
// 참여 거절 (파티원에게 전송)
String title = String.format("🍽️ ‘[%s]’ 😢 참여 거절", partyTitle);
String detail = "아쉽게도 이번 파티는 함께하지 못해요";

memberIds.forEach(userId -> {
String detail = userId.equals(managerId) ? managerDetail : memberDetail;
notificationLogService.saveLog(userId, NotificationType.PARTY_AUTO_CLOSE.name(), title, detail);
});
notificationLogService.saveLog(targetUserId, NotificationType.PARTY_REJECTION.name(), title, detail);

List<String> tokens = fcmTokenService.getMulticastTokensAndLogIfEmpty(memberIds);
if (tokens.isEmpty()) {
return;
}
List<String> tokens = fcmTokenService.getTokensAndLogIfEmpty(targetUserId);
if (tokens.isEmpty()) return;

NotificationMulticastRequest request =
partyMessageManager.createAutoCloseRequest(tokens, partyId, title, memberDetail);
partyMessageManager.createRejectionRequest(tokens, partyId, title, detail);

BatchResponse response = fcmNotificationSender.send(request);
notificationTransactionHelper.handleBatchResponse(response, tokens);
Expand Down Expand Up @@ -147,46 +144,46 @@ public void sendDeliveryReminderNotification(List<Long> memberIds, Long partyId,
}
}

//
@Transactional
public void sendPartyCompleteNotification(List<Long> memberIds, Long partyId) {
String title = "👋 파티 종료";
String detail = "파티장이 수령 완료 처리했습니다. 파티가 종료되었습니다.";
memberIds.forEach(userId ->
notificationLogService.saveLog(userId, NotificationType.PARTY_COMPLETE.name(), title, detail)
);
public void sendAutoCloseNotification(List<Long> memberIds, String partyTitle, Long partyId, Long managerId) {
String title = String.format("🎯 [%s] 인원 모집 완료 !", partyTitle);
String detail = "파티가 시작 되었어요";

memberIds.forEach(userId -> {
notificationLogService.saveLog(userId, NotificationType.PARTY_AUTO_CLOSE.name(), title, detail);
});

List<String> tokens = fcmTokenService.getMulticastTokensAndLogIfEmpty(memberIds);
if (tokens.isEmpty()) {
return;
}
if (tokens.isEmpty()) return;

NotificationMulticastRequest request =
partyMessageManager.createPartyCompleteRequest(tokens, partyId, title, detail);
partyMessageManager.createAutoCloseRequest(tokens, partyId, title, detail);

BatchResponse response = fcmNotificationSender.send(request);
notificationTransactionHelper.handleBatchResponse(response, tokens);
}

//
@Transactional
public void sendNewPartyRequestNotification(Long managerId, Long partyId) {
String title = "🔔 새 참여 요청";
String detail = "새로운 참여 요청이 도착했습니다. 지금 승인해 주세요.";
public void sendPartyCompleteNotification(List<Long> memberIds, String partyTitle, Long partyId) {
String title = String.format("✅ [%s] 파티 종료", partyTitle);
String detail = "참여해 주셔서 감사합니다";

notificationLogService.saveLog(managerId, NotificationType.PARTY_NEW_REQUEST.name(), title, detail);
memberIds.forEach(userId ->
notificationLogService.saveLog(userId, NotificationType.PARTY_COMPLETE.name(), title, detail)
);

List<String> tokens = fcmTokenService.getTokensAndLogIfEmpty(managerId);
if (tokens.isEmpty()) {
return;
}
List<String> tokens = fcmTokenService.getMulticastTokensAndLogIfEmpty(memberIds);
if (tokens.isEmpty()) return;

NotificationMulticastRequest request =
partyMessageManager.createNewPartyRequest(tokens, partyId, title, detail);
partyMessageManager.createPartyCompleteRequest(tokens, partyId, title, detail);

BatchResponse response = fcmNotificationSender.send(request);
notificationTransactionHelper.handleBatchResponse(response, tokens);
}


@Transactional
public void sendMemberLeaveNotification(Long managerId, Long partyId, String leaverName) {
String title = "⚠️ 파티원 이탈";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@

import ita.tinybite.domain.notification.service.ChatNotificationService;
import ita.tinybite.domain.notification.service.PartyNotificationService;
import ita.tinybite.domain.party.entity.Party;
import ita.tinybite.domain.party.repository.PartyRepository;
import ita.tinybite.domain.user.entity.User;
import ita.tinybite.domain.user.repository.UserRepository;
import ita.tinybite.global.exception.BusinessException;
import ita.tinybite.global.exception.errorcode.PartyErrorCode;
import ita.tinybite.global.exception.errorcode.UserErrorCode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

Expand All @@ -22,39 +29,65 @@ public class NotificationFacade {
private final PartyNotificationService partyNotificationService;
private final ChatNotificationService chatNotificationService;

private final PartyRepository partyRepository;
private final UserRepository userRepository;

@Transactional
public void notifyNewPartyRequest(Long managerId, Long requesterId, Long partyId) {
Party party = partyRepository.findById(partyId)
.orElseThrow(() -> new BusinessException(PartyErrorCode.PARTY_NOT_FOUND));

User requester = userRepository.findById(requesterId)
.orElseThrow(() -> new BusinessException(UserErrorCode.USER_NOT_EXISTS));

partyNotificationService.sendNewPartyRequestNotification(
managerId,
requester.getNickname(),
party.getTitle(),
partyId
);
}

@Transactional
public void notifyApproval(Long targetUserId, Long partyId) {
partyNotificationService.sendApprovalNotification(targetUserId, partyId);
Party party = partyRepository.findById(partyId)
.orElseThrow(() -> new BusinessException(PartyErrorCode.PARTY_NOT_FOUND));
partyNotificationService.sendApprovalNotification(targetUserId, party.getTitle(), partyId);
}

@Transactional
public void notifyRejection(Long targetUserId, Long partyId) {
partyNotificationService.sendRejectionNotification(targetUserId, partyId);
Party party = partyRepository.findById(partyId)
.orElseThrow(() -> new BusinessException(PartyErrorCode.PARTY_NOT_FOUND));
partyNotificationService.sendRejectionNotification(targetUserId, party.getTitle(), partyId);
}

// 인원 모집 완료
@Transactional
public void notifyPartyAutoClose(List<Long> memberIds, Long partyId, Long managerId) {
partyNotificationService.sendAutoCloseNotification(memberIds, partyId, managerId);
}
Party party = partyRepository.findById(partyId)
.orElseThrow(() -> new BusinessException(PartyErrorCode.PARTY_NOT_FOUND));

@Transactional
public void notifyOrderComplete(List<Long> memberIds, Long partyId) {
partyNotificationService.sendOrderCompleteNotification(memberIds, partyId);
partyNotificationService.sendAutoCloseNotification(memberIds, party.getTitle(), partyId, managerId);
}

// 파티 종료
@Transactional
public void notifyDeliveryReminder(List<Long> memberIds, Long partyId, Long managerId) {
partyNotificationService.sendDeliveryReminderNotification(memberIds, partyId, managerId);
public void notifyPartyComplete(List<Long> memberIds, Long partyId) {
Party party = partyRepository.findById(partyId)
.orElseThrow(() -> new BusinessException(PartyErrorCode.PARTY_NOT_FOUND));

partyNotificationService.sendPartyCompleteNotification(memberIds, party.getTitle(), partyId);
}

@Transactional
public void notifyPartyComplete(List<Long> memberIds, Long partyId) {
partyNotificationService.sendPartyCompleteNotification(memberIds, partyId);
public void notifyOrderComplete(List<Long> memberIds, Long partyId) {
partyNotificationService.sendOrderCompleteNotification(memberIds, partyId);
}

@Transactional
public void notifyNewPartyRequest(Long managerId, Long partyId) {
partyNotificationService.sendNewPartyRequestNotification(managerId, partyId);
public void notifyDeliveryReminder(List<Long> memberIds, Long partyId, Long managerId) {
partyNotificationService.sendDeliveryReminderNotification(memberIds, partyId, managerId);
}

@Transactional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,6 @@ List<PartyParticipant> findActivePartiesByUserIdExcludingHost(
);

int countByPartyIdAndStatusAndUser_UserIdNot(Long partyId, ParticipantStatus participantStatus, Long userId);

List<PartyParticipant> findAllByPartyAndStatus(Party party, ParticipantStatus status);
}
28 changes: 28 additions & 0 deletions src/main/java/ita/tinybite/domain/party/service/PartyService.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import ita.tinybite.domain.chat.entity.ChatRoom;
import ita.tinybite.domain.chat.enums.ChatRoomType;
import ita.tinybite.domain.chat.repository.ChatRoomRepository;
import ita.tinybite.domain.notification.service.facade.NotificationFacade;
import ita.tinybite.domain.party.dto.request.PartyCreateRequest;
import ita.tinybite.domain.party.dto.request.PartyListRequest;
import ita.tinybite.domain.party.dto.request.PartyUpdateRequest;
Expand Down Expand Up @@ -40,6 +41,7 @@ public class PartyService {
private final PartyParticipantRepository partyParticipantRepository;
private final ChatRoomRepository chatRoomRepository;
private final PartyParticipantRepository participantRepository;
private final NotificationFacade notificationFacade;

/**
* 파티 생성
Expand Down Expand Up @@ -218,6 +220,12 @@ public Long joinParty(Long partyId, Long userId) {

PartyParticipant saved = partyParticipantRepository.save(participant);

notificationFacade.notifyNewPartyRequest(
party.getHost().getUserId(), // 파티장 ID
userId, // 신청자 ID
partyId
);

return saved.getId();
}

Expand Down Expand Up @@ -428,6 +436,12 @@ public void approveParticipant(Long partyId, Long participantId, Long hostId) {
// 단체 채팅방에 참여자 추가
groupChatRoom.addMember(participant.getUser());

// 승인 알림
notificationFacade.notifyApproval(
participant.getUser().getUserId(),
partyId
);

// 목표 인원 달성 확인
checkAndCloseIfFull(party);
}
Expand Down Expand Up @@ -455,6 +469,10 @@ public void rejectParticipant(Long partyId, Long participantId, Long hostId) {
participant.getOneToOneChatRoom().deactivate();
}

notificationFacade.notifyRejection(
participant.getUser().getUserId(),
partyId
);
}

/**
Expand Down Expand Up @@ -546,6 +564,15 @@ public void settleParty(Long partyId, Long hostId) {

// 파티 마감
party.close();

// 알림 대상
List<Long> memberIds = partyParticipantRepository.findAllByPartyAndStatus(party, ParticipantStatus.APPROVED)
.stream()
.map(p -> p.getUser().getUserId())
.toList();

// 파티 종료 알림
notificationFacade.notifyPartyComplete(memberIds, party.getId());
}

// ========== Private Methods ==========
Expand Down Expand Up @@ -614,6 +641,7 @@ private void validateGroupChatRoomAccess(Party party, Long userId) {
}
}

// ??
private void checkAndCloseIfFull(Party party) {
if (party.getCurrentParticipants() >= party.getMaxParticipants()) {
party.close();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package ita.tinybite.global.exception.errorcode;

import org.springframework.http.HttpStatus;

import lombok.Getter;

@Getter
public enum PartyErrorCode implements ErrorCode {
PARTY_NOT_FOUND(HttpStatus.NOT_FOUND, "PARTY_NOT_FOUND", "파티를 찾을 수 없습니다.");

private final HttpStatus httpStatus;
private final String code;
private final String message;

PartyErrorCode(HttpStatus httpStatus, String code, String message) {
this.httpStatus = httpStatus;
this.code = code;
this.message = message;
}
}