Skip to content

Commit

Permalink
feat: 모집 공고 절차 추가 및 관련 API 구현 완료 (#480)
Browse files Browse the repository at this point in the history
  • Loading branch information
limehee authored Aug 18, 2024
1 parent cdc2d97 commit 8b93eae
Show file tree
Hide file tree
Showing 14 changed files with 116 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,10 @@ public static ApplicationPassResponseDto toDto(Application application) {
.isPass(application.getIsPass())
.build();
}

public static ApplicationPassResponseDto defaultResponse() {
return ApplicationPassResponseDto.builder()
.isPass(false)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package page.clab.api.domain.hiring.application.application.exception;

public class RecruitmentEndDateExceededException extends RuntimeException {

public RecruitmentEndDateExceededException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,26 @@
import page.clab.api.domain.hiring.application.application.dto.response.ApplicationPassResponseDto;
import page.clab.api.domain.hiring.application.application.port.in.CheckApplicationPassStatusUseCase;
import page.clab.api.domain.hiring.application.application.port.out.RetrieveApplicationPort;
import page.clab.api.domain.hiring.recruitment.application.port.out.RetrieveRecruitmentPort;
import page.clab.api.domain.hiring.recruitment.domain.Recruitment;

@Service
@RequiredArgsConstructor
public class ApplicationPassCheckService implements CheckApplicationPassStatusUseCase {

private final RetrieveApplicationPort retrieveApplicationPort;
private final RetrieveRecruitmentPort retrieveRecruitmentPort;

@Transactional(readOnly = true)
@Override
public ApplicationPassResponseDto checkPassStatus(Long recruitmentId, String studentId) {
ApplicationId id = ApplicationId.create(studentId, recruitmentId);
Recruitment recruitment = retrieveRecruitmentPort.findByIdOrThrow(recruitmentId);

recruitment.validateEndDateWithin7Days();

return retrieveApplicationPort.findById(id)
.map(ApplicationPassResponseDto::toDto)
.orElseGet(() ->
ApplicationPassResponseDto.builder()
.isPass(false)
.build()
);
.orElseGet(ApplicationPassResponseDto::defaultResponse);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import page.clab.api.domain.hiring.recruitment.application.dto.response.RecruitmentEndDateResponseDto;
import page.clab.api.domain.hiring.recruitment.application.dto.response.RecruitmentResponseDto;
import page.clab.api.domain.hiring.recruitment.application.port.in.RetrieveRecentRecruitmentsUseCase;
import page.clab.api.global.common.dto.ApiResponse;
Expand All @@ -27,4 +28,11 @@ public ApiResponse<List<RecruitmentResponseDto>> retrieveRecentRecruitments() {
List<RecruitmentResponseDto> recruitments = retrieveRecentRecruitmentsUseCase.retrieveRecentRecruitments();
return ApiResponse.success(recruitments);
}

@Operation(summary = "모집 종료 기간 기준 최신 일주일 모집 공고 목록", description = "ROLE_ANONYMOUS 이상의 권한이 필요함")
@GetMapping("/recent-week")
public ApiResponse<List<RecruitmentEndDateResponseDto>> retrieveRecruitmentsByEndDate() {
List<RecruitmentEndDateResponseDto> recruitments = retrieveRecentRecruitmentsUseCase.retrieveRecruitmentsByEndDate();
return ApiResponse.success(recruitments);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import page.clab.api.domain.hiring.recruitment.domain.Recruitment;
import page.clab.api.global.exception.NotFoundException;

import java.time.LocalDateTime;
import java.util.List;

@Component
Expand Down Expand Up @@ -56,9 +57,9 @@ public List<Recruitment> findTop5ByOrderByCreatedAtDesc() {
}

@Override
public void existsByIdOrThrow(Long recruitmentId) {
if (!repository.existsById(recruitmentId)) {
throw new NotFoundException("[Recruitment] id: " + recruitmentId + "에 해당하는 모집 공고가 존재하지 않습니다.");
}
public List<Recruitment> findByEndDateBetween(LocalDateTime weekAgo, LocalDateTime now) {
return repository.findByEndDateBetween(weekAgo, now).stream()
.map(mapper::toDomainEntity)
.toList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.util.List;

@Repository
public interface RecruitmentRepository extends JpaRepository<RecruitmentJpaEntity, Long> {

List<RecruitmentJpaEntity> findTop5ByOrderByCreatedAtDesc();

List<RecruitmentJpaEntity> findByEndDateBetween(LocalDateTime weekAgo, LocalDateTime now);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package page.clab.api.domain.hiring.recruitment.application.dto.response;

import lombok.Builder;
import lombok.Getter;
import page.clab.api.domain.hiring.application.domain.ApplicationType;
import page.clab.api.domain.hiring.recruitment.domain.Recruitment;

import java.util.List;

@Getter
@Builder
public class RecruitmentEndDateResponseDto {

private Long id;
private ApplicationType applicationType;

public static List<RecruitmentEndDateResponseDto> toDto(List<Recruitment> recruitments) {
return recruitments.stream()
.map(RecruitmentEndDateResponseDto::toDto)
.toList();
}

public static RecruitmentEndDateResponseDto toDto(Recruitment recruitment) {
return RecruitmentEndDateResponseDto.builder()
.id(recruitment.getId())
.applicationType(recruitment.getApplicationType())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package page.clab.api.domain.hiring.recruitment.application.port.in;

import page.clab.api.domain.hiring.recruitment.application.dto.response.RecruitmentEndDateResponseDto;
import page.clab.api.domain.hiring.recruitment.application.dto.response.RecruitmentResponseDto;

import java.util.List;

public interface RetrieveRecentRecruitmentsUseCase {

List<RecruitmentResponseDto> retrieveRecentRecruitments();

List<RecruitmentEndDateResponseDto> retrieveRecruitmentsByEndDate();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import page.clab.api.domain.hiring.recruitment.domain.Recruitment;

import java.time.LocalDateTime;
import java.util.List;

public interface RetrieveRecruitmentPort {
Expand All @@ -12,5 +13,5 @@ public interface RetrieveRecruitmentPort {

List<Recruitment> findTop5ByOrderByCreatedAtDesc();

void existsByIdOrThrow(Long recruitmentId);
List<Recruitment> findByEndDateBetween(LocalDateTime weekAgo, LocalDateTime now);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import page.clab.api.domain.hiring.recruitment.application.dto.response.RecruitmentEndDateResponseDto;
import page.clab.api.domain.hiring.recruitment.application.dto.response.RecruitmentResponseDto;
import page.clab.api.domain.hiring.recruitment.application.port.in.RetrieveRecentRecruitmentsUseCase;
import page.clab.api.domain.hiring.recruitment.application.port.out.RetrieveRecruitmentPort;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;

@Service
Expand All @@ -22,4 +25,16 @@ public List<RecruitmentResponseDto> retrieveRecentRecruitments() {
.map(RecruitmentResponseDto::toDto)
.toList();
}

@Transactional(readOnly = true)
@Override
public List<RecruitmentEndDateResponseDto> retrieveRecruitmentsByEndDate() {
LocalDateTime now = LocalDateTime.now();
LocalDateTime weekAgo = now.minusWeeks(1).with(LocalTime.MIN);
LocalDateTime endOfDay = now.with(LocalTime.MAX);

return retrieveRecruitmentPort.findByEndDateBetween(weekAgo, endOfDay).stream()
.map(RecruitmentEndDateResponseDto::toDto)
.toList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import page.clab.api.domain.hiring.application.application.exception.RecruitmentEndDateExceededException;
import page.clab.api.domain.hiring.application.application.exception.RecruitmentNotActiveException;
import page.clab.api.domain.hiring.application.domain.ApplicationType;
import page.clab.api.domain.hiring.recruitment.application.dto.request.RecruitmentUpdateRequestDto;
import page.clab.api.global.exception.InvalidDateRangeException;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Optional;

Expand Down Expand Up @@ -56,4 +58,22 @@ public void validateDateRange() {
throw new InvalidDateRangeException("시작일은 종료일보다 늦을 수 없습니다.");
}
}

/**
* 모집 종료일이 현재 날짜 기준 7일 이내인지 확인하고, 그렇지 않은 경우 예외를 발생시킵니다.
*
* @throws RecruitmentEndDateExceededException 모집 종료일이 현재 날짜 기준 7일을 초과했거나, 아직 모집이 종료되지 않은 경우 발생
*/
public void validateEndDateWithin7Days() {
LocalDate today = LocalDate.now();
LocalDate endDate = this.endDate.toLocalDate();

if (endDate.isBefore(today.minusDays(7)) || !this.isRecruitmentEnd()) {
throw new RecruitmentEndDateExceededException("지원 기간이 종료된 지 7일이 넘었거나, 아직 종료되지 않은 모집입니다.");
}
}

public boolean isRecruitmentEnd() {
return LocalDateTime.now().isAfter(endDate) || status.isClosed();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,8 @@ public enum RecruitmentStatus {
public boolean isRecruiting() {
return this.equals(RecruitmentStatus.OPEN);
}

public boolean isClosed() {
return this.equals(RecruitmentStatus.CLOSED);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class SecurityConstants {

public static final String[] PERMIT_ALL_API_ENDPOINTS_GET = {
"/api/v1/applications/{studentId}",
"/api/v1/recruitments",
"/api/v1/recruitments", "/api/v1/recruitments/recent-week",
"/api/v1/news", "/api/v1/news/**",
"/api/v1/blogs", "/api/v1/blogs/**",
"/api/v1/positions", "/api/v1/positions/**",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import page.clab.api.domain.auth.login.application.exception.MemberLockedException;
import page.clab.api.domain.community.accuse.application.exception.AccuseTargetTypeIncorrectException;
import page.clab.api.domain.hiring.application.application.exception.NotApprovedApplicationException;
import page.clab.api.domain.hiring.application.application.exception.RecruitmentEndDateExceededException;
import page.clab.api.domain.hiring.application.application.exception.RecruitmentNotActiveException;
import page.clab.api.domain.library.book.application.exception.BookAlreadyBorrowedException;
import page.clab.api.domain.library.book.application.exception.InvalidBorrowerException;
Expand Down Expand Up @@ -96,6 +97,7 @@ public class GlobalExceptionHandler {
InvalidEmojiException.class,
InvalidRoleChangeException.class,
RecruitmentNotActiveException.class,
RecruitmentEndDateExceededException.class,
StringIndexOutOfBoundsException.class,
MissingServletRequestParameterException.class,
MalformedJsonException.class,
Expand Down

0 comments on commit 8b93eae

Please sign in to comment.