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

RI-44: [job-board] permet l'ajout d'un job au job-board #196

Merged
merged 5 commits into from
Nov 24, 2021
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 @@ -20,7 +20,7 @@ public JobApplicationDto toDto(JobApplication model) {
.jobTitle(job.getTitle())
.companyName(companyName)
.companyImageUri(companyImageUrl)
.status(model.getStatus())
.statusCode(model.getStatus().name())
.contractType(job.getContractType())
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@ public ResponseEntity<Page<JobPostingDto>> getAllByCriteria(
@RequestParam(value = "sortBy", defaultValue = "id") String sortBy,
@RequestParam(value = "sortOrder", defaultValue = "ASC") String sortOrder,
@RequestParam(value = "search", defaultValue = "") String search,
@RequestParam(value = "contractType", defaultValue = "") String contractType
@RequestParam(value = "contractType", required = false) String contractType,
@RequestParam(value = "checkApply", required = false) String applyCheckAsString
) {
Pageable pageable = PageRequest.of(page, rows, Sort.by(Sort.Direction.valueOf(sortOrder), sortBy));
Page<JobPostingDto> jobPostingDtos = jobPostingService.findAllWithCriteria(pageable, search, contractType);
final boolean applyCheck = Boolean.parseBoolean(applyCheckAsString);
Page<JobPostingDto> jobPostingDtos = jobPostingService.getAllWithCriteria(pageable, search, contractType, applyCheck);
return ResponseEntity.ok(jobPostingDtos);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.dynonuggets.refonteimplicaction.dto;

import com.dynonuggets.refonteimplicaction.model.ApplyStatusEnum;
import com.dynonuggets.refonteimplicaction.model.ContractTypeEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
Expand All @@ -21,7 +20,7 @@ public class JobApplicationDto {

private String companyImageUri;

private ApplyStatusEnum status;
private String statusCode;

private ContractTypeEnum contractType;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@

import com.dynonuggets.refonteimplicaction.model.ApplyStatusEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;

@Data
@Getter
@AllArgsConstructor
public class JobApplicationRequest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ public class JobPostingDto {
private ContractTypeEnum contractType;
private Instant createdAt;
private boolean archive;
private boolean apply;

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package com.dynonuggets.refonteimplicaction.model;

public enum ApplyStatusEnum {
PENDING, SENT, CHASED, INTERVIEW, REFUSED, HIRED
PENDING, SENT, CHASED, INTERVIEW, REJECTED, HIRED
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@
import java.util.List;
import java.util.Optional;

// supprime les warnings sur les noms des méthodes ne respectant pas la convention de nommage (cf named queries)
@SuppressWarnings("squid:S00100")
public interface JobApplicationRepository extends JpaRepository<JobApplication, Long> {
Optional<JobApplication> findByJob(JobPosting job);
Optional<JobApplication> findByJobAndUser_id(JobPosting job, long userId);

List<JobApplication> findAllByUserAndArchiveIsFalse(User user);

List<JobApplication> findAllByJob_IdInAndUser_Id(List<Long> collect, Long userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import com.dynonuggets.refonteimplicaction.repository.JobPostingRepository;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.util.List;
Expand All @@ -28,18 +29,21 @@ public class JobApplicationService {
private final JobApplicationAdapter applyAdapter;
private final AuthService authService;

@Transactional
public JobApplicationDto createApplyIfNotExists(JobApplicationRequest applyRequest) {
final JobPosting job = jobRepository.findById(applyRequest.getJobId())
.orElseThrow(() -> new NotFoundException(String.format(JOB_NOT_FOUND_MESSAGE, applyRequest.getJobId())));

if (applyRepository.findByJob(job).isPresent()) {
final User currentUser = authService.getCurrentUser();

if (applyRepository.findByJobAndUser_id(job, currentUser.getId()).isPresent()) {
throw new IllegalArgumentException(String.format(APPLY_ALREADY_EXISTS_FOR_JOB, job.getId()));
}

final JobApplication apply = JobApplication.builder()
.job(job)
.archive(false)
.user(authService.getCurrentUser())
.user(currentUser)
.status(applyRequest.getStatus())
.lastUpdate(Instant.now())
.build();
Expand All @@ -49,6 +53,7 @@ public JobApplicationDto createApplyIfNotExists(JobApplicationRequest applyReque
return applyAdapter.toDto(applySave);
}

@Transactional(readOnly = true)
public List<JobApplicationDto> getAllAppliesForCurrentUser() {
final User currentUser = authService.getCurrentUser();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import com.dynonuggets.refonteimplicaction.dto.JobPostingDto;
import com.dynonuggets.refonteimplicaction.exception.NotFoundException;
import com.dynonuggets.refonteimplicaction.model.JobPosting;
import com.dynonuggets.refonteimplicaction.repository.JobApplicationRepository;
import com.dynonuggets.refonteimplicaction.repository.JobPostingRepository;
import com.dynonuggets.refonteimplicaction.utils.Message;
import lombok.AllArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
Expand All @@ -16,12 +16,17 @@
import java.util.List;
import java.util.stream.Collectors;

import static com.dynonuggets.refonteimplicaction.utils.Message.JOB_NOT_FOUND_MESSAGE;
import static java.util.stream.Collectors.toList;

@Service
@AllArgsConstructor
public class JobPostingService {

private final JobPostingRepository jobPostingRepository;
private final JobPostingAdapter jobPostingAdapter;
private final JobApplicationRepository jobApplicationRepository;
private final AuthService authService;

public JobPostingDto createJob(JobPostingDto jobPostingDto) {

Expand All @@ -32,14 +37,37 @@ public JobPostingDto createJob(JobPostingDto jobPostingDto) {
}

public JobPostingDto getJobById(Long jobId) {
JobPosting jobPosting = jobPostingRepository.findById(jobId)
.orElseThrow(() -> new NotFoundException(String.format(Message.JOB_NOT_FOUND_MESSAGE, jobId)));
return jobPostingAdapter.toDto(jobPosting);
JobPosting job = jobPostingRepository.findById(jobId)
.orElseThrow(() -> new NotFoundException(String.format(JOB_NOT_FOUND_MESSAGE, jobId)));

final Long currentUserId = authService.getCurrentUser().getId();
final JobPostingDto jobDto = jobPostingAdapter.toDto(job);

jobDto.setApply(jobApplicationRepository.findByJobAndUser_id(job, currentUserId).isPresent());

return jobDto;
}

public Page<JobPostingDto> findAllWithCriteria(Pageable pageable, String search, String contractType) {
return jobPostingRepository.findAllWithCriteria(pageable, search, contractType)
.map(jobPostingAdapter::toDto);
public Page<JobPostingDto> getAllWithCriteria(Pageable pageable, String search, String contractType, boolean applyCheck) {
// récupération des jobs
final Page<JobPosting> jobs = jobPostingRepository.findAllWithCriteria(pageable, search, contractType);
if (applyCheck) {
final List<Long> jobIds = jobs.stream().map(JobPosting::getId).collect(toList());
final List<Long> jobAppliesIds = getAllAppliesWithJobIdsIn(jobIds, authService.getCurrentUser().getId());
return jobs.map(job -> {
final JobPostingDto jobDto = jobPostingAdapter.toDto(job);
jobDto.setApply(jobAppliesIds.contains(jobDto.getId()));
return jobDto;
});
}
return jobs.map(jobPostingAdapter::toDto);
}

private List<Long> getAllAppliesWithJobIdsIn(List<Long> jobIds, Long userId) {
return jobApplicationRepository.findAllByJob_IdInAndUser_Id(jobIds, userId)
.stream()
.map(apply -> apply.getJob().getId())
.collect(toList());
}

@Transactional
Expand All @@ -52,14 +80,14 @@ public JobPostingDto saveOrUpdateJobPosting(final JobPostingDto jobPostingDto) {
@Transactional
public void deleteJobPosting(Long jobPostingId) {
JobPosting jobPosting = jobPostingRepository.findById(jobPostingId)
.orElseThrow(() -> new NotFoundException("Impossible de supprimer l'offre, " + jobPostingId + " n'existe pas."));
.orElseThrow(() -> new NotFoundException(String.format(JOB_NOT_FOUND_MESSAGE, jobPostingId)));
jobPostingRepository.delete(jobPosting);
}

@Transactional
public JobPostingDto toggleArchiveJobPosting(Long jobPostingId) {
JobPosting jobPosting = jobPostingRepository.findById(jobPostingId)
.orElseThrow(() -> new NotFoundException(String.format(Message.JOB_NOT_FOUND_MESSAGE, jobPostingId)));
.orElseThrow(() -> new NotFoundException(String.format(JOB_NOT_FOUND_MESSAGE, jobPostingId)));
jobPosting.setArchive(!jobPosting.isArchive());
final JobPosting save = jobPostingRepository.save(jobPosting);
return jobPostingAdapter.toDto(save);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ void given_company_should_return_dto() {
assertThat(actual.getCompanyName()).isEqualTo(model.getJob().getCompany().getName());
assertThat(actual.getJobId()).isEqualTo(model.getJob().getId());
assertThat(actual.getJobTitle()).isEqualTo(model.getJob().getTitle());
assertThat(actual.getStatus()).isEqualTo(model.getStatus());
assertThat(actual.getStatusCode()).isEqualTo(model.getStatus().name());
assertThat(actual.getContractType()).isEqualTo(model.getJob().getContractType());
}

Expand All @@ -56,7 +56,7 @@ void given_no_company_should_return_dto() {
assertThat(actual.getCompanyName()).isNull();
assertThat(actual.getJobId()).isEqualTo(model.getJob().getId());
assertThat(actual.getJobTitle()).isEqualTo(model.getJob().getTitle());
assertThat(actual.getStatus()).isEqualTo(model.getStatus());
assertThat(actual.getStatusCode()).isEqualTo(model.getStatus().name());
assertThat(actual.getContractType()).isEqualTo(model.getJob().getContractType());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class JobApplicationControllerTest extends ControllerIntegrationTestBase {
void should_create_apply() throws Exception {
// given
JobApplicationRequest request = new JobApplicationRequest(123L, PENDING);
JobApplicationDto response = new JobApplicationDto(243L, 123L, "Mon super Job", "Google", "http://uri.com", PENDING, CDI);
JobApplicationDto response = new JobApplicationDto(243L, 123L, "Mon super Job", "Google", "http://uri.com", PENDING.name(), CDI);
given(applicationService.createApplyIfNotExists(any())).willReturn(response);
String json = gson.toJson(request);

Expand All @@ -57,7 +57,7 @@ void should_create_apply() throws Exception {
.andExpect(jsonPath("$.jobTitle", is(response.getJobTitle())))
.andExpect(jsonPath("$.companyName", is(response.getCompanyName())))
.andExpect(jsonPath("$.companyImageUri", is(response.getCompanyImageUri())))
.andExpect(jsonPath("$.status", is(response.getStatus().name())));
.andExpect(jsonPath("$.statusCode", is(response.getStatusCode())));

verify(applicationService, times(1)).createApplyIfNotExists(any());
}
Expand Down Expand Up @@ -128,9 +128,9 @@ void should_return_forbidden_when_creating_apply_and_no_auth() throws Exception
void should_list_all_users_application() throws Exception {
// given
List<JobApplicationDto> expecteds = asList(
new JobApplicationDto(1L, 12L, "super job", "google", "http://url.com", PENDING, CDD),
new JobApplicationDto(2L, 13L, "super job 2", "microsof", "http://url2.com", CHASED, CDD),
new JobApplicationDto(3L, 14L, "super job 3", "amazon", "http://url3.com", INTERVIEW, INTERIM)
new JobApplicationDto(1L, 12L, "super job", "google", "http://url.com", PENDING.name(), CDD),
new JobApplicationDto(2L, 13L, "super job 2", "microsof", "http://url2.com", CHASED.name(), CDD),
new JobApplicationDto(3L, 14L, "super job 3", "amazon", "http://url3.com", INTERVIEW.name(), INTERIM)
);
int expectedSize = expecteds.size();
given(applicationService.getAllAppliesForCurrentUser()).willReturn(expecteds);
Expand All @@ -149,7 +149,7 @@ void should_list_all_users_application() throws Exception {
.andExpect(jsonPath(contentPath + "jobId", is(expecteds.get(i).getJobId().intValue())))
.andExpect(jsonPath(contentPath + "companyName", is(expecteds.get(i).getCompanyName())))
.andExpect(jsonPath(contentPath + "companyImageUri", is(expecteds.get(i).getCompanyImageUri())))
.andExpect(jsonPath(contentPath + "status", is(expecteds.get(i).getStatus().name())))
.andExpect(jsonPath(contentPath + "statusCode", is(expecteds.get(i).getStatusCode())))
.andExpect(jsonPath(contentPath + "contractType", is(expecteds.get(i).getContractType().name())));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.util.Collections;
import java.util.List;

import static com.dynonuggets.refonteimplicaction.model.ContractTypeEnum.CDD;
import static com.dynonuggets.refonteimplicaction.utils.ApiUrls.*;
import static com.dynonuggets.refonteimplicaction.utils.Message.JOB_NOT_FOUND_MESSAGE;
import static org.hamcrest.Matchers.is;
Expand All @@ -40,45 +41,48 @@ class JobsPostingControllerTest extends ControllerIntegrationTestBase {
@BeforeEach
void setUp() {
jobPostings = Arrays.asList(
JobPostingDto.builder().id(1L).createdAt(Instant.now()).description("description").location("Paris").keywords("toto,yoyo").salary("1111$").build(),
JobPostingDto.builder().id(2L).createdAt(Instant.now()).description("description2").location("New York").keywords("toto2,yoyo2").salary("2222$").build());
JobPostingDto.builder().id(1L).createdAt(Instant.now()).description("description").location("Paris").keywords("toto,yoyo").contractType(CDD).salary("1111$").build(),
JobPostingDto.builder().id(2L).createdAt(Instant.now()).description("description2").location("New York").keywords("toto2,yoyo2").contractType(CDD).salary("2222$").build());
}

@WithMockUser
@Test
@WithMockUser
void getJobPostingsListShouldListAllJobs() throws Exception {
// given
String search = "";
String contractType = "";
Page<JobPostingDto> jobPostingPageMockResponse = new PageImpl<>(jobPostings);

given(jobPostingService.findAllWithCriteria(DEFAULT_PAGEABLE, search, contractType)).willReturn(jobPostingPageMockResponse);
given(jobPostingService.getAllWithCriteria(any(), anyString(), anyString(), anyBoolean())).willReturn(jobPostingPageMockResponse);

ResultActions actions = mvc.perform(get(JOBS_BASE_URI).contentType(APPLICATION_JSON))
.andDo(print())
.andExpect(status().isOk())
// when
ResultActions resultActions = mvc.perform(
get(JOBS_BASE_URI).param("contractType", CDD.name())

).andDo(print());

// then
resultActions.andExpect(status().isOk())
.andExpect(jsonPath("$.totalPages").value(jobPostingPageMockResponse.getTotalPages()))
.andExpect(jsonPath("$.totalElements").value(jobPostings.size()));

for (int i = 0; i < jobPostings.size(); i++) {
final String contentPath = String.format("$.content[%d]", i);
actions.andExpect(jsonPath(contentPath + ".id", is(jobPostings.get(i).getId().intValue())))
resultActions.andExpect(jsonPath(contentPath + ".id", is(jobPostings.get(i).getId().intValue())))
.andExpect(jsonPath(contentPath + ".createdAt", is(jobPostings.get(i).getCreatedAt().toString())))
.andExpect(jsonPath(contentPath + ".description", is(jobPostings.get(i).getDescription())))
.andExpect(jsonPath(contentPath + ".location", is(jobPostings.get(i).getLocation())))
.andExpect(jsonPath(contentPath + ".keywords", is(jobPostings.get(i).getKeywords())))
.andExpect(jsonPath(contentPath + ".salary", is(jobPostings.get(i).getSalary())));
}

verify(jobPostingService, times(1)).findAllWithCriteria(any(), anyString(), anyString());
verify(jobPostingService, times(1)).getAllWithCriteria(any(), anyString(), anyString(), anyBoolean());
}

@Test
void getAllWithoutJwtShouldBeForbidden() throws Exception {
mvc.perform(get(JOBS_BASE_URI)).andDo(print())
.andExpect(status().isForbidden());

verify(jobPostingService, times(0)).findAllWithCriteria(any(), anyString(), anyString());
verify(jobPostingService, times(0)).getAllWithCriteria(any(), anyString(), anyString(), anyBoolean());
}

@Test
Expand Down
Loading