Skip to content

Commit b17df69

Browse files
committed
[EA3-168] feature: 스터디 신청 및 승인 시 참여 10개 제한 기능
1 parent 21974e5 commit b17df69

File tree

4 files changed

+48
-13
lines changed

4 files changed

+48
-13
lines changed

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

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,19 @@ public enum StudyErrorCode implements ErrorCode {
1212
EXTENDED_STUDY_NOT_FOUND("S003", HttpStatus.NOT_FOUND, "연장된 스터디를 찾을 수 없습니다."),
1313

1414
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인 스터디는 지역 입력이 필수입니다."),
18-
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, "연장 스터디 참여는 한 번만 등록할 수 있습니다."),
23-
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, "자기 자신에게는 스터디장 위임이 불가능합니다.");
15+
STUDY_PARTICIPATE_LIMIT ("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인 스터디는 지역 입력이 필수입니다."),
19+
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, "연장 스터디 참여는 한 번만 등록할 수 있습니다."),
24+
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/domain/study/repository/StudyMemberQueryRepository.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package grep.neogulcoder.domain.study.repository;
22

33
import com.querydsl.core.types.Projections;
4+
import com.querydsl.core.types.dsl.BooleanExpression;
45
import com.querydsl.jpa.impl.JPAQueryFactory;
56
import grep.neogulcoder.domain.study.StudyMember;
67
import grep.neogulcoder.domain.study.controller.dto.response.ExtendParticipationResponse;
@@ -81,4 +82,23 @@ public List<StudyMember> findByIdIn(List<Long> studyIds) {
8182
.join(studyMember.study, study).fetchJoin()
8283
.fetch();
8384
}
85+
86+
public int countActiveUnfinishedStudies(Long userId) {
87+
BooleanExpression notExtendedAndParticipate = study.extended.isFalse().and(studyMember.activated.isTrue());
88+
BooleanExpression extendedAndNotParticipate = study.extended.isTrue().and(studyMember.participated.isFalse());
89+
90+
Long result = queryFactory
91+
.select(studyMember.count())
92+
.from(studyMember)
93+
.join(studyMember.study, study)
94+
.where(
95+
studyMember.userId.eq(userId),
96+
study.activated.isTrue(),
97+
study.finished.isFalse(),
98+
notExtendedAndParticipate.or(extendedAndNotParticipate)
99+
)
100+
.fetchOne();
101+
102+
return result != null ? result.intValue() : 0;
103+
}
84104
}

src/main/java/grep/neogulcoder/domain/study/service/StudyService.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ public class StudyService {
6161
private final TeamCalendarService teamCalendarService;
6262
private final GroupChatRoomRepository groupChatRoomRepository;
6363

64-
6564
public StudyItemPagingResponse getMyStudiesPaging(Pageable pageable, Long userId, Boolean finished) {
6665
Page<StudyItemResponse> page = studyQueryRepository.findMyStudiesPaging(pageable, userId, finished);
6766
return StudyItemPagingResponse.of(page);
@@ -259,4 +258,7 @@ private boolean isImgExists(MultipartFile image) {
259258
return image != null && !image.isEmpty();
260259
}
261260

261+
private int getActiveUnfinishedStudiesCount(Long userId) {
262+
return studyMemberQueryRepository.countActiveUnfinishedStudies(userId);
263+
}
262264
}

src/main/java/grep/neogulcoder/domain/studyapplication/service/ApplicationService.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import grep.neogulcoder.domain.study.Study;
66
import grep.neogulcoder.domain.study.StudyMember;
77
import grep.neogulcoder.domain.study.enums.StudyMemberRole;
8+
import grep.neogulcoder.domain.study.repository.StudyMemberQueryRepository;
89
import grep.neogulcoder.domain.study.repository.StudyMemberRepository;
910
import grep.neogulcoder.domain.study.repository.StudyRepository;
1011
import grep.neogulcoder.domain.studyapplication.ApplicationStatus;
@@ -27,6 +28,7 @@
2728
import static grep.neogulcoder.domain.recruitment.RecruitmentErrorCode.NOT_FOUND;
2829
import static grep.neogulcoder.domain.recruitment.RecruitmentErrorCode.NOT_OWNER;
2930
import static grep.neogulcoder.domain.study.exception.code.StudyErrorCode.STUDY_NOT_FOUND;
31+
import static grep.neogulcoder.domain.study.exception.code.StudyErrorCode.STUDY_PARTICIPATE_LIMIT;
3032
import static grep.neogulcoder.domain.studyapplication.exception.code.ApplicationErrorCode.*;
3133

3234
@Transactional(readOnly = true)
@@ -39,6 +41,7 @@ public class ApplicationService {
3941
private final RecruitmentPostRepository recruitmentPostRepository;
4042
private final StudyMemberRepository studyMemberRepository;
4143
private final StudyRepository studyRepository;
44+
private final StudyMemberQueryRepository studyMemberQueryRepository;
4245

4346
@Transactional
4447
public ReceivedApplicationPagingResponse getReceivedApplicationsPaging(Long recruitmentPostId, Pageable pageable, Long userId) {
@@ -62,6 +65,7 @@ public Long createApplication(Long recruitmentPostId, ApplicationCreateRequest r
6265

6366
validateNotLeaderApply(recruitmentPost, userId);
6467
validateNotAlreadyApplied(recruitmentPostId, userId);
68+
validateStudyParticipationLimit(userId);
6569

6670
StudyApplication application = request.toEntity(recruitmentPostId, userId);
6771
applicationRepository.save(application);
@@ -77,6 +81,7 @@ public void approveApplication(Long applicationId, Long userId) {
7781

7882
validateOnlyLeaderCanApprove(study, userId);
7983
validateStatusIsApplying(application);
84+
validateStudyParticipationLimit(application.getUserId());
8085

8186
application.approve();
8287

@@ -154,4 +159,11 @@ private void validateOnlyLeaderCanReject(Study study, Long userId) {
154159
throw new BusinessException(LEADER_ONLY_REJECTED);
155160
}
156161
}
162+
163+
private void validateStudyParticipationLimit(Long userId) {
164+
int count = studyMemberQueryRepository.countActiveUnfinishedStudies(userId);
165+
if (count >= 10) {
166+
throw new BusinessException(STUDY_PARTICIPATE_LIMIT);
167+
}
168+
}
157169
}

0 commit comments

Comments
 (0)