Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

개발 디버깅용 테스트 데이터 추가 및 모집 공고 마감기한 검증 로직 수정 #58

Merged
merged 5 commits into from
Sep 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package com.server.crews.global.config;

import com.server.crews.applicant.domain.Application;
import com.server.crews.applicant.domain.NarrativeAnswer;
import com.server.crews.applicant.domain.SelectiveAnswer;
import com.server.crews.applicant.repository.ApplicationRepository;
import com.server.crews.auth.domain.Administrator;
import com.server.crews.auth.domain.Applicant;
import com.server.crews.auth.repository.AdministratorRepository;
import com.server.crews.auth.repository.ApplicantRepository;
import com.server.crews.recruitment.domain.Choice;
import com.server.crews.recruitment.domain.NarrativeQuestion;
import com.server.crews.recruitment.domain.Recruitment;
import com.server.crews.recruitment.domain.Section;
import com.server.crews.recruitment.domain.SelectiveQuestion;
import com.server.crews.recruitment.repository.RecruitmentRepository;
import java.time.LocalDateTime;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Profile;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Profile(value = "!prod")
@Component
@Transactional
@RequiredArgsConstructor
public class DatabaseInitializer implements ApplicationRunner {
private final PasswordEncoder passwordEncoder;
private final AdministratorRepository administratorRepository;
private final RecruitmentRepository recruitmentRepository;
private final ApplicantRepository applicantRepository;
private final ApplicationRepository applicationRepository;

@Override
public void run(ApplicationArguments args) {
Administrator administrator = new Administrator("admin", passwordEncoder.encode("12341234!"));
administratorRepository.save(administrator);

NarrativeQuestion introductionQuestion = new NarrativeQuestion(null, "자기소개해주세요", true, 1, 500);
List<Choice> personalityChoices = List.of(new Choice(null, "성실함"), new Choice(null, "밝음"),
new Choice(null, "꼼꼼함"));
SelectiveQuestion personalityQuestion = new SelectiveQuestion(null, personalityChoices, "장점을 골라주세요", true, 2, 1,
1);
Section commonSection = new Section(null, "공통", "웹 어플리케이션 서버 개발 파트", List.of(introductionQuestion),
List.of(personalityQuestion));

NarrativeQuestion backendNarrativeQuestion = new NarrativeQuestion(null, "백엔드 파트와 관련된 활동 하나를 서술해주세요.", true, 1,
600);
List<Choice> backendStackChoices = List.of(new Choice(null, "Django, Python"),
new Choice(null, "Springboot, Java"));
SelectiveQuestion backendStackQuestion = new SelectiveQuestion(null, backendStackChoices,
"멋사 프로젝트에서 사용하고 싶은 스택을 골라주세요", true, 2, 1, 2);
Section backendSection = new Section(null, "백엔드", "웹 어플리케이션 서버 개발 파트", List.of(backendNarrativeQuestion),
List.of(backendStackQuestion));

NarrativeQuestion frontendNarrativeQuestion = new NarrativeQuestion(null, "프론트엔드 파트와 관련된 활동 하나를 서술해주세요.", true,
1, 600);
Section frontendSection = new Section(null, "프론트엔드", "웹 클라이언트 사이드 개발 파트", List.of(frontendNarrativeQuestion),
List.of());

Recruitment recruitment = new Recruitment(null, "test-code", "멋쟁이 사자처럼 99기 아기사자 모집",
"멋쟁이 사자처럼 서강대에서 99기 아기사자를 모집합니다!", LocalDateTime.of(2024, 9, 1, 2, 0), administrator,
List.of(commonSection, backendSection, frontendSection));
recruitment.close();
recruitmentRepository.save(recruitment);

Applicant kh = new Applicant("[email protected]", passwordEncoder.encode("test-password"));
Applicant lkh = new Applicant("[email protected]", passwordEncoder.encode("test-password"));
applicantRepository.saveAll(List.of(kh, lkh));

NarrativeAnswer skhIntroductionAnswer = new NarrativeAnswer(null, introductionQuestion, "안녕하세요");
SelectiveAnswer skhPersonalityAnswer = new SelectiveAnswer(null, personalityChoices.get(0),
personalityQuestion);
NarrativeAnswer skhBackendNarrativeAnswer = new NarrativeAnswer(null, backendNarrativeQuestion,
"크루즈 프로젝트 서버 개발을 맡았습니다.");
SelectiveAnswer skhBackendStackAnswer = new SelectiveAnswer(null, backendStackChoices.get(1),
backendStackQuestion);
Application skhApplication = new Application(null, recruitment, kh, "202011414", "컴퓨터공학", "송경호",
List.of(skhIntroductionAnswer, skhBackendNarrativeAnswer),
List.of(skhPersonalityAnswer, skhBackendStackAnswer));
applicationRepository.save(skhApplication);

NarrativeAnswer lkhIntroductionAnswer = new NarrativeAnswer(null, introductionQuestion, "반갑습니다");
SelectiveAnswer lkhPersonalityAnswer = new SelectiveAnswer(null, personalityChoices.get(1),
personalityQuestion);
NarrativeAnswer lkhFrontendNarrativeAnswer = new NarrativeAnswer(null, frontendNarrativeQuestion,
"크루즈 프로젝트 프론트 개발을 맡았습니다.");
Application lkhApplication = new Application(null, recruitment, lkh, "202013232", "컴퓨터공학", "이규호",
List.of(lkhIntroductionAnswer, lkhFrontendNarrativeAnswer), List.of(lkhPersonalityAnswer));
applicationRepository.save(lkhApplication);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public enum ErrorCode {
ALREADY_ANNOUNCED(HttpStatus.BAD_REQUEST, "모집 공고 결과 발표가 이미 완료되었습니다."),
RECRUITMENT_ALREADY_STARTED(HttpStatus.BAD_REQUEST, "모집이 이미 시작되었습니다."),
RECRUITMENT_NOT_STARTED(HttpStatus.BAD_REQUEST, "모집이 시작되지 않았습니다."),
INVALID_MODIFIED_DEADLINE(HttpStatus.BAD_REQUEST, "수정된 모집 마감 기한은 기존 기한 이후이며 모집 진행 중에만 수정할 수 있습니다."),

NO_TOKEN(HttpStatus.UNAUTHORIZED, "토큰이 존재하지 않습니다."),
INVALID_TOKEN(HttpStatus.UNAUTHORIZED, "토큰 형식이 잘못 되었습니다."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.server.crews.recruitment.repository.SelectiveQuestionRepository;
import java.time.Clock;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand Down Expand Up @@ -55,11 +56,22 @@ public RecruitmentDetailsResponse saveRecruitment(Long publisherId, RecruitmentS
.orElseThrow(() -> new CrewsException(ErrorCode.USER_NOT_FOUND));
String code = UUID.randomUUID().toString();
Recruitment recruitment = RecruitmentMapper.recruitmentSaveRequestToRecruitment(request, code, publisher);
validateDeadline(recruitment.getDeadline());
Recruitment savedRecruitment = recruitmentRepository.save(recruitment);
savedRecruitment.sortQuestions();
return RecruitmentMapper.recruitmentToRecruitmentDetailsResponse(savedRecruitment);
}

private void validateDeadline(LocalDateTime deadline) {
LocalDateTime now = LocalDateTime.now(Clock.system(ZoneId.of("Asia/Seoul")));
if (deadline.isBefore(now)) {
throw new CrewsException(ErrorCode.INVALID_DEADLINE);
}
if (deadline.getMinute() != 0 || deadline.getSecond() != 0 || deadline.getNano() != 0) {
throw new CrewsException(ErrorCode.INVALID_DEADLINE);
}
}

@Transactional
public void startRecruiting(Long publisherId) {
Recruitment recruitment = recruitmentRepository.findByPublisher(publisherId)
Expand Down Expand Up @@ -120,8 +132,12 @@ public RecruitmentProgressResponse findRecruitmentProgress(Long publisherId) {
public void updateDeadline(Long publisherId, DeadlineUpdateRequest request) {
Recruitment recruitment = recruitmentRepository.findByPublisher(publisherId)
.orElseThrow(() -> new CrewsException(ErrorCode.RECRUITMENT_NOT_FOUND));
LocalDateTime deadline = LocalDateTime.parse(request.deadline());
recruitment.updateDeadline(deadline);

LocalDateTime modifiedDeadline = LocalDateTime.parse(request.deadline());
if (!recruitment.hasOnOrAfterDeadline(modifiedDeadline) || !recruitment.isInProgress()) {
throw new CrewsException(ErrorCode.INVALID_MODIFIED_DEADLINE);
}
recruitment.updateDeadline(modifiedDeadline);
}

@Transactional
Expand All @@ -130,7 +146,7 @@ public void closeRecruitments() {
LocalDateTime now = LocalDateTime.now(clock);
List<Recruitment> recruitments = recruitmentRepository.findAll();
recruitments.stream()
.filter(recruitment -> recruitment.hasPassedDeadline(now))
.filter(recruitment -> recruitment.hasOnOrAfterDeadline(now))
.forEach(Recruitment::close);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,4 @@ public NarrativeQuestion(Long id, String content, Boolean necessity, Integer ord
public void updateSection(final Section section) {
this.section = section;
}

public void setByExistingId(Long id) {
this.id = id;
}
}
24 changes: 6 additions & 18 deletions src/main/java/com/server/crews/recruitment/domain/Recruitment.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.server.crews.recruitment.domain;

import com.server.crews.auth.domain.Administrator;
import com.server.crews.global.exception.CrewsException;
import com.server.crews.global.exception.ErrorCode;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.ConstraintMode;
Expand All @@ -20,9 +18,7 @@
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import java.time.Clock;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;
import lombok.AccessLevel;
Expand Down Expand Up @@ -77,7 +73,6 @@ public class Recruitment {

public Recruitment(Long id, String code, String title, String description, LocalDateTime deadline,
Administrator publisher, List<Section> sections) {
validateDeadline(deadline);
this.id = id;
this.code = code;
this.title = title;
Expand All @@ -89,20 +84,9 @@ public Recruitment(Long id, String code, String title, String description, Local
}

public void updateDeadline(LocalDateTime deadline) {
validateDeadline(deadline);
this.deadline = deadline;
}

private void validateDeadline(LocalDateTime deadline) {
LocalDateTime now = LocalDateTime.now(Clock.system(ZoneId.of("Asia/Seoul")));
if (deadline.isBefore(now)) {
throw new CrewsException(ErrorCode.INVALID_DEADLINE);
}
if (deadline.getMinute() != 0 || deadline.getSecond() != 0 || deadline.getNano() != 0) {
throw new CrewsException(ErrorCode.INVALID_DEADLINE);
}
}

public void addSections(List<Section> sections) {
sections.forEach(section -> section.updateRecruitment(this));
this.sections.addAll(sections);
Expand All @@ -128,8 +112,12 @@ public boolean isStarted() {
return this.progress != RecruitmentProgress.READY;
}

public boolean hasPassedDeadline(LocalDateTime now) {
return now.isAfter(deadline) || now.equals(deadline);
public boolean isInProgress() {
return this.progress == RecruitmentProgress.IN_PROGRESS;
}

public boolean hasOnOrAfterDeadline(LocalDateTime other) {
return other.isAfter(deadline) || other.equals(deadline);
}

public void sortQuestions() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,4 @@ public SelectiveQuestion(Long id, List<Choice> choices, String content, Boolean
public void updateSection(final Section section) {
this.section = section;
}

public void setByExistingId(Long id) {
this.id = id;
}
}
4 changes: 4 additions & 0 deletions src/test/java/com/server/crews/api/ApiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.server.crews.auth.presentation.AuthorizationExtractor;
import com.server.crews.environ.DatabaseCleaner;
import com.server.crews.external.application.EmailService;
import com.server.crews.global.config.DatabaseInitializer;
import com.server.crews.recruitment.dto.request.QuestionType;
import com.server.crews.recruitment.dto.request.RecruitmentSaveRequest;
import com.server.crews.recruitment.dto.response.RecruitmentDetailsResponse;
Expand Down Expand Up @@ -51,6 +52,9 @@ public abstract class ApiTest {
@MockBean
private EmailService emailService;

@MockBean
private DatabaseInitializer databaseInitializer;

protected RequestSpecification spec;

@BeforeEach
Expand Down
10 changes: 7 additions & 3 deletions src/test/java/com/server/crews/api/RecruitmentApiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import io.restassured.response.ExtractableResponse;
import io.restassured.response.Response;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
Expand Down Expand Up @@ -316,10 +315,15 @@ void updateDeadline() {
// given
AdminLoginResponse adminTokenResponse = signUpAdmin(TEST_CLUB_NAME, TEST_PASSWORD);
String adminAccessToken = adminTokenResponse.accessToken();
createRecruitment(adminAccessToken);
RecruitmentDetailsResponse recruitmentDetailsResponse = createRecruitment(adminAccessToken);

RestAssured.given()
.contentType(MediaType.APPLICATION_JSON_VALUE)
.header(HttpHeaders.AUTHORIZATION, AuthorizationExtractor.BEARER_TYPE + adminAccessToken)
.when().patch("/recruitments/in-progress");

DeadlineUpdateRequest deadlineUpdateRequest = new DeadlineUpdateRequest(
LocalDateTime.of(2030, 8, 5, 18, 0).toString());
recruitmentDetailsResponse.deadline().plusDays(1).toString());

// when
ExtractableResponse<Response> response = RestAssured.given(spec).log().all()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.server.crews.environ.DatabaseCleaner;
import com.server.crews.environ.repository.TestRepository;
import com.server.crews.external.application.EmailService;
import com.server.crews.global.config.DatabaseInitializer;
import com.server.crews.recruitment.domain.Recruitment;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -34,6 +35,9 @@ public abstract class ServiceTest {
@MockBean
private EmailService emailService;

@MockBean
private DatabaseInitializer databaseInitializer;

@BeforeEach
void setUp() {
databaseCleaner.clear();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ private List<Choice> choicesInSelectiveQuestions(List<SelectiveQuestion> selecti
.toList();
}

public TestRecruitment start() {
this.recruitment.start();
environ.recruitmentRepository().save(this.recruitment);
return this;
}

public TestRecruitment announce() {
this.recruitment.announce();
environ.recruitmentRepository().save(this.recruitment);
Expand Down
Loading
Loading