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
2 changes: 2 additions & 0 deletions .github/workflows/dev-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ jobs:
export CLOTH_INFERENCE_PATH=${{ secrets.CLOTH_INFERENCE_PATH }}
export STYLE_INFERENCE_PATH=${{ secrets.STYLE_INFERENCE_PATH }}
export CLOTH_DETECT_PATH=${{ secrets.CLOTH_DETECT_PATH }}
export DEFAULT_PROFILE_IMAGE_URL=${{ secrets.DEFAULT_PROFILE_IMAGE_URL }}
export TODAY_TEMPERATURE_IMAGE_URL=${{ secrets.TODAY_TEMPERATURE_IMAGE_URL }}

sudo mkdir -p /home/ubuntu/secrets
echo "${{ secrets.FIREBASE_SA_JSON_B64 }}" | base64 -d | sudo tee /home/ubuntu/secrets/firebase-sa.json > /dev/null
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/prod-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ jobs:
export CLOTH_INFERENCE_PATH=${{ secrets.CLOTH_INFERENCE_PATH }}
export STYLE_INFERENCE_PATH=${{ secrets.STYLE_INFERENCE_PATH }}
export CLOTH_DETECT_PATH=${{ secrets.CLOTH_DETECT_PATH }}
export DEFAULT_PROFILE_IMAGE_URL=${{ secrets.DEFAULT_PROFILE_IMAGE_URL }}
export TODAY_TEMPERATURE_IMAGE_URL=${{ secrets.TODAY_TEMPERATURE_IMAGE_URL }}

sudo mkdir -p /home/ubuntu/secrets
echo "${{ secrets.FIREBASE_SA_JSON_B64 }}" | base64 -d | sudo tee /home/ubuntu/secrets/firebase-sa.json > /dev/null
Expand Down
2 changes: 2 additions & 0 deletions clokey-api/dev-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ services:

# Firebase
FIREBASE_CREDENTIALS_PATH: /run/secrets/firebase-sa.json
DEFAULT_PROFILE_IMAGE_URL: ${DEFAULT_PROFILE_IMAGE_URL}
TODAY_TEMPERATURE_IMAGE_URL: ${TODAY_TEMPERATURE_IMAGE_URL}

# JWT
JWT_ACCESS_TOKEN_SECRET: ${JWT_ACCESS_TOKEN_SECRET}
Expand Down
2 changes: 2 additions & 0 deletions clokey-api/prod-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ services:

# Firebase
FIREBASE_CREDENTIALS_PATH: /run/secrets/firebase-sa.json
DEFAULT_PROFILE_IMAGE_URL: ${DEFAULT_PROFILE_IMAGE_URL}
TODAY_TEMPERATURE_IMAGE_URL: ${TODAY_TEMPERATURE_IMAGE_URL}

# JWT
JWT_ACCESS_TOKEN_SECRET: ${JWT_ACCESS_TOKEN_SECRET}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,8 @@
import com.google.firebase.messaging.Notification;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.clokey.comment.entitiy.Comment;
import org.clokey.domain.comment.event.NewCommentEvent;
import org.clokey.domain.comment.event.NewReplyEvent;
import org.clokey.domain.comment.exception.CommentErrorCode;
import org.clokey.domain.comment.repository.CommentRepository;
import org.clokey.domain.history.exception.HistoryErrorCode;
import org.clokey.domain.history.repository.HistoryRepository;
import org.clokey.domain.like.event.NewLikeEvent;
import org.clokey.domain.member.exception.MemberErrorCode;
import org.clokey.domain.member.repository.MemberRepository;
Expand All @@ -22,18 +17,18 @@
import org.clokey.domain.notification.exception.NotificationErrorCode;
import org.clokey.domain.notification.repository.CodiveNotificationRepository;
import org.clokey.domain.term.enums.TermInfo;
import org.clokey.domain.term.exception.TermErrorCode;
import org.clokey.domain.term.repository.MemberTermRepository;
import org.clokey.exception.BaseCustomException;
import org.clokey.global.util.MemberUtil;
import org.clokey.history.entity.History;
import org.clokey.member.entity.Member;
import org.clokey.member.enums.MemberStatus;
import org.clokey.notification.entity.CodiveNotification;
import org.clokey.notification.enums.NotificationType;
import org.clokey.notification.enums.ReadStatus;
import org.clokey.notification.enums.RedirectType;
import org.clokey.response.SliceResponse;
import org.clokey.term.entity.MemberTerm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
Expand All @@ -51,8 +46,6 @@ public class CodiveNotificationServiceImpl implements CodiveNotificationService
private final MemberRepository memberRepository;
private final CodiveNotificationRepository codiveNotificationRepository;
private final MemberTermRepository memberTermRepository;
private final HistoryRepository historyRepository;
private final CommentRepository commentRepository;
private final FirebaseMessaging firebaseMessaging;
private final ApplicationEventPublisher eventPublisher;

Expand All @@ -66,7 +59,12 @@ public class CodiveNotificationServiceImpl implements CodiveNotificationService

private static final String TODAY_TEMPERATURE_NOTIFICATION =
"오늘의 기온은 %d도 입니다!\n날씨에 맞는 오늘의 옷차림이 기다리고 있어요👀";
private static final String TODAY_TEMPERATURE_IMAGE_URL = "https://example.com/temperature.png";

@Value("${DEFAULT_PROFILE_IMAGE_URL:}")
private String configuredDefaultProfileImageUrl;

@Value("${TODAY_TEMPERATURE_IMAGE_URL:}")
private String configuredTemperatureImageUrl;

@Override
@Transactional
Expand All @@ -77,10 +75,10 @@ public void sendNewFollowerNotification(Long followFromId, Long followToId) {
if (isAbleToSendNotification(followToMember)) {
String content =
String.format(NEW_FOLLOWER_NOTIFICATION, followFromMember.getNickname());
String profileImageUrl = followFromMember.getProfileImageUrl();
String profileImageUrl =
resolveNotificationImageUrl(followFromMember.getProfileImageUrl());

Notification notification =
Notification.builder().setBody(content).setImage(profileImageUrl).build();
Notification notification = createPushNotification(content, profileImageUrl);

Message message =
Message.builder()
Expand Down Expand Up @@ -115,10 +113,10 @@ public void sendNewPendingFollowerNotification(Long followFromId, Long followToI
String content =
String.format(
NEW_PENDING_FOLLOWER_NOTIFICATION, followFromMember.getNickname());
String profileImageUrl = followFromMember.getProfileImageUrl();
String profileImageUrl =
resolveNotificationImageUrl(followFromMember.getProfileImageUrl());

Notification notification =
Notification.builder().setBody(content).setImage(profileImageUrl).build();
Notification notification = createPushNotification(content, profileImageUrl);

Message message =
Message.builder()
Expand Down Expand Up @@ -155,10 +153,9 @@ public void sendNewCommentNotification(NewCommentEvent event) {
NEW_COMMENT_NOTIFICATION,
event.commenterNickname(),
event.commentContent());
String profileImageUrl = event.commenterProfileImageUrl();
String profileImageUrl = resolveNotificationImageUrl(event.commenterProfileImageUrl());

Notification notification =
Notification.builder().setBody(content).setImage(profileImageUrl).build();
Notification notification = createPushNotification(content, profileImageUrl);

Message message =
Message.builder()
Expand Down Expand Up @@ -191,10 +188,9 @@ public void sendNewReplyNotification(NewReplyEvent event) {
String content =
String.format(
NEW_REPLY_NOTIFICATION, event.replierNickname(), event.replyContent());
String profileImageUrl = event.replierProfileImageUrl();
String profileImageUrl = resolveNotificationImageUrl(event.replierProfileImageUrl());

Notification notification =
Notification.builder().setBody(content).setImage(profileImageUrl).build();
Notification notification = createPushNotification(content, profileImageUrl);
Message message =
Message.builder()
.setToken(receiver.getDeviceToken())
Expand Down Expand Up @@ -225,10 +221,9 @@ public void sendNewLikeNotification(NewLikeEvent event) {

if (isAbleToSendNotification(receiver)) {
String content = String.format(NEW_LIKE_NOTIFICATION, event.likerNickname());
String profileImageUrl = event.likerProfileImageUrl();
String profileImageUrl = resolveNotificationImageUrl(event.likerProfileImageUrl());

Notification notification =
Notification.builder().setBody(content).setImage(profileImageUrl).build();
Notification notification = createPushNotification(content, profileImageUrl);
Message message =
Message.builder()
.setToken(receiver.getDeviceToken())
Expand Down Expand Up @@ -257,13 +252,10 @@ public void sendNewTemperatureNotification(TemperatureNotificationRequest reques
Member receiver = memberUtil.getCurrentMember();
String content =
String.format(TODAY_TEMPERATURE_NOTIFICATION, Math.round(request.temperature()));
String temperatureImageUrl = configuredTemperatureImageUrl;

if (isAbleToSendNotification(receiver)) {
Notification notification =
Notification.builder()
.setBody(content)
.setImage(TODAY_TEMPERATURE_IMAGE_URL)
.build();
Notification notification = createPushNotification(content, temperatureImageUrl);
Message message =
Message.builder()
.setToken(receiver.getDeviceToken())
Expand All @@ -274,7 +266,7 @@ public void sendNewTemperatureNotification(TemperatureNotificationRequest reques
CodiveNotification.createCodiveNotification(
receiver,
content,
TODAY_TEMPERATURE_IMAGE_URL,
temperatureImageUrl,
"",
RedirectType.NONE,
NotificationType.TEMPERATURE_DAILY);
Expand Down Expand Up @@ -327,18 +319,6 @@ private Member getMemberById(Long memberId) {
.orElseThrow(() -> new BaseCustomException(MemberErrorCode.MEMBER_NOT_FOUND));
}

private History getHistoryById(Long historyId) {
return historyRepository
.findById(historyId)
.orElseThrow(() -> new BaseCustomException(HistoryErrorCode.HISTORY_NOT_FOUND));
}

private Comment getCommentById(Long commentId) {
return commentRepository
.findById(commentId)
.orElseThrow(() -> new BaseCustomException(CommentErrorCode.COMMENT_NOT_FOUND));
}

private CodiveNotification getNotificationById(Long notificationId) {
return codiveNotificationRepository
.findById(notificationId)
Expand All @@ -348,22 +328,45 @@ private CodiveNotification getNotificationById(Long notificationId) {
NotificationErrorCode.NOTIFICATION_NOT_FOUND));
}

private boolean isAbleToSendNotification(Member followToMember) {
private boolean isAbleToSendNotification(Member member) {
if (member.getMemberStatus() != MemberStatus.ACTIVE) {
return false;
}

boolean isActive = (followToMember.getMemberStatus() == MemberStatus.ACTIVE);
if (member.getDeviceToken() == null || member.getDeviceToken().isBlank()) {
return false;
}

boolean hasDeviceToken =
(followToMember.getDeviceToken() != null
&& !followToMember.getDeviceToken().isBlank());
return memberTermRepository
.findByMemberIdAndTermId(member.getId(), TermInfo.PUSH_NOTIFICATION_RECEIVE.getId())
.map(MemberTerm::isAgreed)
.orElse(false);
}

boolean hasAgreed =
memberTermRepository
.findByMemberIdAndTermId(
followToMember.getId(), TermInfo.PUSH_NOTIFICATION_RECEIVE.getId())
.orElseThrow(() -> new BaseCustomException(TermErrorCode.TERM_NOT_FOUND))
.isAgreed();
private String resolveNotificationImageUrl(String profileImageUrl) {
if (profileImageUrl != null && !profileImageUrl.isBlank()) {
return profileImageUrl;
}

return resolveDefaultImageUrl();
}

private String resolveDefaultImageUrl() {
if (configuredDefaultProfileImageUrl != null
&& !configuredDefaultProfileImageUrl.isBlank()) {
return configuredDefaultProfileImageUrl;
}

return "";
}

private Notification createPushNotification(String content, String imageUrl) {
Notification.Builder notificationBuilder = Notification.builder().setBody(content);
if (imageUrl != null && !imageUrl.isBlank()) {
notificationBuilder.setImage(imageUrl);
}

return isActive && hasDeviceToken && hasAgreed;
return notificationBuilder.build();
}

@Async
Expand All @@ -373,8 +376,13 @@ public void sendPushAfterCommit(PushSendEvent event) {
try {
firebaseMessaging.send(event.message());
} catch (FirebaseMessagingException e) {
log.warn("[Notification] Firebase 전송 실패", e);
throw new BaseCustomException(NotificationErrorCode.NOTIFICATION_FIREBASE_ERROR);
log.warn(
"[Notification] Firebase 전송 실패: errorCode={}, message={}",
e.getMessagingErrorCode(),
e.getMessage(),
e);
} catch (Exception e) {
log.error("[Notification] Firebase 전송 중 예기치 않은 오류 발생", e);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,13 @@ public static CodiveNotification createCodiveNotification(
String redirectInfo,
RedirectType redirectType,
NotificationType notificationType) {
String resolvedNotificationImageUrl =
(notificationImageUrl == null) ? "" : notificationImageUrl;

return CodiveNotification.builder()
.member(member)
.content(content)
.notificationImageUrl(notificationImageUrl)
.notificationImageUrl(resolvedNotificationImageUrl)
.redirectInfo(redirectInfo)
.redirectType(redirectType)
.notificationType(notificationType)
Expand Down
Loading