66import com .google .firebase .messaging .Notification ;
77import lombok .RequiredArgsConstructor ;
88import lombok .extern .slf4j .Slf4j ;
9- import org .clokey .comment .entitiy .Comment ;
109import org .clokey .domain .comment .event .NewCommentEvent ;
1110import 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 ;
1611import org .clokey .domain .like .event .NewLikeEvent ;
1712import org .clokey .domain .member .exception .MemberErrorCode ;
1813import org .clokey .domain .member .repository .MemberRepository ;
2217import org .clokey .domain .notification .exception .NotificationErrorCode ;
2318import org .clokey .domain .notification .repository .CodiveNotificationRepository ;
2419import org .clokey .domain .term .enums .TermInfo ;
25- import org .clokey .domain .term .exception .TermErrorCode ;
2620import org .clokey .domain .term .repository .MemberTermRepository ;
2721import org .clokey .exception .BaseCustomException ;
2822import org .clokey .global .util .MemberUtil ;
29- import org .clokey .history .entity .History ;
3023import org .clokey .member .entity .Member ;
3124import org .clokey .member .enums .MemberStatus ;
3225import org .clokey .notification .entity .CodiveNotification ;
3326import org .clokey .notification .enums .NotificationType ;
3427import org .clokey .notification .enums .ReadStatus ;
3528import org .clokey .notification .enums .RedirectType ;
3629import org .clokey .response .SliceResponse ;
30+ import org .clokey .term .entity .MemberTerm ;
31+ import org .springframework .beans .factory .annotation .Value ;
3732import org .springframework .context .ApplicationEventPublisher ;
3833import org .springframework .scheduling .annotation .Async ;
3934import 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
0 commit comments