Skip to content

Commit

Permalink
refactor: fcm service 통합 (#270)
Browse files Browse the repository at this point in the history
  • Loading branch information
char-yb authored Sep 21, 2024
1 parent 2c8446b commit dcd6a61
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 104 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.depromeet.stonebed.domain.fcm.api;

import com.depromeet.stonebed.domain.fcm.application.FcmNotificationService;
import com.depromeet.stonebed.domain.fcm.application.FcmTokenService;
import com.depromeet.stonebed.domain.fcm.dto.request.FcmTokenRequest;
import com.depromeet.stonebed.domain.fcm.dto.response.FcmNotificationResponse;
import io.swagger.v3.oas.annotations.Operation;
Expand All @@ -25,22 +24,21 @@
@RestController
@RequestMapping("/alarm")
@RequiredArgsConstructor
public class FcmController {
private final FcmTokenService fcmTokenService;
public class FcmNotificationController {
private final FcmNotificationService fcmNotificationService;

@Operation(summary = "FCM 토큰 저장", description = "로그인 시 FCM 토큰을 저장합니다.")
@PostMapping("/token")
public ResponseEntity<Void> fcmTokenStore(
public ResponseEntity<Void> fcmTokenSave(
@RequestBody @Validated FcmTokenRequest fcmTokenRequest) {
fcmTokenService.createFcmToken(fcmTokenRequest.token());
fcmNotificationService.saveFcmToken(fcmTokenRequest.token());
return ResponseEntity.ok().build();
}

@Operation(summary = "FCM 토큰 삭제", description = "로그아웃 시 FCM 토큰을 삭제합니다.")
@DeleteMapping("/token")
public ResponseEntity<Void> fcmTokenDelete() {
fcmTokenService.invalidateTokenForCurrentMember();
fcmNotificationService.invalidateTokenForCurrentMember();
return ResponseEntity.ok().build();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.depromeet.stonebed.domain.fcm.application;

import com.depromeet.stonebed.domain.fcm.dao.FcmNotificationRepository;
import com.depromeet.stonebed.domain.fcm.dao.FcmRepository;
import com.depromeet.stonebed.domain.fcm.dao.FcmTokenRepository;
import com.depromeet.stonebed.domain.fcm.domain.FcmMessage;
import com.depromeet.stonebed.domain.fcm.domain.FcmNotification;
import com.depromeet.stonebed.domain.fcm.domain.FcmNotificationType;
Expand Down Expand Up @@ -42,7 +42,7 @@ public class FcmNotificationService {
private final FcmNotificationRepository notificationRepository;
private final MissionRecordBoostRepository missionRecordBoostRepository;
private final MissionRecordRepository missionRecordRepository;
private final FcmRepository fcmRepository;
private final FcmTokenRepository fcmTokenRepository;
private final MemberRepository memberRepository;
private final MemberUtil memberUtil;

Expand Down Expand Up @@ -199,7 +199,7 @@ private void sendBoostNotification(
FcmNotificationConstants notificationConstants,
long boostCount) {
String token =
fcmRepository
fcmTokenRepository
.findByMember(missionRecord.getMember())
.map(FcmToken::getToken)
.orElseThrow(() -> new CustomException(ErrorCode.FAILED_TO_FIND_FCM_TOKEN));
Expand Down Expand Up @@ -242,7 +242,7 @@ private List<FcmNotification> buildNotificationList(

for (String token : tokens) {
Member member =
fcmRepository
fcmTokenRepository
.findByToken(token)
.map(FcmToken::getMember)
.orElseThrow(
Expand Down Expand Up @@ -279,4 +279,52 @@ private List<List<String>> createBatches(List<String> tokens, int batchSize) {
Math.min(tokens.size(), (i + 1) * batchSize)))
.collect(Collectors.toList());
}

@Transactional(readOnly = true)
public List<String> getAllTokens() {
return fcmTokenRepository.findAllValidTokens();
}

@Transactional
public void invalidateTokenForCurrentMember() {
Member currentMember = memberUtil.getCurrentMember();
fcmTokenRepository
.findByMember(currentMember)
.ifPresentOrElse(
fcmToken -> updateToken(fcmToken, null),
() -> {
throw new CustomException(ErrorCode.FAILED_TO_FIND_FCM_TOKEN);
});
}

private void updateToken(FcmToken fcmToken, String token) {
fcmToken.updateToken(token);
fcmTokenRepository.save(fcmToken);
}

@Transactional
public void saveFcmToken(String token) {
if (token == null || token.isEmpty()) {
throw new CustomException(ErrorCode.INVALID_FCM_TOKEN);
}

Member member = memberUtil.getCurrentMember();
Optional<FcmToken> existingTokenOptional = fcmTokenRepository.findByToken(token);

existingTokenOptional.ifPresent(
existingToken -> {
if (!existingToken.getMember().equals(member)) {
fcmTokenRepository.delete(existingToken);
}
});

fcmTokenRepository
.findByMember(member)
.ifPresentOrElse(
fcmToken -> fcmToken.updateToken(token),
() -> {
FcmToken fcmToken = FcmToken.createFcmToken(member, token);
fcmTokenRepository.save(fcmToken);
});
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,12 @@
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;

public interface FcmRepository extends JpaRepository<FcmToken, Long>, FcmRepositoryCustom {
public interface FcmTokenRepository
extends JpaRepository<FcmToken, Long>, FcmTokenRepositoryCustom {
Optional<FcmToken> findByMember(Member member);

Optional<FcmToken> findByToken(String token);

List<FcmToken> findAll();

List<FcmToken> findAllByMemberStatus(MemberStatus status);

List<FcmToken> findAllByUpdatedAtBefore(LocalDateTime cutoffDate);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

import java.util.List;

public interface FcmRepositoryCustom {
public interface FcmTokenRepositoryCustom {
List<String> findAllValidTokens();
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class FcmRepositoryImpl implements FcmRepositoryCustom {
public class FcmTokenRepositoryImpl implements FcmTokenRepositoryCustom {

private final JPAQueryFactory jpaQueryFactory;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package com.depromeet.stonebed.scheduler.fcm;

import com.depromeet.stonebed.domain.fcm.application.FcmNotificationService;
import com.depromeet.stonebed.domain.fcm.application.FcmTokenService;
import com.depromeet.stonebed.domain.fcm.dao.FcmRepository;
import com.depromeet.stonebed.domain.fcm.dao.FcmTokenRepository;
import com.depromeet.stonebed.domain.fcm.domain.FcmToken;
import com.depromeet.stonebed.domain.member.domain.MemberStatus;
import com.depromeet.stonebed.domain.missionRecord.dao.MissionRecordRepository;
Expand All @@ -21,17 +20,16 @@
@Service
@RequiredArgsConstructor
public class FcmScheduler {
private final FcmTokenService fcmTokenService;
private final FcmNotificationService fcmNotificationService;
private final FcmRepository fcmRepository;
private final FcmTokenRepository fcmTokenRepository;
private final MissionRecordRepository missionRecordRepository;

// 매일 0시 0분에 실행
@Scheduled(cron = "0 0 0 * * ?")
public void removeInactiveTokens() {
LocalDateTime cutoffDate = LocalDateTime.now().minusMonths(2);
List<FcmToken> inactiveTokens = fcmRepository.findAllByUpdatedAtBefore(cutoffDate);
fcmRepository.deleteAll(inactiveTokens);
List<FcmToken> inactiveTokens = fcmTokenRepository.findAllByUpdatedAtBefore(cutoffDate);
fcmTokenRepository.deleteAll(inactiveTokens);
log.info("비활성 토큰 {}개 삭제 완료", inactiveTokens.size());
}

Expand All @@ -41,7 +39,7 @@ public void sendDailyNotification() {
FcmNotificationConstants notificationConstants = FcmNotificationConstants.MISSION_START;
String title = notificationConstants.getTitle();
String message = notificationConstants.getMessage();
List<String> tokens = fcmTokenService.getAllTokens();
List<String> tokens = fcmNotificationService.getAllTokens();

fcmNotificationService.sendAndNotifications(title, message, tokens);

Expand Down Expand Up @@ -73,7 +71,7 @@ private List<String> getIncompleteMissionTokens() {
.map(missionRecord -> missionRecord.getMember().getId())
.collect(Collectors.toList());

return fcmRepository.findAllByMemberStatus(MemberStatus.NORMAL).stream()
return fcmTokenRepository.findAllByMemberStatus(MemberStatus.NORMAL).stream()
.filter(fcmToken -> !completedMemberIds.contains(fcmToken.getMember().getId()))
.map(FcmToken::getToken)
.collect(Collectors.toList());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@

import com.depromeet.stonebed.FixtureMonkeySetUp;
import com.depromeet.stonebed.domain.fcm.dao.FcmNotificationRepository;
import com.depromeet.stonebed.domain.fcm.dao.FcmRepository;
import com.depromeet.stonebed.domain.fcm.domain.FcmNotification;
import com.depromeet.stonebed.domain.fcm.domain.FcmNotificationType;
import com.depromeet.stonebed.domain.fcm.dto.response.FcmNotificationResponse;
import com.depromeet.stonebed.domain.member.dao.MemberRepository;
import com.depromeet.stonebed.domain.member.domain.Member;
import com.depromeet.stonebed.domain.missionRecord.dao.MissionRecordBoostRepository;
import com.depromeet.stonebed.domain.missionRecord.dao.MissionRecordRepository;
import com.depromeet.stonebed.domain.missionRecord.domain.MissionRecord;
import com.depromeet.stonebed.global.error.ErrorCode;
Expand All @@ -34,8 +32,6 @@
public class FcmNotificationServiceTest extends FixtureMonkeySetUp {
@Mock private FcmNotificationRepository notificationRepository;
@Mock private MissionRecordRepository missionRecordRepository;
@Mock private MissionRecordBoostRepository missionRecordBoostRepository;
@Mock private FcmRepository fcmRepository;
@Mock private MemberRepository memberRepository;
@Mock private MemberUtil memberUtil;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import static org.mockito.Mockito.*;

import com.depromeet.stonebed.FixtureMonkeySetUp;
import com.depromeet.stonebed.domain.fcm.dao.FcmRepository;
import com.depromeet.stonebed.domain.fcm.dao.FcmTokenRepository;
import com.depromeet.stonebed.domain.fcm.domain.FcmToken;
import com.depromeet.stonebed.domain.member.domain.MemberStatus;
import com.depromeet.stonebed.domain.missionRecord.dao.MissionRecordRepository;
Expand All @@ -27,8 +27,7 @@
@ExtendWith(MockitoExtension.class)
public class FcmSchedulerTest extends FixtureMonkeySetUp {
@Mock private FcmNotificationService fcmNotificationService;
@Mock private FcmRepository fcmRepository;
@Mock private FcmTokenService fcmTokenService;
@Mock private FcmTokenRepository fcmTokenRepository;
@Mock private MissionRecordRepository missionRecordRepository;

@InjectMocks private FcmScheduler fcmScheduler;
Expand All @@ -37,27 +36,28 @@ public class FcmSchedulerTest extends FixtureMonkeySetUp {
void 비활성화된_토큰을_삭제하면_정상적으로_삭제된다() {
// given
List<FcmToken> tokens = fixtureMonkey.giveMe(FcmToken.class, 5);
when(fcmRepository.findAllByUpdatedAtBefore(any(LocalDateTime.class))).thenReturn(tokens);
when(fcmTokenRepository.findAllByUpdatedAtBefore(any(LocalDateTime.class)))
.thenReturn(tokens);

// when
fcmScheduler.removeInactiveTokens();

// then
ArgumentCaptor<LocalDateTime> captor = ArgumentCaptor.forClass(LocalDateTime.class);
verify(fcmRepository).findAllByUpdatedAtBefore(captor.capture());
verify(fcmTokenRepository).findAllByUpdatedAtBefore(captor.capture());

LocalDateTime actualCutoffDate = captor.getValue();

assertNotNull(actualCutoffDate);
assertTrue(actualCutoffDate.isBefore(LocalDateTime.now()));
verify(fcmRepository).deleteAll(tokens);
verify(fcmTokenRepository).deleteAll(tokens);
}

@Test
void 매일_정기_알림을_모든_사용자에게_전송하고_저장한다() {
// given
List<String> tokens = fixtureMonkey.giveMe(String.class, 5);
when(fcmTokenService.getAllTokens()).thenReturn(tokens);
when(fcmNotificationService.getAllTokens()).thenReturn(tokens);

// when
fcmScheduler.sendDailyNotification();
Expand Down Expand Up @@ -91,7 +91,7 @@ public class FcmSchedulerTest extends FixtureMonkeySetUp {
.collect(Collectors.toList()));

List<FcmToken> allTokens = fixtureMonkey.giveMe(FcmToken.class, 5);
when(fcmRepository.findAllByMemberStatus(MemberStatus.NORMAL)).thenReturn(allTokens);
when(fcmTokenRepository.findAllByMemberStatus(MemberStatus.NORMAL)).thenReturn(allTokens);

List<String> tokens =
allTokens.stream()
Expand Down

0 comments on commit dcd6a61

Please sign in to comment.