11package ongi .pill .service ;
22
3- import com .google .firebase .messaging .AndroidConfig ;
4- import com .google .firebase .messaging .AndroidNotification ;
5- import com .google .firebase .messaging .ApnsConfig ;
6- import com .google .firebase .messaging .Aps ;
7- import com .google .firebase .messaging .FirebaseMessaging ;
8- import com .google .firebase .messaging .FirebaseMessagingException ;
9- import com .google .firebase .messaging .Message ;
10- import com .google .firebase .messaging .Notification ;
113import java .net .URL ;
124import java .time .LocalDate ;
13- import java .time .LocalDateTime ;
14- import java .util .Optional ;
155import java .util .UUID ;
166import lombok .RequiredArgsConstructor ;
177import ongi .exception .EntityNotFoundException ;
2717import ongi .pill .repository .PillIntakeRecordRepository ;
2818import ongi .pill .repository .PillRepository ;
2919import ongi .user .entity .User ;
30- import ongi .user .entity .UserFcmToken ;
31- import ongi .user .repository .UserFcmTokenRepository ;
3220import ongi .user .repository .UserRepository ;
3321import ongi .util .S3FileService ;
34- import org .springframework .scheduling .annotation .Scheduled ;
3522import org .springframework .stereotype .Service ;
3623import org .springframework .transaction .annotation .Transactional ;
3724
@@ -51,7 +38,6 @@ public class PillService {
5138 private final S3FileService s3FileService ;
5239
5340 private static final String DIR_NAME = "pill-photos" ;
54- private final UserFcmTokenRepository userFcmTokenRepository ;
5541
5642 @ Transactional
5743 public PillInfo createPill (User child , PillCreateRequest request ) {
@@ -69,7 +55,7 @@ public PillInfo createPill(User child, PillCreateRequest request) {
6955 throw new IllegalArgumentException ("가족에 속하지 않은 사용자입니다." );
7056 }
7157
72- if (request .fileName () != null ) {
58+ if (request .fileName () != null ) {
7359 if (!s3FileService .objectExists (DIR_NAME , request .fileName ())) {
7460 throw new IllegalArgumentException ("S3에 파일이 존재하지 않습니다." );
7561 }
@@ -94,8 +80,6 @@ public void deletePill(User user, Long pillId) {
9480 Pill pill = pillRepository .findById (pillId )
9581 .orElseThrow (() -> new EntityNotFoundException ("약 정보를 찾을 수 없습니다." ));
9682
97- pillIntakeRecordRepository .deleteByPill (pill );
98-
9983 Family family = familyRepository .findByMembersContains (user .getUuid ())
10084 .orElseThrow (() -> new EntityNotFoundException ("가족 정보를 찾을 수 없습니다." ));
10185
@@ -173,8 +157,7 @@ public List<PillInfoWithIntakeStatus> getFamilyPills(User user, UUID parentUuid,
173157
174158 return pills .stream ()
175159 .map (pill -> new PillInfoWithIntakeStatus (pill ,
176- pill .getFileName () != null ? s3FileService .createSignedGetUrl (DIR_NAME ,
177- pill .getFileName ()) : null ,
160+ pill .getFileName () != null ? s3FileService .createSignedGetUrl (DIR_NAME , pill .getFileName ()) : null ,
178161 intakeRecordsMap .getOrDefault (pill .getId (), List .of ())))
179162 .toList ();
180163 }
@@ -185,88 +168,4 @@ public PillPresignedResponseDto getPresignedPutUrl(User user) {
185168
186169 return new PillPresignedResponseDto (signedGetUrl , fileName );
187170 }
188-
189- @ Scheduled (cron = "0 * * * * *" )
190- public void checkAndSendMedicationAlarms () {
191- List <Pill > targets = findMedicationsNeedAlarm ();
192-
193- if (targets .isEmpty ()) {
194- return ;
195- }
196-
197- for (Pill pill : targets ) {
198- try {
199- sendPillAlarmNotification (pill );
200- } catch (Exception e ) {
201- System .err .println ("약 알람 발송 실패: " + pill .getName () + ", 오류: " + e .getMessage ());
202- }
203- }
204- }
205-
206- private void sendPillAlarmNotification (Pill pill ) throws FirebaseMessagingException {
207- Optional <UserFcmToken > userFcmTokenOptional = userFcmTokenRepository .findByUser (pill .getOwner ());
208- if (userFcmTokenOptional .isEmpty ()) {
209- return ;
210- }
211-
212- Message message = Message .builder ()
213- .setNotification (Notification .builder ()
214- .setTitle ("'" + pill .getName () + "' 약을 복용할 시간입니다!" )
215- .setBody ("복용 후 알림을 길게 눌러 복용 여부를 체크하세요." )
216- .build ())
217- .setAndroidConfig (AndroidConfig .builder ()
218- .setTtl (3600 * 1000 )
219- .setNotification (AndroidNotification .builder ()
220- .setSound ("default" )
221- .build ())
222- .build ())
223- .setApnsConfig (ApnsConfig .builder ()
224- .putHeader ("apns-push-type" , "alert" )
225- .putHeader ("apns-priority" , "10" )
226- .setAps (Aps .builder ()
227- .setCategory ("PILL_TAKE_REMINDER" )
228- .setBadge (1 )
229- .setSound ("default" )
230- .putCustomData ("interruption-level" , "time-sensitive" )
231- .build ())
232- .build ())
233- .setToken (userFcmTokenOptional .get ().getToken ())
234- .build ();
235-
236- FirebaseMessaging .getInstance ().send (message );
237- }
238-
239- private List <Pill > findMedicationsNeedAlarm () {
240- LocalDateTime now = LocalDateTime .now ();
241- LocalDate today = now .toLocalDate ();
242-
243- List <Pill > allPills = pillRepository .findAll ();
244- List <PillIntakeRecord > todayRecords = pillIntakeRecordRepository .findByIntakeDate (today );
245- Map <Long , List <PillIntakeRecord >> todayRecordsMap = todayRecords .stream ()
246- .collect (Collectors .groupingBy (record -> record .getPill ().getId ()));
247-
248- return allPills .stream ()
249- .filter (pill -> {
250- if (!pill .getIntakeDays ().contains (today .getDayOfWeek ())) {
251- return false ;
252- }
253-
254- List <PillIntakeRecord > pillTodayRecords = todayRecordsMap .getOrDefault (
255- pill .getId (), List .of ());
256-
257- return pill .getIntakeTimes ().stream ()
258- .anyMatch (intakeTime -> {
259- boolean isTimePassed =
260- now .toLocalTime ().isAfter (intakeTime ) || now .toLocalTime ()
261- .equals (intakeTime );
262-
263- boolean hasRecord = pillTodayRecords .stream ()
264- .anyMatch (record -> record .getIntakeTime ()
265- .equals (intakeTime ));
266-
267- return isTimePassed && !hasRecord ;
268- });
269- })
270- .toList ();
271- }
272171}
0 commit comments