Skip to content

Commit 2a15e1b

Browse files
authored
Merge pull request #414 from Clokey-dev/develop
[DEPLOY] 알림 로직 최적화, 예외처리 추가 및 알림 기본 이미지 URL 사용 추가 배포
2 parents 1d41347 + 714c779 commit 2a15e1b

6 files changed

Lines changed: 77 additions & 58 deletions

File tree

.github/workflows/dev-cd.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ jobs:
107107
export CLOTH_INFERENCE_PATH=${{ secrets.CLOTH_INFERENCE_PATH }}
108108
export STYLE_INFERENCE_PATH=${{ secrets.STYLE_INFERENCE_PATH }}
109109
export CLOTH_DETECT_PATH=${{ secrets.CLOTH_DETECT_PATH }}
110+
export DEFAULT_PROFILE_IMAGE_URL=${{ secrets.DEFAULT_PROFILE_IMAGE_URL }}
111+
export TODAY_TEMPERATURE_IMAGE_URL=${{ secrets.TODAY_TEMPERATURE_IMAGE_URL }}
110112
111113
sudo mkdir -p /home/ubuntu/secrets
112114
echo "${{ secrets.FIREBASE_SA_JSON_B64 }}" | base64 -d | sudo tee /home/ubuntu/secrets/firebase-sa.json > /dev/null

.github/workflows/prod-cd.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ jobs:
117117
export CLOTH_INFERENCE_PATH=${{ secrets.CLOTH_INFERENCE_PATH }}
118118
export STYLE_INFERENCE_PATH=${{ secrets.STYLE_INFERENCE_PATH }}
119119
export CLOTH_DETECT_PATH=${{ secrets.CLOTH_DETECT_PATH }}
120+
export DEFAULT_PROFILE_IMAGE_URL=${{ secrets.DEFAULT_PROFILE_IMAGE_URL }}
121+
export TODAY_TEMPERATURE_IMAGE_URL=${{ secrets.TODAY_TEMPERATURE_IMAGE_URL }}
120122
121123
sudo mkdir -p /home/ubuntu/secrets
122124
echo "${{ secrets.FIREBASE_SA_JSON_B64 }}" | base64 -d | sudo tee /home/ubuntu/secrets/firebase-sa.json > /dev/null

clokey-api/dev-compose.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ services:
3535

3636
# Firebase
3737
FIREBASE_CREDENTIALS_PATH: /run/secrets/firebase-sa.json
38+
DEFAULT_PROFILE_IMAGE_URL: ${DEFAULT_PROFILE_IMAGE_URL}
39+
TODAY_TEMPERATURE_IMAGE_URL: ${TODAY_TEMPERATURE_IMAGE_URL}
3840

3941
# JWT
4042
JWT_ACCESS_TOKEN_SECRET: ${JWT_ACCESS_TOKEN_SECRET}

clokey-api/prod-compose.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ services:
3535

3636
# Firebase
3737
FIREBASE_CREDENTIALS_PATH: /run/secrets/firebase-sa.json
38+
DEFAULT_PROFILE_IMAGE_URL: ${DEFAULT_PROFILE_IMAGE_URL}
39+
TODAY_TEMPERATURE_IMAGE_URL: ${TODAY_TEMPERATURE_IMAGE_URL}
3840

3941
# JWT
4042
JWT_ACCESS_TOKEN_SECRET: ${JWT_ACCESS_TOKEN_SECRET}

clokey-api/src/main/java/org/clokey/domain/notification/service/CodiveNotificationServiceImpl.java

Lines changed: 65 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,8 @@
66
import com.google.firebase.messaging.Notification;
77
import lombok.RequiredArgsConstructor;
88
import lombok.extern.slf4j.Slf4j;
9-
import org.clokey.comment.entitiy.Comment;
109
import org.clokey.domain.comment.event.NewCommentEvent;
1110
import org.clokey.domain.comment.event.NewReplyEvent;
12-
import org.clokey.domain.comment.exception.CommentErrorCode;
13-
import org.clokey.domain.comment.repository.CommentRepository;
14-
import org.clokey.domain.history.exception.HistoryErrorCode;
15-
import org.clokey.domain.history.repository.HistoryRepository;
1611
import org.clokey.domain.like.event.NewLikeEvent;
1712
import org.clokey.domain.member.exception.MemberErrorCode;
1813
import org.clokey.domain.member.repository.MemberRepository;
@@ -22,18 +17,18 @@
2217
import org.clokey.domain.notification.exception.NotificationErrorCode;
2318
import org.clokey.domain.notification.repository.CodiveNotificationRepository;
2419
import org.clokey.domain.term.enums.TermInfo;
25-
import org.clokey.domain.term.exception.TermErrorCode;
2620
import org.clokey.domain.term.repository.MemberTermRepository;
2721
import org.clokey.exception.BaseCustomException;
2822
import org.clokey.global.util.MemberUtil;
29-
import org.clokey.history.entity.History;
3023
import org.clokey.member.entity.Member;
3124
import org.clokey.member.enums.MemberStatus;
3225
import org.clokey.notification.entity.CodiveNotification;
3326
import org.clokey.notification.enums.NotificationType;
3427
import org.clokey.notification.enums.ReadStatus;
3528
import org.clokey.notification.enums.RedirectType;
3629
import org.clokey.response.SliceResponse;
30+
import org.clokey.term.entity.MemberTerm;
31+
import org.springframework.beans.factory.annotation.Value;
3732
import org.springframework.context.ApplicationEventPublisher;
3833
import org.springframework.scheduling.annotation.Async;
3934
import org.springframework.stereotype.Service;
@@ -51,8 +46,6 @@ public class CodiveNotificationServiceImpl implements CodiveNotificationService
5146
private final MemberRepository memberRepository;
5247
private final CodiveNotificationRepository codiveNotificationRepository;
5348
private final MemberTermRepository memberTermRepository;
54-
private final HistoryRepository historyRepository;
55-
private final CommentRepository commentRepository;
5649
private final FirebaseMessaging firebaseMessaging;
5750
private final ApplicationEventPublisher eventPublisher;
5851

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

6760
private static final String TODAY_TEMPERATURE_NOTIFICATION =
6861
"오늘의 기온은 %d도 입니다!\n날씨에 맞는 오늘의 옷차림이 기다리고 있어요👀";
69-
private static final String TODAY_TEMPERATURE_IMAGE_URL = "https://example.com/temperature.png";
62+
63+
@Value("${DEFAULT_PROFILE_IMAGE_URL:}")
64+
private String configuredDefaultProfileImageUrl;
65+
66+
@Value("${TODAY_TEMPERATURE_IMAGE_URL:}")
67+
private String configuredTemperatureImageUrl;
7068

7169
@Override
7270
@Transactional
@@ -77,10 +75,10 @@ public void sendNewFollowerNotification(Long followFromId, Long followToId) {
7775
if (isAbleToSendNotification(followToMember)) {
7876
String content =
7977
String.format(NEW_FOLLOWER_NOTIFICATION, followFromMember.getNickname());
80-
String profileImageUrl = followFromMember.getProfileImageUrl();
78+
String profileImageUrl =
79+
resolveNotificationImageUrl(followFromMember.getProfileImageUrl());
8180

82-
Notification notification =
83-
Notification.builder().setBody(content).setImage(profileImageUrl).build();
81+
Notification notification = createPushNotification(content, profileImageUrl);
8482

8583
Message message =
8684
Message.builder()
@@ -115,10 +113,10 @@ public void sendNewPendingFollowerNotification(Long followFromId, Long followToI
115113
String content =
116114
String.format(
117115
NEW_PENDING_FOLLOWER_NOTIFICATION, followFromMember.getNickname());
118-
String profileImageUrl = followFromMember.getProfileImageUrl();
116+
String profileImageUrl =
117+
resolveNotificationImageUrl(followFromMember.getProfileImageUrl());
119118

120-
Notification notification =
121-
Notification.builder().setBody(content).setImage(profileImageUrl).build();
119+
Notification notification = createPushNotification(content, profileImageUrl);
122120

123121
Message message =
124122
Message.builder()
@@ -155,10 +153,9 @@ public void sendNewCommentNotification(NewCommentEvent event) {
155153
NEW_COMMENT_NOTIFICATION,
156154
event.commenterNickname(),
157155
event.commentContent());
158-
String profileImageUrl = event.commenterProfileImageUrl();
156+
String profileImageUrl = resolveNotificationImageUrl(event.commenterProfileImageUrl());
159157

160-
Notification notification =
161-
Notification.builder().setBody(content).setImage(profileImageUrl).build();
158+
Notification notification = createPushNotification(content, profileImageUrl);
162159

163160
Message message =
164161
Message.builder()
@@ -191,10 +188,9 @@ public void sendNewReplyNotification(NewReplyEvent event) {
191188
String content =
192189
String.format(
193190
NEW_REPLY_NOTIFICATION, event.replierNickname(), event.replyContent());
194-
String profileImageUrl = event.replierProfileImageUrl();
191+
String profileImageUrl = resolveNotificationImageUrl(event.replierProfileImageUrl());
195192

196-
Notification notification =
197-
Notification.builder().setBody(content).setImage(profileImageUrl).build();
193+
Notification notification = createPushNotification(content, profileImageUrl);
198194
Message message =
199195
Message.builder()
200196
.setToken(receiver.getDeviceToken())
@@ -225,10 +221,9 @@ public void sendNewLikeNotification(NewLikeEvent event) {
225221

226222
if (isAbleToSendNotification(receiver)) {
227223
String content = String.format(NEW_LIKE_NOTIFICATION, event.likerNickname());
228-
String profileImageUrl = event.likerProfileImageUrl();
224+
String profileImageUrl = resolveNotificationImageUrl(event.likerProfileImageUrl());
229225

230-
Notification notification =
231-
Notification.builder().setBody(content).setImage(profileImageUrl).build();
226+
Notification notification = createPushNotification(content, profileImageUrl);
232227
Message message =
233228
Message.builder()
234229
.setToken(receiver.getDeviceToken())
@@ -257,13 +252,10 @@ public void sendNewTemperatureNotification(TemperatureNotificationRequest reques
257252
Member receiver = memberUtil.getCurrentMember();
258253
String content =
259254
String.format(TODAY_TEMPERATURE_NOTIFICATION, Math.round(request.temperature()));
255+
String temperatureImageUrl = configuredTemperatureImageUrl;
260256

261257
if (isAbleToSendNotification(receiver)) {
262-
Notification notification =
263-
Notification.builder()
264-
.setBody(content)
265-
.setImage(TODAY_TEMPERATURE_IMAGE_URL)
266-
.build();
258+
Notification notification = createPushNotification(content, temperatureImageUrl);
267259
Message message =
268260
Message.builder()
269261
.setToken(receiver.getDeviceToken())
@@ -274,7 +266,7 @@ public void sendNewTemperatureNotification(TemperatureNotificationRequest reques
274266
CodiveNotification.createCodiveNotification(
275267
receiver,
276268
content,
277-
TODAY_TEMPERATURE_IMAGE_URL,
269+
temperatureImageUrl,
278270
"",
279271
RedirectType.NONE,
280272
NotificationType.TEMPERATURE_DAILY);
@@ -327,18 +319,6 @@ private Member getMemberById(Long memberId) {
327319
.orElseThrow(() -> new BaseCustomException(MemberErrorCode.MEMBER_NOT_FOUND));
328320
}
329321

330-
private History getHistoryById(Long historyId) {
331-
return historyRepository
332-
.findById(historyId)
333-
.orElseThrow(() -> new BaseCustomException(HistoryErrorCode.HISTORY_NOT_FOUND));
334-
}
335-
336-
private Comment getCommentById(Long commentId) {
337-
return commentRepository
338-
.findById(commentId)
339-
.orElseThrow(() -> new BaseCustomException(CommentErrorCode.COMMENT_NOT_FOUND));
340-
}
341-
342322
private CodiveNotification getNotificationById(Long notificationId) {
343323
return codiveNotificationRepository
344324
.findById(notificationId)
@@ -348,22 +328,45 @@ private CodiveNotification getNotificationById(Long notificationId) {
348328
NotificationErrorCode.NOTIFICATION_NOT_FOUND));
349329
}
350330

351-
private boolean isAbleToSendNotification(Member followToMember) {
331+
private boolean isAbleToSendNotification(Member member) {
332+
if (member.getMemberStatus() != MemberStatus.ACTIVE) {
333+
return false;
334+
}
352335

353-
boolean isActive = (followToMember.getMemberStatus() == MemberStatus.ACTIVE);
336+
if (member.getDeviceToken() == null || member.getDeviceToken().isBlank()) {
337+
return false;
338+
}
354339

355-
boolean hasDeviceToken =
356-
(followToMember.getDeviceToken() != null
357-
&& !followToMember.getDeviceToken().isBlank());
340+
return memberTermRepository
341+
.findByMemberIdAndTermId(member.getId(), TermInfo.PUSH_NOTIFICATION_RECEIVE.getId())
342+
.map(MemberTerm::isAgreed)
343+
.orElse(false);
344+
}
358345

359-
boolean hasAgreed =
360-
memberTermRepository
361-
.findByMemberIdAndTermId(
362-
followToMember.getId(), TermInfo.PUSH_NOTIFICATION_RECEIVE.getId())
363-
.orElseThrow(() -> new BaseCustomException(TermErrorCode.TERM_NOT_FOUND))
364-
.isAgreed();
346+
private String resolveNotificationImageUrl(String profileImageUrl) {
347+
if (profileImageUrl != null && !profileImageUrl.isBlank()) {
348+
return profileImageUrl;
349+
}
350+
351+
return resolveDefaultImageUrl();
352+
}
353+
354+
private String resolveDefaultImageUrl() {
355+
if (configuredDefaultProfileImageUrl != null
356+
&& !configuredDefaultProfileImageUrl.isBlank()) {
357+
return configuredDefaultProfileImageUrl;
358+
}
359+
360+
return "";
361+
}
362+
363+
private Notification createPushNotification(String content, String imageUrl) {
364+
Notification.Builder notificationBuilder = Notification.builder().setBody(content);
365+
if (imageUrl != null && !imageUrl.isBlank()) {
366+
notificationBuilder.setImage(imageUrl);
367+
}
365368

366-
return isActive && hasDeviceToken && hasAgreed;
369+
return notificationBuilder.build();
367370
}
368371

369372
@Async
@@ -373,8 +376,13 @@ public void sendPushAfterCommit(PushSendEvent event) {
373376
try {
374377
firebaseMessaging.send(event.message());
375378
} catch (FirebaseMessagingException e) {
376-
log.warn("[Notification] Firebase 전송 실패", e);
377-
throw new BaseCustomException(NotificationErrorCode.NOTIFICATION_FIREBASE_ERROR);
379+
log.warn(
380+
"[Notification] Firebase 전송 실패: errorCode={}, message={}",
381+
e.getMessagingErrorCode(),
382+
e.getMessage(),
383+
e);
384+
} catch (Exception e) {
385+
log.error("[Notification] Firebase 전송 중 예기치 않은 오류 발생", e);
378386
}
379387
}
380388

clokey-domain/src/main/java/org/clokey/notification/entity/CodiveNotification.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,13 @@ public static CodiveNotification createCodiveNotification(
6969
String redirectInfo,
7070
RedirectType redirectType,
7171
NotificationType notificationType) {
72+
String resolvedNotificationImageUrl =
73+
(notificationImageUrl == null) ? "" : notificationImageUrl;
74+
7275
return CodiveNotification.builder()
7376
.member(member)
7477
.content(content)
75-
.notificationImageUrl(notificationImageUrl)
78+
.notificationImageUrl(resolvedNotificationImageUrl)
7679
.redirectInfo(redirectInfo)
7780
.redirectType(redirectType)
7881
.notificationType(notificationType)

0 commit comments

Comments
 (0)