Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package cmf.commitField.domain.commit.scheduler;

import cmf.commitField.domain.commit.totalCommit.service.TotalCommitService;
import cmf.commitField.domain.noti.noti.entity.NotiDetailType;
import cmf.commitField.domain.noti.noti.entity.NotiType;
import cmf.commitField.domain.noti.noti.event.NotiEvent;
import cmf.commitField.domain.noti.noti.service.CommitSteakNotiService;
import cmf.commitField.domain.noti.noti.service.NotiService;
import cmf.commitField.domain.user.entity.User;
import cmf.commitField.domain.user.repository.UserRepository;
import lombok.RequiredArgsConstructor;
Expand All @@ -25,6 +30,8 @@ public class CommitScheduler {
private final StringRedisTemplate redisTemplate;
private final AtomicInteger counter = new AtomicInteger(0);
private final SimpMessagingTemplate messagingTemplate;
private final NotiService notiService;
private final CommitSteakNotiService commitSteakNotiService;

private final ApplicationEventPublisher eventPublisher;

Expand Down Expand Up @@ -86,6 +93,7 @@ private void processUserCommit(String username) {
updateTotalCommit = totalCommitService.getTotalCommitCount(
username
).getTotalCommitContributions();
int currentStreakCommit = totalCommitService.getTotalCommitCount(username).getCurrentStreakDays();

newCommitCount = updateTotalCommit - currentCommit; // 새로 추가된 커밋 수

Expand All @@ -101,6 +109,9 @@ private void processUserCommit(String username) {

CommitUpdateEvent event = new CommitUpdateEvent(this, username, newCommitCount);
eventPublisher.publishEvent(event); // 이벤트 발생

commitSteakNotiService.checkAndCreateSteakNoti(user, currentStreakCommit);

System.out.println("CommitCreatedEvent published for user: " + username);
} else if(newCommitCount < 0) {
// newCommitCount에 문제가 있을 경우 문제 상황 / 데이터 동기화 필요. db 갱신.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,39 @@
package cmf.commitField.domain.noti.noti.entity;

import java.text.MessageFormat;
import java.util.Arrays;

public enum NotiDetailType {
// 업적
RANK_UP, // 랭킹 상승
ACHIEVEMENT_COMPLETED, // 업적 달성
ACHIEVEMENT_COMPLETED("🎉 {0}님이 [{1}] 업적을 달성했습니다!", new String[]{"nickname", "achievementName"}),
STREAK_CONTINUED("🔥 {0}님의 연속 커밋이 {1}일째 이어지고 있습니다!", new String[]{"nickname", "days"}),
STREAK_BROKEN("😢 {0}님의 연속 커밋 기록이 끊겼습니다.", new String[]{"nickname"}),
SEASON_START("🚀 새로운 [{0}] 시즌이 시작되었습니다! 랭킹 경쟁을 준비하세요!", new String[]{"seasonName"}),
RANK_UP("📈 축하합니다! {0}님의 랭킹이 {1}(으)로 상승했습니다! 🎊", new String[]{"nickname", "tier"}),
NOTICE_CREATED("📢 공지사항이 있습니다: {0}", new String[]{"noticeTitle"});

private final String template;
private final String[] paramNames;

NotiDetailType(String template, String[] paramNames) {
this.template = template;
this.paramNames = paramNames;
}

// 연속
STREAK_CONTINUED, // 연속 커밋 이어짐
STREAK_BROKEN, // 연속 커밋 끊김
public String getTemplate() {
return template;
}

NOTICE_CREATED, // 시즌
SEASON_START // 시즌 시작
public String[] getParamNames() {
return paramNames;
}

public String formatMessage(Object... params) {
if (paramNames.length != params.length) {
throw new IllegalArgumentException("🚨 잘못된 파라미터 개수! 필요: " +
Arrays.toString(paramNames) + ", 제공됨: " + Arrays.toString(params));
}
return MessageFormat.format(template, params);
}
}


This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ public interface NotiRepository extends JpaRepository<Noti, Long> {

// 최근 10일 내 동일한 커밋 부재 알림이 있는지 확인
boolean existsByReceiverAndTypeCodeAndType2CodeAndCreatedAtAfter(User receiver, NotiType type, NotiDetailType detailType, LocalDateTime after);

boolean existsByReceiverAndType2CodeAndCreatedAtAfter(User receiver, NotiDetailType notiDetailType, LocalDateTime todayStart);
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,65 @@
package cmf.commitField.domain.noti.noti.service;

import cmf.commitField.domain.commit.totalCommit.service.TotalCommitService;
import cmf.commitField.domain.noti.noti.entity.NotiDetailType;
import cmf.commitField.domain.noti.noti.entity.NotiType;
import cmf.commitField.domain.noti.noti.repository.NotiRepository;
import cmf.commitField.domain.user.entity.User;
import cmf.commitField.domain.user.repository.UserRepository;
import cmf.commitField.domain.user.service.UserService;
import cmf.commitField.global.error.ErrorCode;
import cmf.commitField.global.exception.CustomException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;

@Service
@RequiredArgsConstructor
@Slf4j
public class CommitSteakNotiService {
private final UserRepository userRepository;
private final TotalCommitService totalCommitService;
private final NotiService notiService;
private final NotiRepository notiRepository;

// 매일 10시 실행
@Scheduled(cron = "0 0 10 * * *")
@Transactional
public void sendCommitSteakNoti() {
List<User> users = userRepository.findAll();

for (User user : users) {
int currentStreakCommit = totalCommitService.getTotalCommitCount(user.getUsername()).getCurrentStreakDays();
checkAndCreateSteakNoti(user, currentStreakCommit);
}
}

public void checkAndCreateSteakNoti(User user, int currentStreakCommit) {
boolean alreadyNotified = notiRepository.existsByReceiverAndType2CodeAndCreatedAtAfter(
user, NotiDetailType.STREAK_CONTINUED, LocalDate.now().atStartOfDay()
);

log.info("알림 상세 타입: {}", NotiDetailType.STREAK_CONTINUED.name());

if (shouldNotify(currentStreakCommit) && !alreadyNotified) {
log.info("🔍 연속 커밋 축하 알림 User: {}, Streak: {}", user.getUsername(), currentStreakCommit);
notiService.createStreakCommitNoti(user, String.valueOf(currentStreakCommit));
}
}


/**
* 특정 연속 커밋 횟수에 도달했는지 확인
*/
public boolean shouldNotify(int streak) {
return streak == 3 || (streak % 10 == 0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,11 @@
import cmf.commitField.domain.noti.noti.dto.NotiDto;
import cmf.commitField.domain.noti.noti.entity.Noti;
import cmf.commitField.domain.noti.noti.entity.NotiDetailType;
import cmf.commitField.domain.noti.noti.entity.NotiMessageTemplates;
import cmf.commitField.domain.noti.noti.entity.NotiType;
import cmf.commitField.domain.noti.noti.event.NotiEvent;
import cmf.commitField.domain.noti.noti.repository.NotiRepository;
import cmf.commitField.domain.season.entity.Rank;
import cmf.commitField.domain.season.entity.Season;
import cmf.commitField.domain.user.entity.User;
import cmf.commitField.domain.user.repository.UserRepository;
import cmf.commitField.global.error.ErrorCode;
import cmf.commitField.global.exception.CustomException;
import lombok.RequiredArgsConstructor;
Expand All @@ -19,7 +16,6 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

Expand All @@ -29,21 +25,13 @@
@Slf4j
public class NotiService {
private final NotiRepository notiRepository;
private final UserRepository userRepository;
private final ApplicationEventPublisher eventPublisher;

// 알림 메시지 생성
public static String generateMessage(NotiDetailType type, Object... params) {
String template = NotiMessageTemplates.getTemplate(type);
String message = MessageFormat.format(template, params); // params 배열을 그대로 전달
return message;
}

// 알림 생성
@Transactional
public void createNoti(User receiver, NotiType notiType, NotiDetailType notiDetailType, Long relId, String relTypeCode, Object... params) {
// 메시지 생성
String message = NotiService.generateMessage(notiDetailType, params);
String message = notiDetailType.formatMessage(params);

// 알림 엔티티 생성
Noti noti = Noti.builder()
Expand Down