diff --git a/src/main/java/grep/neogulcoder/domain/recruitment/RecruitmentErrorCode.java b/src/main/java/grep/neogulcoder/domain/recruitment/RecruitmentErrorCode.java index 283c3120..d6217cb3 100644 --- a/src/main/java/grep/neogulcoder/domain/recruitment/RecruitmentErrorCode.java +++ b/src/main/java/grep/neogulcoder/domain/recruitment/RecruitmentErrorCode.java @@ -15,7 +15,8 @@ public enum RecruitmentErrorCode implements ErrorCode { NOT_FOUND_STUDY_MEMBER(HttpStatus.NOT_FOUND, HttpStatus.NOT_FOUND.name(), "스터디에 참여하고 있지 않은 회원 입니다."), NOT_FOUND_COMMENT(HttpStatus.NOT_FOUND, HttpStatus.NOT_FOUND.name(), "댓글을 찾지 못했습니다"), NOT_OWNER(HttpStatus.BAD_REQUEST, HttpStatus.BAD_REQUEST.name(), "모집글을 등록한 당사자가 아닙니다."), - END_DATE_ERROR(HttpStatus.BAD_REQUEST, HttpStatus.BAD_REQUEST.name(), "모집글은 스터디가 시작되고 종료될 때까지 작성 가능 합니다."); + END_DATE_ERROR(HttpStatus.BAD_REQUEST, HttpStatus.BAD_REQUEST.name(), "모집글은 스터디가 시작되고 종료될 때까지 작성 가능 합니다."), + END_DATE_BEFORE_NOW_NOT_ALLOWED(HttpStatus.BAD_REQUEST, HttpStatus.BAD_REQUEST.name(), "모집글 마감기간은 오늘 이전으로 선택은 불가능 합니다."); private static final String BASIC_MESSAGE = "RECRUITMENT"; private final HttpStatus status; diff --git a/src/main/java/grep/neogulcoder/domain/recruitment/post/controller/RecruitmentPostSaveController.java b/src/main/java/grep/neogulcoder/domain/recruitment/post/controller/RecruitmentPostSaveController.java index 56b05159..fc4558a4 100644 --- a/src/main/java/grep/neogulcoder/domain/recruitment/post/controller/RecruitmentPostSaveController.java +++ b/src/main/java/grep/neogulcoder/domain/recruitment/post/controller/RecruitmentPostSaveController.java @@ -5,6 +5,7 @@ import grep.neogulcoder.domain.recruitment.post.controller.dto.response.save.JoinedStudyLoadInfo; import grep.neogulcoder.domain.recruitment.post.service.RecruitmentPostSaveService; import grep.neogulcoder.global.auth.Principal; +import grep.neogulcoder.global.exception.validation.ValidationException; import grep.neogulcoder.global.response.ApiResponse; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -12,6 +13,10 @@ import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; +import java.time.LocalDate; + +import static grep.neogulcoder.domain.recruitment.RecruitmentErrorCode.END_DATE_BEFORE_NOW_NOT_ALLOWED; + @RequestMapping("/recruitment-posts") @RequiredArgsConstructor @RestController @@ -22,6 +27,11 @@ public class RecruitmentPostSaveController implements RecruitmentPostSaveSpecifi @PostMapping public ResponseEntity> save(@Valid @RequestBody RecruitmentPostCreateRequest request, @AuthenticationPrincipal Principal userDetails) { + + if (request.hasExpiredDateBefore(LocalDate.now())) { + throw new ValidationException(END_DATE_BEFORE_NOW_NOT_ALLOWED); + } + long postId = recruitmentPostService.create(request.toServiceRequest(), userDetails.getUserId()); return ResponseEntity.ok(ApiResponse.success(postId)); } diff --git a/src/main/java/grep/neogulcoder/domain/recruitment/post/controller/dto/request/save/RecruitmentPostCreateRequest.java b/src/main/java/grep/neogulcoder/domain/recruitment/post/controller/dto/request/save/RecruitmentPostCreateRequest.java index b48001ae..33272486 100644 --- a/src/main/java/grep/neogulcoder/domain/recruitment/post/controller/dto/request/save/RecruitmentPostCreateRequest.java +++ b/src/main/java/grep/neogulcoder/domain/recruitment/post/controller/dto/request/save/RecruitmentPostCreateRequest.java @@ -8,6 +8,7 @@ import lombok.Builder; import lombok.Getter; +import java.time.LocalDate; import java.time.LocalDateTime; @Getter @@ -55,4 +56,8 @@ public RecruitmentPostCreateServiceRequest toServiceRequest() { .expiredDate(this.expiredDate) .build(); } + + public boolean hasExpiredDateBefore(LocalDate date) { + return this.expiredDate.toLocalDate().isBefore(date); + } } diff --git a/src/main/java/grep/neogulcoder/domain/recruitment/post/service/RecruitmentPostSaveService.java b/src/main/java/grep/neogulcoder/domain/recruitment/post/service/RecruitmentPostSaveService.java index 02715b89..09eab9fa 100644 --- a/src/main/java/grep/neogulcoder/domain/recruitment/post/service/RecruitmentPostSaveService.java +++ b/src/main/java/grep/neogulcoder/domain/recruitment/post/service/RecruitmentPostSaveService.java @@ -1,7 +1,7 @@ package grep.neogulcoder.domain.recruitment.post.service; -import grep.neogulcoder.domain.recruitment.post.controller.dto.response.save.JoinedStudyLoadInfo; import grep.neogulcoder.domain.recruitment.post.controller.dto.response.save.JoinedStudiesInfo; +import grep.neogulcoder.domain.recruitment.post.controller.dto.response.save.JoinedStudyLoadInfo; import grep.neogulcoder.domain.recruitment.post.repository.RecruitmentPostRepository; import grep.neogulcoder.domain.recruitment.post.service.request.RecruitmentPostCreateServiceRequest; import grep.neogulcoder.domain.study.Study; @@ -13,12 +13,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.time.LocalDateTime; import java.util.List; import static grep.neogulcoder.domain.recruitment.RecruitmentErrorCode.*; -import static grep.neogulcoder.domain.recruitment.RecruitmentErrorCode.NOT_FOUND_STUDY_MEMBER; -import static grep.neogulcoder.domain.recruitment.RecruitmentErrorCode.NOT_STUDY_LEADER; @RequiredArgsConstructor @Transactional(readOnly = true) @@ -36,7 +33,7 @@ public long create(RecruitmentPostCreateServiceRequest request, long userId) { throw new BusinessException(NOT_STUDY_LEADER); } - if(studyMember.getStudy().hasEndDateBefore(request.getExpiredDate())){ + if (studyMember.getStudy().hasEndDateBefore(request.getExpiredDate())) { throw new BusinessException(END_DATE_ERROR); } @@ -70,7 +67,7 @@ private List toStudyList(List studyMembers) { private Study findValidStudy(long studyId, long userId) { StudyMember studyMember = studyMemberRepository.findByStudyIdAndUserId(studyId, userId); - if(isNotParticipated(studyMember)){ + if (isNotParticipated(studyMember)) { throw new NotFoundException(NOT_FOUND_STUDY_MEMBER); } return studyMember.getStudy(); diff --git a/src/main/java/grep/neogulcoder/domain/study/Study.java b/src/main/java/grep/neogulcoder/domain/study/Study.java index f9129428..260de1a4 100644 --- a/src/main/java/grep/neogulcoder/domain/study/Study.java +++ b/src/main/java/grep/neogulcoder/domain/study/Study.java @@ -126,7 +126,7 @@ public boolean isReviewableAt(LocalDateTime currentDateTime) { } public boolean hasEndDateBefore(LocalDateTime dateTime) { - return this.endDate.isBefore(dateTime); + return this.endDate.toLocalDate().isBefore(dateTime.toLocalDate()); } public static boolean isOverJoinLimit(int joinedStudyCount) { diff --git a/src/main/java/grep/neogulcoder/domain/study/service/StudySchedulerService.java b/src/main/java/grep/neogulcoder/domain/study/service/StudySchedulerService.java index 59c6bc0c..57f3c876 100644 --- a/src/main/java/grep/neogulcoder/domain/study/service/StudySchedulerService.java +++ b/src/main/java/grep/neogulcoder/domain/study/service/StudySchedulerService.java @@ -4,6 +4,7 @@ import grep.neogulcoder.domain.study.Study; import grep.neogulcoder.domain.study.StudyMember; import grep.neogulcoder.domain.study.event.StudyExtensionReminderEvent; +import grep.neogulcoder.domain.study.repository.StudyMemberQueryRepository; import grep.neogulcoder.domain.study.repository.StudyMemberRepository; import grep.neogulcoder.domain.study.repository.StudyRepository; import lombok.RequiredArgsConstructor; @@ -14,6 +15,8 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; @Transactional(readOnly = true) @RequiredArgsConstructor @@ -24,6 +27,7 @@ public class StudySchedulerService { private final BuddyEnergyService buddyEnergyService; private final StudyMemberRepository studyMemberRepository; private final ApplicationEventPublisher eventPublisher; + private final StudyMemberQueryRepository studyMemberQueryRepository; @Transactional public void findStudiesEndingIn7Days() { @@ -43,14 +47,27 @@ public void finalizeStudies() { LocalDateTime now = LocalDateTime.now(); List studiesToBeFinished = studyRepository.findStudiesToBeFinished(now); + Map> memberMap = getActivatedMemberMap(studiesToBeFinished); + for (Study study : studiesToBeFinished) { study.finish(); // 스터디 멤버들 조회 후 버디에너지 업데이트 - List members = studyMemberRepository.findFetchStudyByStudyId(study.getId()); + List members = memberMap.getOrDefault(study.getId(), List.of()); for (StudyMember member : members) { buddyEnergyService.updateEnergyByStudy(member.getUserId(), member.isLeader()); } } } + + private Map> getActivatedMemberMap(List studies) { + List studyIds = studies.stream() + .map(Study::getId) + .toList(); + + List allActivatedMembers = studyMemberQueryRepository.findActivatedMembersByStudyIds(studyIds); + + return allActivatedMembers.stream() + .collect(Collectors.groupingBy(studyMember -> studyMember.getStudy().getId())); + } }