Skip to content

Commit

Permalink
FCM 부스터 알림 기능 로직 수정 (#246)
Browse files Browse the repository at this point in the history
* fix: 부스터 알림 기능 로직 수정

* fix: fcm_notification에 memberId저장 수정

* fix: NotificationService test수정

* fix: 1-1000-5000 부스트 알림 개수 수정

* fix: remind알림 대상 수정

* fix: test코드 제거

* fix: 미사용 메서드 삭제
  • Loading branch information
dbscks97 authored Sep 5, 2024
1 parent 66cbfa4 commit c5d5a87
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.depromeet.stonebed.domain.fcm.domain.FcmToken;
import com.depromeet.stonebed.domain.fcm.dto.response.FcmNotificationDto;
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;
Expand All @@ -23,6 +24,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import lombok.RequiredArgsConstructor;
Expand All @@ -41,17 +43,27 @@ public class FcmNotificationService {
private final MissionRecordBoostRepository missionRecordBoostRepository;
private final MissionRecordRepository missionRecordRepository;
private final FcmRepository fcmRepository;
private final MemberRepository memberRepository;
private final MemberUtil memberUtil;

private static final DateTimeFormatter DATE_FORMATTER =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");

private static final long POPULAR_THRESHOLD = 500;
private static final long FIRST_BOOST_THRESHOLD = 1;
private static final long POPULAR_THRESHOLD = 1000;
private static final long SUPER_POPULAR_THRESHOLD = 5000;

public void saveNotification(
FcmNotificationType type, String title, String message, Long targetId, Boolean isRead) {
final Member member = memberUtil.getCurrentMember();
FcmNotificationType type,
String title,
String message,
Long targetId,
Long memberId,
Boolean isRead) {
Member member =
memberRepository
.findById(memberId)
.orElseThrow(() -> new CustomException(ErrorCode.MEMBER_NOT_FOUND));

FcmNotification notification =
FcmNotification.create(type, title, message, member, targetId, isRead);
Expand Down Expand Up @@ -132,22 +144,38 @@ public void checkAndSendBoostNotification(MissionRecord missionRecord) {
missionRecordBoostRepository.sumBoostCountByMissionRecord(missionRecord.getId());

if (totalBoostCount != null) {
FcmNotificationConstants notificationConstants =
Optional<FcmNotificationConstants> notificationType =
determineNotificationType(totalBoostCount);

if (notificationConstants != null) {
sendBoostNotification(missionRecord, notificationConstants);
}
notificationType.ifPresent(
type -> {
if (!notificationAlreadySent(missionRecord, type)) {
sendBoostNotification(missionRecord, type);
}
});
}
}

private FcmNotificationConstants determineNotificationType(Long totalBoostCount) {
if (totalBoostCount == POPULAR_THRESHOLD) {
return FcmNotificationConstants.POPULAR;
} else if (totalBoostCount == SUPER_POPULAR_THRESHOLD) {
return FcmNotificationConstants.SUPER_POPULAR;
private boolean notificationAlreadySent(
MissionRecord missionRecord, FcmNotificationConstants notificationConstants) {
return notificationRepository.existsByTargetIdAndTypeAndTitle(
missionRecord.getId(),
FcmNotificationType.BOOSTER,
notificationConstants.getTitle());
}

private Optional<FcmNotificationConstants> determineNotificationType(Long totalBoostCount) {
if (totalBoostCount >= SUPER_POPULAR_THRESHOLD) {
return Optional.of(FcmNotificationConstants.SUPER_POPULAR);
}
if (totalBoostCount >= POPULAR_THRESHOLD) {
return Optional.of(FcmNotificationConstants.POPULAR);
}
return null;
if (totalBoostCount >= FIRST_BOOST_THRESHOLD) {
return Optional.of(FcmNotificationConstants.FIRST_BOOST);
}

return Optional.empty();
}

private void sendBoostNotification(
Expand All @@ -170,6 +198,7 @@ private void sendBoostNotification(
notificationConstants.getTitle(),
notificationConstants.getMessage(),
missionRecord.getId(),
missionRecord.getMember().getId(),
false);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
Expand Down Expand Up @@ -63,20 +63,17 @@ private List<String> getIncompleteMissionTokens() {
LocalDateTime startOfDay = LocalDate.now().atStartOfDay();
LocalDateTime endOfDay = startOfDay.plusDays(1);

return missionRecordRepository
.findAllByCreatedAtBetweenAndStatusNot(
startOfDay, endOfDay, MissionRecordStatus.COMPLETED)
.stream()
.map(
missionRecord -> {
FcmToken fcmToken =
fcmRepository
.findByMemberAndMemberStatus(
missionRecord.getMember(), MemberStatus.NORMAL)
.orElse(null);
return fcmToken != null ? fcmToken.getToken() : null;
})
.filter(Objects::nonNull)
.toList();
List<Long> completedMemberIds =
missionRecordRepository
.findAllByCreatedAtBetweenAndStatus(
startOfDay, endOfDay, MissionRecordStatus.COMPLETED)
.stream()
.map(missionRecord -> missionRecord.getMember().getId())
.collect(Collectors.toList());

return fcmRepository.findAllByMemberStatus(MemberStatus.NORMAL).stream()
.filter(fcmToken -> !completedMemberIds.contains(fcmToken.getMember().getId()))
.map(FcmToken::getToken)
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.depromeet.stonebed.domain.fcm.dao;

import com.depromeet.stonebed.domain.fcm.domain.FcmNotification;
import com.depromeet.stonebed.domain.fcm.domain.FcmNotificationType;
import com.depromeet.stonebed.domain.member.domain.Member;
import java.time.LocalDateTime;
import java.util.List;
Expand All @@ -21,6 +22,8 @@ List<FcmNotification> findByMemberIdAndCreatedAtLessThanEqual(

boolean existsByCreatedAtLessThan(LocalDateTime createdAt);

boolean existsByTargetIdAndTypeAndTitle(Long targetId, FcmNotificationType type, String title);

// Delete
@Modifying
@Query("DELETE FROM FcmNotification fn WHERE fn.member.id = :memberId")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public interface FcmRepository extends JpaRepository<FcmToken, Long>, FcmReposit

List<FcmToken> findAll();

List<FcmToken> findAllByUpdatedAtBefore(LocalDateTime cutoffDate);
List<FcmToken> findAllByMemberStatus(MemberStatus status);

Optional<FcmToken> findByMemberAndMemberStatus(Member member, MemberStatus status);
List<FcmToken> findAllByUpdatedAtBefore(LocalDateTime cutoffDate);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Optional<MissionRecord> findByMemberAndMissionHistory(

Long countByMemberIdAndStatus(Long memberId, MissionRecordStatus status);

List<MissionRecord> findAllByCreatedAtBetweenAndStatusNot(
List<MissionRecord> findAllByCreatedAtBetweenAndStatus(
LocalDateTime startTime, LocalDateTime endTime, MissionRecordStatus status);

List<MissionRecord> findByIdIn(List<Long> ids);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
@Getter
@AllArgsConstructor
public enum FcmNotificationConstants {
POPULAR("인기쟁이", "게시물 부스터를 500개를 달성했어요!"),
// FIRST_BOOST는 임시 -> 디자인측에서 제공시 수정예정
FIRST_BOOST("첫 부스터 달성!", "축하합니다! 게시물에 첫 번째 부스터가 추가되었어요!"),
POPULAR("인기쟁이", "게시물 부스터를 1000개를 달성했어요!"),
SUPER_POPULAR("최고 인기 달성", "인기폭발! 부스터를 5000개 달성했어요!"),
MISSION_START("미션 시작!", "새로운 미션을 지금 시작해보세요!"),
MISSION_REMINDER("미션 리마인드", "미션 종료까지 5시간 남았어요!");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
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;
Expand All @@ -35,6 +36,7 @@ public class FcmNotificationServiceTest extends FixtureMonkeySetUp {
@Mock private MissionRecordRepository missionRecordRepository;
@Mock private MissionRecordBoostRepository missionRecordBoostRepository;
@Mock private FcmRepository fcmRepository;
@Mock private MemberRepository memberRepository;
@Mock private MemberUtil memberUtil;

@InjectMocks private FcmNotificationService fcmNotificationService;
Expand All @@ -43,11 +45,11 @@ public class FcmNotificationServiceTest extends FixtureMonkeySetUp {
void 정규알림_응답값_저장() {
// given
Member member = fixtureMonkey.giveMeOne(Member.class);
when(memberUtil.getCurrentMember()).thenReturn(member);
when(memberRepository.findById(member.getId())).thenReturn(Optional.of(member));

// when
fcmNotificationService.saveNotification(
FcmNotificationType.MISSION, "title", "message", 1L, false);
FcmNotificationType.MISSION, "title", "message", 1L, member.getId(), false);

// then
verify(notificationRepository, times(1)).save(any(FcmNotification.class));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
Expand Down Expand Up @@ -70,29 +69,33 @@ public class FcmScheduledServiceTest extends FixtureMonkeySetUp {
@Test
void 미완료_미션_사용자에게_리마인더를_전송하고_저장한다() {
// given
List<MissionRecord> missionRecords = fixtureMonkey.giveMe(MissionRecord.class, 2);
LocalDateTime startOfDay = LocalDate.now().atStartOfDay();
LocalDateTime endOfDay = startOfDay.plusDays(1);
when(missionRecordRepository.findAllByCreatedAtBetweenAndStatusNot(
startOfDay, endOfDay, MissionRecordStatus.COMPLETED))
.thenReturn(missionRecords);

missionRecords.forEach(record -> record.getMember().updateStatus(MemberStatus.NORMAL));
List<Long> completedMemberIds = List.of(1L, 2L);
when(missionRecordRepository.findAllByCreatedAtBetweenAndStatus(
startOfDay, endOfDay, MissionRecordStatus.COMPLETED))
.thenReturn(
completedMemberIds.stream()
.map(
id -> {
MissionRecord record =
fixtureMonkey
.giveMeBuilder(MissionRecord.class)
.set("member.id", id)
.sample();
record.getMember().updateStatus(MemberStatus.NORMAL);
return record;
})
.collect(Collectors.toList()));

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

List<String> tokens =
missionRecords.stream()
.map(
missionRecord -> {
FcmToken token =
fixtureMonkey
.giveMeBuilder(FcmToken.class)
.set("member", missionRecord.getMember())
.sample();
when(fcmRepository.findByMemberAndMemberStatus(
missionRecord.getMember(), MemberStatus.NORMAL))
.thenReturn(Optional.of(token));
return token.getToken();
})
allTokens.stream()
.filter(token -> !completedMemberIds.contains(token.getMember().getId()))
.map(FcmToken::getToken)
.collect(Collectors.toList());

// when
Expand Down

0 comments on commit c5d5a87

Please sign in to comment.