Skip to content

Commit

Permalink
[Server] 명소 리마인드 푸쉬 알림 스케쥴링을 구현을 서버에 반영한다 (#181)
Browse files Browse the repository at this point in the history
* [Server] 테스트 푸시 API 수정 내용 서버 반영 (#175)

* Chore: Redis 설정 credentials 추가

* Fix: 푸시 알림 테스트 계정 연결

* [Server] 카테고리 리마인드 푸쉬 알림 스케쥴링을 구현한다 (#177)

* Chore: Redis 설정 credentials 추가

* Feat: UserCategory 푸시 알림 구현

* [Server] 명소 리마인드 푸쉬 알림 스케쥴링을 구현한다 (#180)

* Chore: Redis 설정 credentials 추가

* Refactor: 필요없는 코드 삭제

* Refactor: 로그 추가

* Feat: 명소 리마인드 알림 기능 구현

* Feat: 알림 저장 로직 구현

* Refactor: 로그 삭제

* Refactor: 필요없는 코드 삭제
  • Loading branch information
JeongHeumChoi authored Oct 3, 2024
1 parent fabd355 commit 7616d4c
Show file tree
Hide file tree
Showing 13 changed files with 221 additions and 14 deletions.
23 changes: 19 additions & 4 deletions src/main/java/Skeep/backend/category/domain/UserCategory.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,35 @@ public class UserCategory extends BaseTimeEntity {

@Builder
public UserCategory(
final Long id,
final String name,
final String description,
final User user
) {
this.id = id;
this.name = name;
this.description = description;
this.user = user;
}

public static UserCategory createUserCategory(
String name,
String description,
User user) {
return new UserCategory(name, description, user);
final String name,
final String description,
final User user
) {
return UserCategory.builder()
.name(name)
.description(description)
.user(user)
.build();
}

public static UserCategory createUserCategory(
final Long id
) {
return UserCategory.builder()
.id(id)
.build();
}

public void updateUserCategory(
Expand Down
3 changes: 0 additions & 3 deletions src/main/java/Skeep/backend/fcm/service/FcmService.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,6 @@ public Void testNotification(
);
}

// sendNotification(Boolean.FALSE, token, "테스트 >.0", "얏호~ 성공~", 6L, "category", "/category/205");

return null;
}

Expand Down Expand Up @@ -141,7 +139,6 @@ public void sendNotification(
String response = FirebaseMessaging.getInstance().send(message);
log.info("Successfully sent message: {}", response);
} catch (Exception e) {
e.printStackTrace();
log.info("fail to sent message");
if (!isScheduling)
throw BaseException.type(FcmErrorCode.FCM_FAIL);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,13 @@ public class UserLocation extends BaseTimeEntity {

@Builder
public UserLocation(
final Long id,
final String fileName,
final Location location,
final User user,
final UserCategory userCategory
) {
this.id = id;
this.fileName = fileName;
this.location = location;
this.user = user;
Expand All @@ -64,6 +66,14 @@ public static UserLocation createUserLocation(
.build();
}

public static UserLocation createUserLocation(
final Long id
) {
return UserLocation.builder()
.id(id)
.build();
}

public void updateUserLocation(
final String fileName,
final Location location,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package Skeep.backend.location.userLocation.domain;

import java.time.LocalDate;

public interface UserLocationRecommendProjection {
Long getUserLocationId();
String getLocationPlaceName();
LocalDate getWeatherDate();
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,28 @@ Page<UserLocation> findAllByUserIdAndUserCategory(
Pageable pageable
);

@Query(
value = "SELECT ul.id as userLocationId, l.place_name as locationPlaceName, w.date as weatherDate " +
"FROM users_location ul " +
"JOIN location l ON ul.location_id = l.id " +
"JOIN weather w ON w.location_id = l.id " +
"WHERE ul.user_id = :userId " +
"AND ul.created_date >= CURRENT_DATE - INTERVAL 4 DAY " +
"AND w.date = (" +
"SELECT MIN(w2.date)" +
"FROM weather w2 " +
"WHERE w2.location_id = l.id " +
"AND w2.weather_condition NOT IN ('SNOW', 'RAIN', 'RAIN_AND_SNOW') " +
"AND w2.temperature < 35 " +
"AND w2.temperature > -12 " +
"AND w2.date > CURRENT_DATE" +
")" +
"ORDER BY ul.created_date DESC " +
"LIMIT 1",
nativeQuery = true
)
Optional<UserLocationRecommendProjection> findUserLocationRecommendByUserIdAndWeatherAndCreatedDate(Long userId);

@Modifying
@Query("DELETE FROM UserLocation ul WHERE ul.user = :user")
void deleteAllByUser(@Param(value = "user") User user);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import Skeep.backend.category.domain.UserCategory;
import Skeep.backend.global.exception.BaseException;
import Skeep.backend.location.userLocation.domain.UserLocation;
import Skeep.backend.location.userLocation.domain.UserLocationRecommendProjection;
import Skeep.backend.location.userLocation.domain.UserLocationRepository;
import Skeep.backend.location.userLocation.exception.UserLocationErrorCode;
import Skeep.backend.user.domain.User;
Expand All @@ -11,6 +12,8 @@
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;

import java.util.Optional;

@Component
@RequiredArgsConstructor
public class UserLocationRetriever {
Expand Down Expand Up @@ -41,7 +44,9 @@ public UserLocation findById(Long id) {
.orElseThrow(() -> BaseException.type(UserLocationErrorCode.NOT_FOUND_USER_LOCATION));
}

public Long countByUserCategory(UserCategory userCategory) {
return userLocationRepository.countByUserCategory(userCategory);
public Optional<UserLocationRecommendProjection> findUserLocationRecommendByUserIdAndWeatherAndCreatedDate(
User user
) {
return userLocationRepository.findUserLocationRecommendByUserIdAndWeatherAndCreatedDate(user.getId());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package Skeep.backend.notification.constant;

public class NotificationConstants {
public static String USER_LOCATION_TYPE = "userLocation";
public static String CATEGORY_TYPE = "category";
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import lombok.experimental.SuperBuilder;
import org.hibernate.annotations.DynamicUpdate;

import java.time.LocalDateTime;

@Entity
@Getter
@DynamicUpdate
Expand All @@ -21,7 +23,7 @@ public class CategoryNotification extends Notification {
@JoinColumn(name = "user_category_id")
private UserCategory userCategory;

public CategoryNotification createCategoryNotification(
public static CategoryNotification createCategoryNotification(
final UserCategory userCategory,
final String title,
final String type,
Expand All @@ -34,6 +36,7 @@ public CategoryNotification createCategoryNotification(
.type(type)
.isChecked(isChecked)
.user(user)
.createdDate(LocalDateTime.now())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import lombok.experimental.SuperBuilder;
import org.hibernate.annotations.DynamicUpdate;

import java.time.LocalDateTime;

@Entity
@Getter
@DynamicUpdate
Expand All @@ -21,7 +23,7 @@ public class UserLocationNotification extends Notification {
@JoinColumn(name = "user_location_id")
private UserLocation userLocation;

public UserLocationNotification createUserLocationNotification(
public static UserLocationNotification createUserLocationNotification(
final UserLocation userLocation,
final String title,
final String type,
Expand All @@ -34,6 +36,7 @@ public UserLocationNotification createUserLocationNotification(
.type(type)
.isChecked(isChecked)
.user(user)
.createdDate(LocalDateTime.now())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package Skeep.backend.notification.service.CategoryNotification;

import Skeep.backend.notification.domain.CategoryNotification.CategoryNotification;
import Skeep.backend.notification.domain.CategoryNotification.CategoryNotificationRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class CategoryNotificationSaver {
private final CategoryNotificationRepository categoryNotificationRepository;

public void save(CategoryNotification categoryNotification) {
categoryNotificationRepository.save(categoryNotification);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package Skeep.backend.notification.service;

import Skeep.backend.notification.domain.CategoryNotification.CategoryNotification;
import Skeep.backend.notification.domain.UserLocationNotification.UserLocationNotification;
import Skeep.backend.notification.service.CategoryNotification.CategoryNotificationSaver;
import Skeep.backend.notification.service.UserLocationNotification.UserLocationNotificationSaver;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
@RequiredArgsConstructor
public class NotificationSaver {
private final UserLocationNotificationSaver userLocationNotificationSaver;
private final CategoryNotificationSaver categoryNotificationSaver;

@Transactional
public void saveNotification(Object notification) {
if (notification instanceof UserLocationNotification)
userLocationNotificationSaver.save((UserLocationNotification) notification);
else if (notification instanceof CategoryNotification)
categoryNotificationSaver.save((CategoryNotification) notification);
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
package Skeep.backend.notification.service;

import Skeep.backend.category.domain.UserCategory;
import Skeep.backend.category.domain.UserCategoryMostUserLocationProjection;
import Skeep.backend.category.service.UserCategoryRetriever;
import Skeep.backend.fcm.constant.FcmConstants;
import Skeep.backend.fcm.service.FcmService;
import Skeep.backend.location.userLocation.domain.UserLocation;
import Skeep.backend.location.userLocation.domain.UserLocationRecommendProjection;
import Skeep.backend.location.userLocation.service.UserLocationRetriever;
import Skeep.backend.notification.constant.NotificationConstants;
import Skeep.backend.notification.domain.CategoryNotification.CategoryNotification;
import Skeep.backend.notification.domain.UserLocationNotification.UserLocationNotification;
import Skeep.backend.user.domain.User;
import Skeep.backend.user.service.UserFindService;
import lombok.RequiredArgsConstructor;
Expand All @@ -12,7 +19,9 @@
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Locale;
import java.util.Optional;

@Slf4j
Expand All @@ -22,9 +31,11 @@ public class NotificationScheduleService {
private final FcmService fcmService;
private final UserFindService userFindService;
private final UserCategoryRetriever userCategoryRetriever;
private final UserLocationRetriever userLocationRetriever;
private final NotificationSaver notificationSaver;

@Async
@Scheduled(cron = "0 0 9 * * *")
@Scheduled(cron = "0 0 10 * * *")
public void sendCategoryNotification() {
List<User> userList = userFindService.findAllByFcmTokenIsNotNull();

Expand All @@ -48,7 +59,21 @@ public void sendCategoryNotification() {
String url = FcmConstants.CATEGORY_URL
+ userCategoryNameAndUserLocationCount.getUserCategoryId().toString();

log.info("user : {} fcm 호출", user.getName());
UserCategory tempUserCategory
= UserCategory.createUserCategory(
userCategoryNameAndUserLocationCount.getUserCategoryId()
);
CategoryNotification categoryNotification
= CategoryNotification.createCategoryNotification(
tempUserCategory,
title,
NotificationConstants.CATEGORY_TYPE,
Boolean.FALSE,
user
);
notificationSaver.saveNotification(categoryNotification);

log.info("user(UserCategory) : {} fcm 호출", user.getName());
fcmService.sendNotification(
Boolean.TRUE,
user.getFcmToken(),
Expand All @@ -58,7 +83,63 @@ public void sendCategoryNotification() {
"category",
url
);
log.info("user : {} fcm 끝", user.getName());
log.info("user(UserCategory) : {} fcm 끝", user.getName());
});
}

@Async
@Scheduled(cron = "0 0 11 * * *")
public void sendUserLocationNotification() {
List<User> userList = userFindService.findAllByFcmTokenIsNotNull();

log.info("userList : {}", userList);

userList.forEach(user -> {

Optional<UserLocationRecommendProjection> userLocationRecommendProjection
= userLocationRetriever.findUserLocationRecommendByUserIdAndWeatherAndCreatedDate(user);

if (userLocationRecommendProjection.isEmpty())
return;
UserLocationRecommendProjection userLocationNameAndUserLocationCount
= userLocationRecommendProjection.get();

String title = user.getName() + FcmConstants.USER_LOCATION_TITLE_1
+ userLocationNameAndUserLocationCount.getLocationPlaceName()
+ FcmConstants.USER_LOCATION_TITLE_2;

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M월 d일", Locale.KOREAN);
String formattedDate = userLocationNameAndUserLocationCount.getWeatherDate().format(formatter);
String body = formattedDate + FcmConstants.USER_LOCATION_BODY;

String url = FcmConstants.USER_LOCATION_URL
+ userLocationNameAndUserLocationCount.getUserLocationId().toString();

UserLocation tempUserLocation =
UserLocation.createUserLocation(
userLocationNameAndUserLocationCount.getUserLocationId()
);
UserLocationNotification userLocationNotification
= UserLocationNotification.createUserLocationNotification(
tempUserLocation,
title,
NotificationConstants.USER_LOCATION_TYPE,
Boolean.FALSE,
user
);
notificationSaver.saveNotification(userLocationNotification);

log.info("user(UserLocation) : {} fcm 호출", user.getName());
fcmService.sendNotification(
Boolean.TRUE,
user.getFcmToken(),
title,
body,
userLocationNameAndUserLocationCount.getUserLocationId(),
"userLocation",
url
);
log.info("user(UserLocation) : {} fcm 끝", user.getName());
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package Skeep.backend.notification.service.UserLocationNotification;

import Skeep.backend.notification.domain.UserLocationNotification.UserLocationNotification;
import Skeep.backend.notification.domain.UserLocationNotification.UserLocationNotificationRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class UserLocationNotificationSaver {
private final UserLocationNotificationRepository userLocationNotificationRepository;

public void save(UserLocationNotification userLocationNotification) {
userLocationNotificationRepository.save(userLocationNotification);
}
}

0 comments on commit 7616d4c

Please sign in to comment.