Skip to content
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
Expand Up @@ -4,6 +4,7 @@
import com.jobdri.jobdri_api.domain.mockapply.dto.request.MockApplyCreateMockFromJobPostingRequest;
import com.jobdri.jobdri_api.domain.mockapply.dto.request.MockApplyCreateMockRequest;
import com.jobdri.jobdri_api.domain.mockapply.dto.response.MockApplyCreateResponse;
import com.jobdri.jobdri_api.domain.mockapply.dto.response.MockApplyHomeResponse;
import com.jobdri.jobdri_api.domain.mockapply.dto.response.MockApplySequenceResponse;
import com.jobdri.jobdri_api.domain.jobposting.dto.response.JobPostingResponse;
import com.jobdri.jobdri_api.domain.mockapply.service.MockApplyService;
Expand Down Expand Up @@ -33,6 +34,20 @@ public class MockApplyController {

private final MockApplyService mockApplyService;

@Operation(
summary = "내 모의 서류 지원 홈 목록 조회",
description = "홈 화면에서 이어서 작성할 지원과 완료된 분석 결과 카드를 조회합니다."
)
@GetMapping("/me")
public ApiResponse<MockApplyHomeResponse> getMyMockApplies(
@AuthenticationPrincipal UserDetailsImpl userDetails
) {
return ApiResponse.onSuccess(
"모의 서류 지원 목록 조회에 성공했습니다.",
mockApplyService.getMyMockApplies(userDetails.getUser())
);
}

@Operation(
summary = "실제 공고 기반 모의 서류 지원 생성",
description = "공고 텍스트/URL 추출, 공고 저장, 사용자 확인 및 수정이 선행된 뒤 저장된 채용 공고 ID를 기준으로 로그인 사용자의 ACTUAL 타입 모의 서류 지원을 생성합니다."
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.jobdri.jobdri_api.domain.mockapply.dto.response;

import com.jobdri.jobdri_api.domain.analysis.entity.Analysis;
import com.jobdri.jobdri_api.domain.jobposting.entity.JobPosting;
import com.jobdri.jobdri_api.domain.mockapply.entity.ApplyType;
import com.jobdri.jobdri_api.domain.mockapply.entity.MockApply;
import com.jobdri.jobdri_api.domain.mockapply.entity.MockApplyStatus;

import java.time.LocalDateTime;

public record MockApplyHomeItemResponse(
Long mockApplyId,
String resumePath,
Long jobPostingId,
MockApplyStatus status,
String companyName,
String detailClassificationName,
String jobTitle,
LocalDateTime createdAt,
ApplyType applyType,
Integer score
) {
public static MockApplyHomeItemResponse from(MockApply mockApply) {
JobPosting jobPosting = mockApply.getJobPosting();
String detailClassificationName = jobPosting.getDetailClassification().getDetailName();
Analysis analysis = mockApply.getAnalysis();

return new MockApplyHomeItemResponse(
mockApply.getId(),
resumePath(mockApply),
jobPosting.getId(),
mockApply.getStatus(),
jobPosting.getCompany().getName(),
detailClassificationName,
detailClassificationName,
mockApply.getCreatedAt(),
mockApply.getApplyType(),
analysis == null ? null : analysis.getScore()
);
}

private static String resumePath(MockApply mockApply) {
return switch (mockApply.getStatus()) {
case APPLICATION_CREATED -> "/mock-applies/" + mockApply.getId() + "/job-posting";
case QUESTION_SELECT -> "/mock-applies/" + mockApply.getId() + "/questions";
case ANSWER_WRITE -> "/mock-applies/" + mockApply.getId() + "/answers";
case COMPLETED -> "/mock-applies/" + mockApply.getId() + "/analysis";
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.jobdri.jobdri_api.domain.mockapply.dto.response;

import java.util.List;

public record MockApplyHomeResponse(
List<MockApplyHomeItemResponse> inProgress,
List<MockApplyHomeItemResponse> completed
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ public interface MockApplyRepository extends JpaRepository<MockApply, Long> {
List<MockApply> findAllByJobPostingId(Long jobPostingId);
long countByUserIdAndJobPostingId(Long userId, Long jobPostingId);

@Query("""
select ma
from MockApply ma
join fetch ma.jobPosting jp
join fetch jp.company
join fetch jp.detailClassification
left join fetch ma.analysis
where ma.user.id = :userId
order by ma.createdAt desc, ma.id desc
""")
List<MockApply> findHomeItemsByUserId(@Param("userId") Long userId);

@Query("""
select count(ma)
from MockApply ma
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@
import com.jobdri.jobdri_api.domain.mockapply.dto.request.MockApplyCreateMockFromJobPostingRequest;
import com.jobdri.jobdri_api.domain.mockapply.dto.request.MockApplyCreateMockRequest;
import com.jobdri.jobdri_api.domain.mockapply.dto.response.MockApplyCreateResponse;
import com.jobdri.jobdri_api.domain.mockapply.dto.response.MockApplyHomeItemResponse;
import com.jobdri.jobdri_api.domain.mockapply.dto.response.MockApplyHomeResponse;
import com.jobdri.jobdri_api.domain.mockapply.dto.response.MockApplySequenceResponse;
import com.jobdri.jobdri_api.domain.mockapply.entity.ApplyType;
import com.jobdri.jobdri_api.domain.mockapply.entity.MockApply;
import com.jobdri.jobdri_api.domain.mockapply.entity.MockApplyStatus;
import com.jobdri.jobdri_api.domain.mockapply.repository.MockApplyRepository;
import com.jobdri.jobdri_api.domain.user.entity.User;
import com.jobdri.jobdri_api.domain.user.service.UserService;
Expand All @@ -24,6 +27,9 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
Expand Down Expand Up @@ -122,6 +128,27 @@ public MockApplySequenceResponse getMockApplySequence(User user, Long mockApplyI
);
}

public MockApplyHomeResponse getMyMockApplies(User user) {
User validatedUser = userService.validateUser(user);
List<MockApplyHomeItemResponse> items = mockApplyRepository.findHomeItemsByUserId(validatedUser.getId()).stream()
.map(MockApplyHomeItemResponse::from)
.toList();

return new MockApplyHomeResponse(
filterByCompletion(items, false),
filterByCompletion(items, true)
);
}

private List<MockApplyHomeItemResponse> filterByCompletion(
List<MockApplyHomeItemResponse> items,
boolean completed
) {
return items.stream()
.filter(item -> completed == (item.status() == MockApplyStatus.COMPLETED))
.collect(Collectors.toList());
}

private MockApply getOwnedMockApply(User user, Long mockApplyId) {
MockApply mockApply = mockApplyRepository.findById(mockApplyId)
.orElseThrow(() -> new GeneralException(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.jobdri.jobdri_api.domain.mockapply.service;

import com.jobdri.jobdri_api.domain.analysis.entity.Analysis;
import com.jobdri.jobdri_api.domain.analysis.repository.AnalysisRepository;
import com.jobdri.jobdri_api.domain.classification.entity.Classification;
import com.jobdri.jobdri_api.domain.classification.entity.DetailClassification;
import com.jobdri.jobdri_api.domain.classification.entity.MiddleClassification;
Expand All @@ -14,6 +16,7 @@
import com.jobdri.jobdri_api.domain.jobposting.service.MockJobPostingGenerationService;
import com.jobdri.jobdri_api.domain.mockapply.dto.request.MockApplyCreateMockRequest;
import com.jobdri.jobdri_api.domain.mockapply.dto.response.MockApplyCreateResponse;
import com.jobdri.jobdri_api.domain.mockapply.dto.response.MockApplyHomeResponse;
import com.jobdri.jobdri_api.domain.mockapply.dto.response.MockApplySequenceResponse;
import com.jobdri.jobdri_api.domain.mockapply.entity.ApplyType;
import com.jobdri.jobdri_api.domain.mockapply.entity.MockApply;
Expand Down Expand Up @@ -51,6 +54,9 @@ class MockApplyServiceTest {
@Autowired
private MockApplyRepository mockApplyRepository;

@Autowired
private AnalysisRepository analysisRepository;

@Autowired
private JobPostingRepository jobPostingRepository;

Expand Down Expand Up @@ -180,6 +186,42 @@ void getMockApplySequence() {
assertThat(response.sequence()).isEqualTo(2);
}

@Test
@DisplayName("홈 화면에서 이어쓰기와 완료 결과 카드 목록을 조회한다")
void getMyMockApplies() {
User user = saveUser("home-list@example.com");
User otherUser = saveUser("home-list-other@example.com");
JobPosting backendPosting = saveJobPosting(user, "백엔드 개발");
JobPosting dataPosting = saveJobPosting(user, "데이터 분석");
JobPosting otherPosting = saveJobPosting(otherUser, "프론트엔드 개발");

MockApply inProgress = mockApplyRepository.save(MockApply.create(user, backendPosting, ApplyType.ACTUAL));
inProgress.updateStatus(MockApplyStatus.ANSWER_WRITE);
MockApply completed = mockApplyRepository.save(MockApply.create(user, dataPosting, ApplyType.MOCK));
completed.updateStatus(MockApplyStatus.COMPLETED);
mockApplyRepository.save(MockApply.create(otherUser, otherPosting, ApplyType.MOCK));
Analysis analysis = analysisRepository.save(Analysis.create(completed, 71, 72, 73, 74, "완료 분석입니다."));
completed.assignAnalysis(analysis);

MockApplyHomeResponse response = mockApplyService.getMyMockApplies(user);

assertThat(response.inProgress()).hasSize(1);
assertThat(response.completed()).hasSize(1);
assertThat(response.inProgress().get(0).mockApplyId()).isEqualTo(inProgress.getId());
assertThat(response.inProgress().get(0).jobPostingId()).isEqualTo(backendPosting.getId());
assertThat(response.inProgress().get(0).status()).isEqualTo(MockApplyStatus.ANSWER_WRITE);
assertThat(response.inProgress().get(0).companyName()).isEqualTo("테스트 기업");
assertThat(response.inProgress().get(0).detailClassificationName()).isEqualTo("백엔드 개발");
assertThat(response.inProgress().get(0).jobTitle()).isEqualTo("백엔드 개발");
assertThat(response.inProgress().get(0).applyType()).isEqualTo(ApplyType.ACTUAL);
assertThat(response.inProgress().get(0).score()).isNull();
assertThat(response.inProgress().get(0).resumePath()).isEqualTo("/mock-applies/" + inProgress.getId() + "/answers");
assertThat(response.completed().get(0).mockApplyId()).isEqualTo(completed.getId());
assertThat(response.completed().get(0).score()).isEqualTo(71);
assertThat(response.completed().get(0).applyType()).isEqualTo(ApplyType.MOCK);
assertThat(response.completed().get(0).resumePath()).isEqualTo("/mock-applies/" + completed.getId() + "/analysis");
}

@Test
@DisplayName("존재하지 않는 공고 ID로 ACTUAL 타입 지원 생성 시 예외를 던진다")
void createActualApplyThrowsWhenJobPostingNotFound() {
Expand Down
Loading