Skip to content

Commit 4bfbb71

Browse files
authored
Merge branch 'develop' into feature/EA3-181-study-alarm
2 parents e4bea8f + acbdd41 commit 4bfbb71

File tree

8 files changed

+146
-31
lines changed

8 files changed

+146
-31
lines changed

src/main/java/grep/neogulcoder/domain/alram/exception/code/AlarmErrorCode.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ public enum AlarmErrorCode implements ErrorCode {
99

1010
ALARM_NOT_FOUND("A001",HttpStatus.NOT_FOUND,"알람을 찾을 수 없습니다.");
1111

12-
1312
private final String code;
1413
private final HttpStatus status;
1514
private final String message;
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package grep.neogulcoder.domain.alram.type;
22

33
public enum AlarmType {
4-
54
INVITE, STUDY_EXTEND, STUDY_EXTENSION_REMINDER
65
}
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 DomainType {
4-
STUDY
4+
STUDY, TIME_VOTE
55
}

src/main/java/grep/neogulcoder/domain/timevote/dto/response/TimeVotePeriodResponse.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import grep.neogulcoder.domain.timevote.entity.TimeVotePeriod;
44
import io.swagger.v3.oas.annotations.media.Schema;
55
import java.time.LocalDateTime;
6+
import java.util.List;
67
import lombok.Builder;
78
import lombok.Getter;
89

@@ -19,18 +20,24 @@ public class TimeVotePeriodResponse {
1920
@Schema(description = "종료일", example = "2025-07-30T23:59:59")
2021
private LocalDateTime endDate;
2122

23+
@Schema(description = "알림이 전송된 팀원 멤버 ID 목록", example = "[11, 12, 13]")
24+
private List<Long> notifiedMemberIds;
25+
2226
@Builder
23-
private TimeVotePeriodResponse(Long studyId, LocalDateTime startDate, LocalDateTime endDate) {
27+
private TimeVotePeriodResponse(Long studyId, LocalDateTime startDate, LocalDateTime endDate, List<Long> notifiedMemberIds) {
2428
this.studyId = studyId;
2529
this.startDate = startDate;
2630
this.endDate = endDate;
31+
this.notifiedMemberIds = notifiedMemberIds;
2732
}
2833

29-
public static TimeVotePeriodResponse from(TimeVotePeriod timeVotePeriod) {
34+
public static TimeVotePeriodResponse from(TimeVotePeriod timeVotePeriod, List<Long> notifiedMemberIds) {
3035
return TimeVotePeriodResponse.builder()
3136
.studyId(timeVotePeriod.getStudyId())
3237
.startDate(timeVotePeriod.getStartDate())
3338
.endDate(timeVotePeriod.getEndDate())
39+
.notifiedMemberIds(notifiedMemberIds)
3440
.build();
3541
}
3642
}
43+
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package grep.neogulcoder.domain.timevote.provider;
2+
3+
import static grep.neogulcoder.domain.timevote.exception.code.TimeVoteErrorCode.STUDY_NOT_FOUND;
4+
5+
import grep.neogulcoder.domain.alram.type.AlarmType;
6+
import grep.neogulcoder.domain.alram.type.DomainType;
7+
import grep.neogulcoder.domain.study.Study;
8+
import grep.neogulcoder.domain.study.repository.StudyRepository;
9+
import grep.neogulcoder.global.exception.business.NotFoundException;
10+
import grep.neogulcoder.global.provider.MessageProvidable;
11+
import lombok.RequiredArgsConstructor;
12+
import org.springframework.stereotype.Component;
13+
14+
@Component
15+
@RequiredArgsConstructor
16+
public class TimeVoteMessageProvider implements MessageProvidable {
17+
18+
private final StudyRepository studyRepository;
19+
20+
@Override
21+
public boolean isSupport(AlarmType alarmType) {
22+
return alarmType == AlarmType.TIME_VOTE_REQUEST;
23+
}
24+
25+
@Override
26+
public String provideMessage(DomainType domainType, Long domainId) {
27+
if (domainType != DomainType.TIME_VOTE) {
28+
throw new IllegalArgumentException("시간 투표 요청은 TIME_VOTE 도메인에만 해당됩니다.");
29+
}
30+
31+
Study study = studyRepository.findById(domainId)
32+
.orElseThrow(() -> new NotFoundException(STUDY_NOT_FOUND));
33+
34+
return String.format("[%s] 스터디장이 모임 일정 조율을 위한 투표를 요청했습니다.", study.getName());
35+
}
36+
}

src/main/java/grep/neogulcoder/domain/timevote/service/TimeVotePeriodService.java

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
package grep.neogulcoder.domain.timevote.service;
22

3-
import static grep.neogulcoder.domain.timevote.exception.code.TimeVoteErrorCode.*;
4-
3+
import static grep.neogulcoder.domain.timevote.exception.code.TimeVoteErrorCode.FORBIDDEN_TIME_VOTE_CREATE;
4+
import static grep.neogulcoder.domain.timevote.exception.code.TimeVoteErrorCode.INVALID_TIME_VOTE_PERIOD;
5+
import static grep.neogulcoder.domain.timevote.exception.code.TimeVoteErrorCode.STUDY_MEMBER_NOT_FOUND;
6+
import static grep.neogulcoder.domain.timevote.exception.code.TimeVoteErrorCode.STUDY_NOT_FOUND;
7+
import static grep.neogulcoder.domain.timevote.exception.code.TimeVoteErrorCode.TIME_VOTE_INVALID_DATE_RANGE;
8+
import static grep.neogulcoder.domain.timevote.exception.code.TimeVoteErrorCode.TIME_VOTE_PERIOD_START_DATE_IN_PAST;
9+
10+
import grep.neogulcoder.domain.alram.service.AlarmService;
11+
import grep.neogulcoder.domain.alram.type.AlarmType;
12+
import grep.neogulcoder.domain.alram.type.DomainType;
513
import grep.neogulcoder.domain.study.Study;
614
import grep.neogulcoder.domain.study.StudyMember;
715
import grep.neogulcoder.domain.study.enums.StudyMemberRole;
@@ -14,9 +22,12 @@
1422
import grep.neogulcoder.domain.timevote.repository.TimeVoteRepository;
1523
import grep.neogulcoder.domain.timevote.repository.TimeVoteStatRepository;
1624
import grep.neogulcoder.global.exception.business.BusinessException;
25+
import grep.neogulcoder.global.provider.finder.MessageFinder;
1726
import java.time.LocalDateTime;
1827
import java.time.LocalTime;
1928
import java.time.temporal.ChronoUnit;
29+
import java.util.ArrayList;
30+
import java.util.List;
2031
import lombok.RequiredArgsConstructor;
2132
import org.springframework.stereotype.Service;
2233
import org.springframework.transaction.annotation.Transactional;
@@ -31,6 +42,8 @@ public class TimeVotePeriodService {
3142
private final TimeVoteStatRepository timeVoteStatRepository;
3243
private final StudyRepository studyRepository;
3344
private final StudyMemberRepository studyMemberRepository;
45+
private final AlarmService alarmService;
46+
private final MessageFinder messageFinder;
3447

3548
public TimeVotePeriodResponse createTimeVotePeriodAndReturn(TimeVotePeriodCreateRequest request, Long studyId, Long userId) {
3649
StudyMember studyMember = getValidStudyMember(studyId, userId);
@@ -48,7 +61,20 @@ public TimeVotePeriodResponse createTimeVotePeriodAndReturn(TimeVotePeriodCreate
4861

4962
TimeVotePeriod savedPeriod = timeVotePeriodRepository.save(request.toEntity(studyId, adjustedEndDate));
5063

51-
return TimeVotePeriodResponse.from(savedPeriod);
64+
getValidStudy(studyId);
65+
messageFinder.findMessage(AlarmType.TIME_VOTE_REQUEST, DomainType.TIME_VOTE, studyId);
66+
67+
List<StudyMember> members = studyMemberRepository.findAllByStudyIdAndActivatedTrue(studyId);
68+
List<Long> notifiedUserIds = new ArrayList<>();
69+
for (StudyMember member : members) {
70+
if (!member.getUserId().equals(userId)) {
71+
alarmService.saveAlarm(member.getUserId(), AlarmType.TIME_VOTE_REQUEST,
72+
DomainType.TIME_VOTE, studyId);
73+
notifiedUserIds.add(member.getId());
74+
}
75+
}
76+
77+
return TimeVotePeriodResponse.from(savedPeriod, notifiedUserIds);
5278
}
5379

5480
public void deleteAllTimeVoteDate(Long studyId) {

src/main/java/grep/neogulcoder/domain/users/service/UserService.java

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@
2323
import grep.neogulcoder.global.utils.upload.FileUsageType;
2424
import grep.neogulcoder.global.utils.upload.uploader.GcpFileUploader;
2525
import grep.neogulcoder.global.utils.upload.uploader.LocalFileUploader;
26-
import jakarta.transaction.Transactional;
2726
import java.io.IOException;
2827
import java.util.List;
2928
import lombok.RequiredArgsConstructor;
3029
import org.springframework.beans.factory.annotation.Autowired;
3130
import org.springframework.core.env.Environment;
3231
import org.springframework.security.crypto.password.PasswordEncoder;
3332
import org.springframework.stereotype.Service;
33+
import org.springframework.transaction.annotation.Transactional;
3434
import org.springframework.web.multipart.MultipartFile;
3535

3636
@Transactional
@@ -58,14 +58,14 @@ public class UserService {
5858
private Environment environment;
5959

6060

61+
@Transactional(readOnly = true)
6162
public User get(Long id) {
62-
User user = findUser(id);
63-
return user;
63+
return findUserById(id);
6464
}
6565

66+
@Transactional(readOnly = true)
6667
public User getByEmail(String email) {
67-
User user = findUser(email);
68-
return user;
68+
return findUserByEmail(email);
6969
}
7070

7171
public void signUp(SignUpRequest request) {
@@ -84,7 +84,7 @@ public void signUp(SignUpRequest request) {
8484
userRepository.save(
8585
User.UserInit(request.getEmail(), encodedPassword, request.getNickname()));
8686

87-
User user = findUser(request.getEmail());
87+
User user = findUserByEmail(request.getEmail());
8888
initializeUserData(user.getId());
8989

9090
verificationService.clearVerifiedStatus(request.getEmail());
@@ -93,10 +93,9 @@ public void signUp(SignUpRequest request) {
9393
public void updateProfile(Long userId, String nickname, MultipartFile profileImage)
9494
throws IOException {
9595

96-
User user = findUser(userId);
97-
if(isDuplicateNickname(nickname)){
98-
throw new NicknameDuplicatedException(UserErrorCode.IS_DUPLICATED_NICKNAME);
99-
}
96+
User user = findUserById(userId);
97+
98+
String validatedNickname = validateUpdateNickname(user, nickname);
10099

101100
String uploadedImageUrl;
102101
if (isProfileImgExists(profileImage)) {
@@ -108,12 +107,12 @@ public void updateProfile(Long userId, String nickname, MultipartFile profileIma
108107
uploadedImageUrl = user.getProfileImageUrl();
109108
}
110109

111-
user.updateProfile(nickname, uploadedImageUrl);
110+
user.updateProfile(validatedNickname, uploadedImageUrl);
112111
}
113112

114113
public void updatePassword(Long id, String password, String newPassword,
115114
String newPasswordCheck) {
116-
User user = findUser(id);
115+
User user = findUserById(id);
117116

118117
if (isNotMatchCurrentPassword(password, user.getPassword())) {
119118
throw new PasswordNotMatchException(UserErrorCode.PASSWORD_MISMATCH);
@@ -128,7 +127,7 @@ public void updatePassword(Long id, String password, String newPassword,
128127
}
129128

130129
public void deleteUser(Long userId, String password) {
131-
User user = findUser(userId);
130+
User user = findUserById(userId);
132131

133132
if (isNotMatchCurrentPassword(password, user.getPassword())) {
134133
throw new PasswordNotMatchException(UserErrorCode.PASSWORD_MISMATCH);
@@ -142,7 +141,7 @@ public void deleteUser(Long userId, String password) {
142141
}
143142

144143
public void deleteUser(Long userId) {
145-
User user = findUser(userId);
144+
User user = findUserById(userId);
146145

147146
prTemplateService.deleteByUserId(user.getId());
148147
linkService.deleteByUserId(userId);
@@ -157,6 +156,7 @@ public void initializeUserData(Long userId) {
157156
buddyEnergyService.createDefaultEnergy(userId);
158157
}
159158

159+
@Transactional(readOnly = true)
160160
public UserResponse getUserResponse(Long userId) {
161161
User user = get(userId);
162162
return UserResponse.toUserResponse(
@@ -168,6 +168,7 @@ public UserResponse getUserResponse(Long userId) {
168168
user.getRole());
169169
}
170170

171+
@Transactional(readOnly = true)
171172
public List<AllUserResponse> getAllUsers() {
172173
return userRepository.findAllByActivatedTrue().stream()
173174
.map(user -> AllUserResponse.builder()
@@ -180,13 +181,26 @@ public List<AllUserResponse> getAllUsers() {
180181
.toList();
181182
}
182183

183-
private User findUser(Long id) {
184+
private String validateUpdateNickname(User user, String nickname) {
185+
if (isChangedNickname(nickname)) {
186+
nickNameDuplicationCheck(nickname);
187+
} else {
188+
nickname = user.getNickname();
189+
}
190+
return nickname;
191+
}
192+
193+
private boolean isChangedNickname(String nickname){
194+
return nickname != null && !nickname.isBlank();
195+
}
196+
197+
private User findUserById(Long id) {
184198
return userRepository.findById(id)
185199
.orElseThrow(
186200
() -> new UserNotFoundException(UserErrorCode.USER_NOT_FOUND));
187201
}
188202

189-
private User findUser(String email) {
203+
private User findUserByEmail(String email) {
190204
return userRepository.findByEmail(email)
191205
.orElseThrow(
192206
() -> new UserNotFoundException(UserErrorCode.USER_NOT_FOUND));
@@ -202,6 +216,12 @@ private void duplicationCheck(String email, String nickname) {
202216
}
203217
}
204218

219+
private void nickNameDuplicationCheck(String nickname){
220+
if(isDuplicateNickname(nickname)){
221+
throw new NicknameDuplicatedException(UserErrorCode.IS_DUPLICATED_NICKNAME);
222+
}
223+
}
224+
205225
private boolean isDuplicateEmail(String email) {
206226
return userRepository.findByEmail(email).isPresent();
207227
}

0 commit comments

Comments
 (0)