Skip to content

Commit

Permalink
feat : 문제 생성 시의 알림 로직 제거 및 문제 시작 시 알림 전송 추가 (#133)
Browse files Browse the repository at this point in the history
* feat : 매일 정각에 시작하는 문제에 대해 알림 전송하는 스케줄러 추가

* feat : 문제 시작 시 알림 전송하는 scheduler 생성

- 문제 생성 시, 문제 시작 날짜가 당일일 경우 알림 전송
- 매일 자정, 문제가 시작하는 당일이면 그룹 멤버들에게 알림 전송
- 알림 메세지 enum 생성

* test : 시작되는 문제들에 대해 그룹 멤버들에게 알림 전송 테스트 작성

* test : 문제 생성 시 알림 관련 테스트 수정

* refactor : 알림 전송 실패 시, 로그 레벨 warn으로 수정
  • Loading branch information
rladmstn authored Oct 29, 2024
1 parent 7a5ec0f commit 21ae5c5
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 18 deletions.
2 changes: 2 additions & 0 deletions src/main/java/com/gamzabat/algohub/AlgohubApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@EnableScheduling
@SpringBootApplication
public class AlgohubApplication {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.gamzabat.algohub.feature.notification.enums;

public enum NotificationMessage {
PROBLEM_STARTED("[%s] 문제가 시작되었습니다! 지금 도전해보세요!");

private final String message;

NotificationMessage(String message) {
this.message = message;
}

public String format(String... args) {
return String.format(message, args);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public interface ProblemRepository extends JpaRepository<Problem, Long> {

List<Problem> findAllByStudyGroupAndStartDateAfter(StudyGroup studyGroup, LocalDate startDate);

List<Problem> findAllByStartDate(LocalDate startDate);

@Query("SELECT COUNT(p) FROM Problem p WHERE p.studyGroup.id = :groupId")
Long countProblemsByGroupId(@Param("groupId") Long groupId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
Expand All @@ -22,6 +23,7 @@
import com.gamzabat.algohub.constants.BOJResultConstants;
import com.gamzabat.algohub.exception.ProblemValidationException;
import com.gamzabat.algohub.exception.StudyGroupValidationException;
import com.gamzabat.algohub.feature.notification.enums.NotificationMessage;
import com.gamzabat.algohub.feature.notification.service.NotificationService;
import com.gamzabat.algohub.feature.problem.domain.Problem;
import com.gamzabat.algohub.feature.problem.dto.CreateProblemRequest;
Expand Down Expand Up @@ -80,13 +82,9 @@ public void createProblem(User user, CreateProblemRequest request) {
.endDate(request.endDate())
.build());

List<GroupMember> members = groupMemberRepository.findAllByStudyGroup(group);
List<String> users = members.stream().map(member -> member.getUser().getEmail()).toList();
try {
notificationService.sendList(users, "새로운 과제가 등록되었습니다.", group, null);
} catch (Exception e) {
log.info("failed to send notification", e);
}
if (request.startDate().equals(LocalDate.now()))
sendProblemStartedNotification(group, title);

log.info("success to create problem");
}

Expand Down Expand Up @@ -251,6 +249,15 @@ public List<GetProblemResponse> getQueuedProblemList(User user, Long groupId) {
return responseList;
}

@Scheduled(cron = "0 0 0 * * *")
public void dailyProblemScheduler() {
LocalDate now = LocalDate.now();
List<Problem> problems = problemRepository.findAllByStartDate(now);
for (Problem problem : problems) {
sendProblemStartedNotification(problem.getStudyGroup(), problem.getTitle());
}
}

private Problem getProblem(Long problemId) {
return problemRepository.findById(problemId)
.orElseThrow(() -> new ProblemValidationException(HttpStatus.NOT_FOUND.value(), "존재하지 않는 문제 입니다."));
Expand Down Expand Up @@ -321,4 +328,15 @@ private Integer calculateAccuracy(Integer submitMemberCount, Integer correctCoun
private Boolean isInProgress(Problem problem) {
return problem.getEndDate() != null && !LocalDate.now().isAfter(problem.getEndDate());
}

private void sendProblemStartedNotification(StudyGroup group, String title) {
List<GroupMember> members = groupMemberRepository.findAllByStudyGroup(group);
List<String> users = members.stream().map(member -> member.getUser().getEmail()).toList();
try {
String message = NotificationMessage.PROBLEM_STARTED.format(title);
notificationService.sendList(users, message, group, null);
} catch (Exception e) {
log.warn("failed to send notification", e);
}
}
}
59 changes: 48 additions & 11 deletions src/test/java/com/gamzabat/algohub/service/ProblemServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ void createProblem_Success() {
CreateProblemRequest request = CreateProblemRequest.builder()
.groupId(10L)
.link("https://www.acmicpc.net/problem/1000")
.startDate(LocalDate.now().minusDays(7))
.endDate(LocalDate.now())
.startDate(LocalDate.now().plusDays(3))
.endDate(LocalDate.now().plusDays(10))
.build();
when(groupRepository.findById(10L)).thenReturn(Optional.ofNullable(group));
String apiResult = "[{\"titleKo\":\"A+B\",\"level\":1}]";
Expand All @@ -143,9 +143,8 @@ void createProblem_Success() {
assertThat(result.getNumber()).isEqualTo(1000);
assertThat(result.getTitle()).isEqualTo("A+B");
assertThat(result.getLevel()).isEqualTo(1);
assertThat(result.getStartDate()).isEqualTo(LocalDate.now().minusDays(7));
assertThat(result.getEndDate()).isEqualTo(LocalDate.now());
verify(notificationService, times(1)).sendList(any(), any(), any(), any());
assertThat(result.getStartDate()).isEqualTo(LocalDate.now().plusDays(3));
assertThat(result.getEndDate()).isEqualTo(LocalDate.now().plusDays(10));
}

@Test
Expand All @@ -155,8 +154,8 @@ void createProblem_SuccessByADMIN() {
CreateProblemRequest request = CreateProblemRequest.builder()
.groupId(10L)
.link("https://www.acmicpc.net/problem/1000")
.startDate(LocalDate.now().minusDays(7))
.endDate(LocalDate.now())
.startDate(LocalDate.now())
.endDate(LocalDate.now().plusDays(10))
.build();
when(groupRepository.findById(10L)).thenReturn(Optional.ofNullable(group));
when(groupMemberRepository.findByUserAndStudyGroup(user3, group)).thenReturn(Optional.of(groupMember3));
Expand All @@ -173,8 +172,8 @@ void createProblem_SuccessByADMIN() {
assertThat(result.getNumber()).isEqualTo(1000);
assertThat(result.getTitle()).isEqualTo("A+B");
assertThat(result.getLevel()).isEqualTo(1);
assertThat(result.getStartDate()).isEqualTo(LocalDate.now().minusDays(7));
assertThat(result.getEndDate()).isEqualTo(LocalDate.now());
assertThat(result.getStartDate()).isEqualTo(LocalDate.now());
assertThat(result.getEndDate()).isEqualTo(LocalDate.now().plusDays(10));
verify(notificationService, times(1)).sendList(any(), any(), any(), any());
}

Expand Down Expand Up @@ -284,8 +283,8 @@ void createProblemSuccess_NotificationFailed() {
CreateProblemRequest request = CreateProblemRequest.builder()
.groupId(10L)
.link("https://www.acmicpc.net/problem/1000")
.startDate(LocalDate.now().minusDays(7))
.endDate(LocalDate.now())
.startDate(LocalDate.now())
.endDate(LocalDate.now().plusDays(10))
.build();
when(groupRepository.findById(10L)).thenReturn(Optional.ofNullable(group));
String apiResult = "[{\"titleKo\":\"A+B\",\"level\":1}]";
Expand Down Expand Up @@ -729,4 +728,42 @@ void getQueuedProblemListFailed_4() {
.hasFieldOrPropertyWithValue("error", "예정 문제를 조회할 권한이 없습니다. : 그룹의 방장과 부방장만 볼 수 있습니다.");
}

@Test
@DisplayName("문제 시작 날짜가 오늘일 시 그룹 멤버들에게 알림 전송")
void sendProblemStartedNotification() {
// given
StudyGroup group2 = StudyGroup.builder().name("group2").build();
User user11 = User.builder().email("email1").build();
GroupMember groupMember11 = GroupMember.builder().user(user11).studyGroup(group2).build();

List<GroupMember> group1Members = List.of(groupMember1, groupMember3, groupMember4);
List<GroupMember> group2Members = List.of(groupMember11);

List<Problem> problems = new ArrayList<>();
for (int i = 0; i < 5; i++) {
problems.add(Problem.builder()
.studyGroup(group)
.startDate(LocalDate.now())
.endDate(LocalDate.now().plusDays(30))
.title("started problem")
.build());
}
for (int i = 5; i < 10; i++) {
problems.add(Problem.builder()
.studyGroup(group2)
.startDate(LocalDate.now())
.endDate(LocalDate.now().plusDays(30))
.title("started problem")
.build());
}

when(problemRepository.findAllByStartDate(LocalDate.now())).thenReturn(problems);
when(groupMemberRepository.findAllByStudyGroup(group)).thenReturn(group1Members);
when(groupMemberRepository.findAllByStudyGroup(group2)).thenReturn(group2Members);
// when
problemService.dailyProblemScheduler();
// then
verify(notificationService, times(10)).sendList(anyList(), anyString(), any(StudyGroup.class), eq(null));
}

}

0 comments on commit 21ae5c5

Please sign in to comment.