Skip to content

Commit cef5a44

Browse files
authored
Merge pull request #223 from prgrms-web-devcourse-final-project/feature/EA3-181-study-alarm
[EA3-181] feature: 스터디 연장 알림 기능 추가
2 parents acbdd41 + 4bfbb71 commit cef5a44

File tree

12 files changed

+149
-18
lines changed

12 files changed

+149
-18
lines changed

src/main/java/grep/neogulcoder/domain/alram/service/AlarmService.java

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,12 @@
88
import grep.neogulcoder.domain.alram.type.DomainType;
99
import grep.neogulcoder.domain.study.Study;
1010
import grep.neogulcoder.domain.study.StudyMember;
11+
import grep.neogulcoder.domain.study.enums.StudyMemberRole;
12+
import grep.neogulcoder.domain.study.event.StudyExtendEvent;
13+
import grep.neogulcoder.domain.study.event.StudyExtensionReminderEvent;
1114
import grep.neogulcoder.domain.study.event.StudyInviteEvent;
1215
import grep.neogulcoder.domain.study.repository.StudyMemberQueryRepository;
16+
import grep.neogulcoder.domain.study.repository.StudyMemberRepository;
1317
import grep.neogulcoder.domain.study.repository.StudyRepository;
1418
import grep.neogulcoder.global.exception.business.BusinessException;
1519
import grep.neogulcoder.global.exception.business.NotFoundException;
@@ -20,8 +24,8 @@
2024
import org.springframework.stereotype.Service;
2125
import org.springframework.transaction.annotation.Transactional;
2226

23-
import static grep.neogulcoder.domain.study.exception.code.StudyErrorCode.STUDY_NOT_FOUND;
24-
import static grep.neogulcoder.domain.studyapplication.exception.code.ApplicationErrorCode.APPLICATION_PARTICIPANT_LIMIT_EXCEEDED;
27+
import static grep.neogulcoder.domain.study.exception.code.StudyErrorCode.*;
28+
import static grep.neogulcoder.domain.studyapplication.exception.code.ApplicationErrorCode.*;
2529

2630
@Service
2731
@RequiredArgsConstructor
@@ -32,6 +36,7 @@ public class AlarmService {
3236
private final MessageFinder messageFinder;
3337
private final StudyRepository studyRepository;
3438
private final StudyMemberQueryRepository studyMemberQueryRepository;
39+
private final StudyMemberRepository studyMemberRepository;
3540

3641
@Transactional
3742
public void saveAlarm(Long receiverId, AlarmType alarmType, DomainType domainType, Long domainId) {
@@ -87,6 +92,35 @@ public void rejectInvite(Long alarmId) {
8792
alarm.checkAlarm();
8893
}
8994

95+
@EventListener
96+
public void handleStudyExtendEvent(StudyExtendEvent event) {
97+
List<StudyMember> members = studyMemberRepository.findAllByStudyIdAndActivatedTrue(event.studyId());
98+
99+
for (StudyMember member : members) {
100+
if (!member.isLeader()) {
101+
saveAlarm(
102+
member.getUserId(),
103+
AlarmType.STUDY_EXTEND,
104+
DomainType.STUDY,
105+
event.studyId()
106+
);
107+
}
108+
}
109+
}
110+
111+
@EventListener
112+
public void handleStudyExtensionReminderEvent(StudyExtensionReminderEvent event) {
113+
StudyMember leader = studyMemberRepository.findByStudyIdAndRoleAndActivatedTrue(event.studyId(), StudyMemberRole.LEADER)
114+
.orElseThrow(() -> new BusinessException(STUDY_LEADER_NOT_FOUND));
115+
116+
saveAlarm(
117+
leader.getUserId(),
118+
AlarmType.STUDY_EXTENSION_REMINDER,
119+
DomainType.STUDY,
120+
event.studyId()
121+
);
122+
}
123+
90124
private Alarm findValidAlarm(Long alarmId) {
91125
return alarmRepository.findById(alarmId).orElseThrow(() -> new NotFoundException(AlarmErrorCode.ALARM_NOT_FOUND));
92126
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
package grep.neogulcoder.domain.alram.type;
22

33
public enum AlarmType {
4-
INVITE, TIME_VOTE_REQUEST
4+
INVITE, STUDY_EXTEND, STUDY_EXTENSION_REMINDER
55
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package grep.neogulcoder.domain.study.event;
2+
3+
public record StudyExtendEvent(Long studyId) {
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package grep.neogulcoder.domain.study.event;
2+
3+
public record StudyExtensionReminderEvent(Long studyId) {
4+
}

src/main/java/grep/neogulcoder/domain/study/exception/code/StudyErrorCode.java

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,21 @@ public enum StudyErrorCode implements ErrorCode {
1010
STUDY_NOT_FOUND("S001",HttpStatus.NOT_FOUND,"스터디를 찾을 수 없습니다."),
1111
STUDY_MEMBER_NOT_FOUND("S002", HttpStatus.NOT_FOUND, "스터디 멤버가 아닙니다."),
1212
EXTENDED_STUDY_NOT_FOUND("S003", HttpStatus.NOT_FOUND, "연장된 스터디를 찾을 수 없습니다."),
13+
STUDY_LEADER_NOT_FOUND("S004", HttpStatus.NOT_FOUND, "스터디장을 찾을 수 없습니다."),
1314

14-
STUDY_CREATE_LIMIT_EXCEEDED("S004", HttpStatus.BAD_REQUEST, "종료되지 않은 스터디는 최대 10개까지만 생성할 수 있습니다."),
15-
STUDY_ALREADY_STARTED("S005", HttpStatus.BAD_REQUEST, "이미 시작된 스터디의 시작일은 변경할 수 없습니다."),
16-
STUDY_DELETE_NOT_ALLOWED("S006", HttpStatus.BAD_REQUEST, "스터디 멤버가 1명일 때만 삭제할 수 있습니다."),
17-
STUDY_LOCATION_REQUIRED("S007", HttpStatus.BAD_REQUEST, "스터디 타입이 OFFLINE이나 HYBRID인 스터디는 지역 입력이 필수입니다."),
15+
STUDY_CREATE_LIMIT_EXCEEDED("S005", HttpStatus.BAD_REQUEST, "종료되지 않은 스터디는 최대 10개까지만 생성할 수 있습니다."),
16+
STUDY_ALREADY_STARTED("S006", HttpStatus.BAD_REQUEST, "이미 시작된 스터디의 시작일은 변경할 수 없습니다."),
17+
STUDY_DELETE_NOT_ALLOWED("S007", HttpStatus.BAD_REQUEST, "스터디 멤버가 1명일 때만 삭제할 수 있습니다."),
18+
STUDY_LOCATION_REQUIRED("S008", HttpStatus.BAD_REQUEST, "스터디 타입이 OFFLINE이나 HYBRID인 스터디는 지역 입력이 필수입니다."),
1819

19-
STUDY_EXTENSION_NOT_AVAILABLE("S008", HttpStatus.BAD_REQUEST, "스터디 연장은 스터디 종료일 7일 전부터 가능합니다."),
20-
END_DATE_BEFORE_ORIGIN_STUDY("S009", HttpStatus.BAD_REQUEST, "연장 스터디 종료일은 기존 스터디 종료일 이후여야 합니다."),
21-
ALREADY_EXTENDED_STUDY("S010", HttpStatus.BAD_REQUEST, "이미 연장된 스터디입니다."),
22-
ALREADY_REGISTERED_PARTICIPATION("S011", HttpStatus.BAD_REQUEST, "연장 스터디 참여는 한 번만 등록할 수 있습니다."),
20+
STUDY_EXTENSION_NOT_AVAILABLE("S009", HttpStatus.BAD_REQUEST, "스터디 연장은 스터디 종료일 7일 전부터 가능합니다."),
21+
END_DATE_BEFORE_ORIGIN_STUDY("S010", HttpStatus.BAD_REQUEST, "연장 스터디 종료일은 기존 스터디 종료일 이후여야 합니다."),
22+
ALREADY_EXTENDED_STUDY("S011", HttpStatus.BAD_REQUEST, "이미 연장된 스터디입니다."),
23+
ALREADY_REGISTERED_PARTICIPATION("S012", HttpStatus.BAD_REQUEST, "연장 스터디 참여는 한 번만 등록할 수 있습니다."),
2324

24-
NOT_STUDY_LEADER("S012", HttpStatus.FORBIDDEN, "스터디장만 접근이 가능합니다."),
25-
LEADER_CANNOT_LEAVE_STUDY("S013", HttpStatus.BAD_REQUEST, "스터디장은 스터디를 탈퇴할 수 없습니다."),
26-
LEADER_CANNOT_DELEGATE_TO_SELF("S014", HttpStatus.BAD_REQUEST, "자기 자신에게는 스터디장 위임이 불가능합니다.");
25+
NOT_STUDY_LEADER("S013", HttpStatus.FORBIDDEN, "스터디장만 접근이 가능합니다."),
26+
LEADER_CANNOT_LEAVE_STUDY("S014", HttpStatus.BAD_REQUEST, "스터디장은 스터디를 탈퇴할 수 없습니다."),
27+
LEADER_CANNOT_DELEGATE_TO_SELF("S015", HttpStatus.BAD_REQUEST, "자기 자신에게는 스터디장 위임이 불가능합니다.");
2728

2829
private final String code;
2930
private final HttpStatus status;

src/main/java/grep/neogulcoder/global/provider/InviteMessageProvider.java renamed to src/main/java/grep/neogulcoder/domain/study/provider/InviteMessageProvider.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
package grep.neogulcoder.global.provider;
1+
package grep.neogulcoder.domain.study.provider;
22

33
import grep.neogulcoder.domain.alram.type.AlarmType;
44
import grep.neogulcoder.domain.alram.type.DomainType;
55
import grep.neogulcoder.domain.study.Study;
66
import grep.neogulcoder.domain.study.exception.code.StudyErrorCode;
77
import grep.neogulcoder.domain.study.repository.StudyRepository;
88
import grep.neogulcoder.global.exception.business.NotFoundException;
9+
import grep.neogulcoder.global.provider.MessageProvidable;
910
import lombok.RequiredArgsConstructor;
1011
import org.springframework.stereotype.Component;
1112

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package grep.neogulcoder.domain.study.provider;
2+
3+
import grep.neogulcoder.domain.alram.type.AlarmType;
4+
import grep.neogulcoder.domain.alram.type.DomainType;
5+
import grep.neogulcoder.domain.study.Study;
6+
import grep.neogulcoder.domain.study.repository.StudyRepository;
7+
import grep.neogulcoder.global.exception.business.NotFoundException;
8+
import grep.neogulcoder.global.provider.MessageProvidable;
9+
import lombok.RequiredArgsConstructor;
10+
import org.springframework.stereotype.Component;
11+
12+
import static grep.neogulcoder.domain.study.exception.code.StudyErrorCode.*;
13+
14+
@Component
15+
@RequiredArgsConstructor
16+
public class StudyExtendMessageProvider implements MessageProvidable {
17+
18+
private final StudyRepository studyRepository;
19+
20+
@Override
21+
public boolean isSupport(AlarmType alarmType) {
22+
return alarmType == AlarmType.STUDY_EXTEND;
23+
}
24+
25+
@Override
26+
public String provideMessage(DomainType domainType, Long domainId) {
27+
if (domainType != DomainType.STUDY) {
28+
throw new IllegalArgumentException("스터디 연장 알림은 STUDY 도메인에만 해당됩니다.");
29+
}
30+
31+
String studyName = studyRepository.findById(domainId)
32+
.map(Study::getName)
33+
.orElseThrow(() -> new NotFoundException(STUDY_NOT_FOUND));
34+
35+
return String.format("스터디 '%s'가 연장되었습니다.", studyName);
36+
}
37+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package grep.neogulcoder.domain.study.provider;
2+
3+
import grep.neogulcoder.domain.alram.type.AlarmType;
4+
import grep.neogulcoder.domain.alram.type.DomainType;
5+
import grep.neogulcoder.domain.study.Study;
6+
import grep.neogulcoder.domain.study.repository.StudyRepository;
7+
import grep.neogulcoder.global.exception.business.NotFoundException;
8+
import grep.neogulcoder.global.provider.MessageProvidable;
9+
import lombok.RequiredArgsConstructor;
10+
import org.springframework.stereotype.Component;
11+
12+
import static grep.neogulcoder.domain.study.exception.code.StudyErrorCode.*;
13+
14+
@Component
15+
@RequiredArgsConstructor
16+
public class StudyExtensionReminderMessageProvider implements MessageProvidable {
17+
18+
private final StudyRepository studyRepository;
19+
20+
@Override
21+
public boolean isSupport(AlarmType alarmType) {
22+
return alarmType == AlarmType.STUDY_EXTENSION_REMINDER;
23+
}
24+
25+
@Override
26+
public String provideMessage(DomainType domainType, Long domainId) {
27+
if (domainType != DomainType.STUDY) {
28+
throw new IllegalArgumentException("스터디 종료 7일 전 연장 가능 알림은 STUDY 도메인에만 해당됩니다.");
29+
}
30+
31+
String studyName = studyRepository.findById(domainId)
32+
.map(Study::getName)
33+
.orElseThrow(() -> new NotFoundException(STUDY_NOT_FOUND));
34+
35+
return String.format("스터디 '%s' 종료 7일 전 입니다. 스터디 연장이 가능합니다.", studyName);
36+
}
37+
}

src/main/java/grep/neogulcoder/domain/study/repository/StudyMemberRepository.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,6 @@ public interface StudyMemberRepository extends JpaRepository<StudyMember, Long>
4646
boolean existsByStudyIdAndUserId(Long studyId, Long id);
4747

4848
boolean existsByStudyIdAndUserIdAndRole(Long studyId, Long userId, StudyMemberRole role);
49+
50+
Optional<StudyMember> findByStudyIdAndRoleAndActivatedTrue(Long studyId, StudyMemberRole role);
4951
}

src/main/java/grep/neogulcoder/domain/study/scheduler/StudyScheduler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public class StudyScheduler {
1616

1717
@Scheduled(cron = "0 0 0 * * *")
1818
public void processEndingStudies() {
19-
List<Study> studiesEndingIn7Days = studySchedulerService.findStudiesEndingIn7Days();
19+
studySchedulerService.findStudiesEndingIn7Days();
2020

2121
studySchedulerService.finalizeStudies();
2222
}

0 commit comments

Comments
 (0)