Skip to content
This repository has been archived by the owner on Jan 2, 2024. It is now read-only.

Commit

Permalink
Confirm Mentor feature for Approved Mentees (#92)
Browse files Browse the repository at this point in the history
  • Loading branch information
Piumal1999 authored Dec 19, 2020
1 parent 917e550 commit 2e59272
Show file tree
Hide file tree
Showing 11 changed files with 188 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.sefglobal.scholarx.controller;

import org.sefglobal.scholarx.exception.BadRequestException;
import org.sefglobal.scholarx.exception.NoContentException;
import org.sefglobal.scholarx.exception.ResourceNotFoundException;
import org.sefglobal.scholarx.exception.UnauthorizedException;
Expand All @@ -12,6 +13,7 @@
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
Expand Down Expand Up @@ -59,4 +61,12 @@ public List<Mentee> getMentees(@CookieValue long profileId,
throws ResourceNotFoundException, NoContentException {
return introspectionService.getMentees(id, profileId, menteeStates);
}

@PutMapping("/mentor/{id}/confirmation")
@ResponseStatus(HttpStatus.OK)
public Mentee confirmMentor(@PathVariable long id,
@CookieValue(value = "profileId") long profileId)
throws ResourceNotFoundException, BadRequestException {
return introspectionService.confirmMentor(id, profileId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.sefglobal.scholarx.model.Mentor;
import org.sefglobal.scholarx.model.Program;
import org.sefglobal.scholarx.service.ProgramService;
import org.sefglobal.scholarx.util.EnrolmentState;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.GetMapping;
Expand All @@ -14,6 +15,7 @@
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

Expand Down Expand Up @@ -77,9 +79,10 @@ public Mentor updateMentorData(@PathVariable long id,
@GetMapping("/{id}/mentee/mentors")
@ResponseStatus(HttpStatus.OK)
public List<Mentor> getAppliedMentors(@PathVariable long id,
@RequestParam(required = false) List<EnrolmentState> menteeStates,
@CookieValue(value = "profileId") long profileId)
throws NoContentException {
return programService.getAppliedMentorsOfMentee(id, profileId);
return programService.getAppliedMentorsOfMentee(id, menteeStates, profileId);
}

@GetMapping("/{id}/mentee/mentor")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public interface MenteeRepository extends JpaRepository<Mentee, Long> {

List<Mentee> findAllByProgramIdAndProfileId(long programId, long profileId);

List<Mentee> findAllByProgramIdAndProfileIdAndStateIn(long programId, long profileId, List<EnrolmentState> states);

Optional<Mentee> findByProfileIdAndMentorId(long profileId, long mentorId);

List<Mentee> findAllByProfileId(long profileId);
Expand All @@ -36,4 +38,16 @@ public interface MenteeRepository extends JpaRepository<Mentee, Long> {
nativeQuery = true
)
void deleteByMentorProgramId(long id);

@Modifying
@Query(
value = "UPDATE " +
"mentee " +
"SET state = 'REMOVED' " +
"WHERE profile_id = :profileId " +
"AND program_id = :programId " +
"AND mentor_id != :mentorId",
nativeQuery = true
)
void removeAllByProgramIdAndProfileIdAndMentorIdNot(long programId, long profileId, long mentorId);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.sefglobal.scholarx.service;

import org.sefglobal.scholarx.exception.BadRequestException;
import org.sefglobal.scholarx.exception.NoContentException;
import org.sefglobal.scholarx.exception.ResourceNotFoundException;
import org.sefglobal.scholarx.exception.UnauthorizedException;
Expand Down Expand Up @@ -166,4 +167,43 @@ public List<Mentee> getMentees(long programId, long profileId,
}
return mentees;
}

/**
* Confirm a {@link Mentor} for a specific {@link Mentee}
*
* @param mentorId which is the id of the confirmed {@link Mentor}
* @param profileId which is the id of the {@link Profile}
* @return the updated {@link Mentee}
*
* @throws ResourceNotFoundException is thrown if the {@link Mentor} doesn't exist
* @throws BadRequestException is thrown if the {@link Mentee} is not approved
*/
public Mentee confirmMentor(long mentorId, long profileId)
throws ResourceNotFoundException, BadRequestException {
Optional<Mentor> optionalMentor = mentorRepository.findById(mentorId);
if (!optionalMentor.isPresent()) {
String msg = "Error, Mentor by id: " + mentorId + " doesn't exist.";
log.error(msg);
throw new ResourceNotFoundException(msg);
}

Optional<Mentee> optionalMentee = menteeRepository.findByProfileIdAndMentorId(profileId, mentorId);
if (!optionalMentee.isPresent()) {
String msg = "Error, User with id: " + profileId + " haven't applied for " +
"mentor by id: " + mentorId + ".";
log.error(msg);
throw new BadRequestException(msg);
}

if (!optionalMentee.get().getState().equals(EnrolmentState.APPROVED)) {
String msg = "Error, User with id: " + profileId + " is not approved " +
"by the mentor by id: " + mentorId + ".";
log.error(msg);
throw new BadRequestException(msg);
}

long programId = optionalMentor.get().getProgram().getId();
menteeRepository.removeAllByProgramIdAndProfileIdAndMentorIdNot(programId, profileId, mentorId);
return optionalMentee.get();
}
}
16 changes: 11 additions & 5 deletions src/main/java/org/sefglobal/scholarx/service/ProgramService.java
Original file line number Diff line number Diff line change
Expand Up @@ -280,16 +280,22 @@ public Mentor updateMentorData(long profileId, long programId, Mentor mentor)
/**
* Retrieves the applied {@link Mentor} objects of the {@link Mentee}
*
* @param programId which is the id of the {@link Program}
* @param profileId which is the profile id of the {@link Mentee}
* @param programId which is the id of the {@link Program}
* @param profileId which is the profile id of the {@link Mentee}
* @param menteeStates which is the list of states that {@link Mentee} objects should be
* filtered from
* @return {@link List} of {@link Mentor} objects
*
* @throws NoContentException if the user hasn't applied for {@link Mentor} objects
*/
public List<Mentor> getAppliedMentorsOfMentee(long programId, long profileId)
public List<Mentor> getAppliedMentorsOfMentee(long programId, List<EnrolmentState> menteeStates, long profileId)
throws NoContentException {
List<Mentee> menteeList = menteeRepository
.findAllByProgramIdAndProfileId(programId, profileId);
List<Mentee> menteeList;
if (menteeStates == null || menteeStates.isEmpty()) {
menteeList = menteeRepository.findAllByProgramIdAndProfileId(programId, profileId);
} else {
menteeList = menteeRepository.findAllByProgramIdAndProfileIdAndStateIn(programId, profileId, menteeStates);
}
if (menteeList.isEmpty()) {
String msg = "Error, Mentee by program id: " + programId + " and " +
"profile id: " + profileId + " doesn't exist.";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public enum ProgramState {
MENTOR_SELECTION,
MENTEE_APPLICATION,
MENTEE_SELECTION,
MENTOR_CONFIRMATION,
ONGOING,
COMPLETED,
REMOVED;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.sefglobal.scholarx.controller;

import org.junit.jupiter.api.Test;
import org.sefglobal.scholarx.exception.BadRequestException;
import org.sefglobal.scholarx.exception.NoContentException;
import org.sefglobal.scholarx.exception.ResourceNotFoundException;
import org.sefglobal.scholarx.exception.UnauthorizedException;
Expand All @@ -16,6 +17,7 @@
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.doThrow;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebMvcTest(controllers = IntrospectionController.class)
Expand All @@ -25,6 +27,7 @@ public class IntrospectionControllerTest {
@MockBean
private IntrospectionService introspectionService;
private final Long programId = 1L;
private final Long mentorId = 1L;
private final Cookie profileIdCookie = new Cookie("profileId", "1");

@Test
Expand Down Expand Up @@ -142,4 +145,33 @@ void getMentees_withUnavailableData_thenReturns204() throws Exception {
.cookie(profileIdCookie))
.andExpect(status().isNoContent());
}

@Test
void confirmMentor_withValidData_thenReturns200() throws Exception {
mockMvc.perform(put("/me/mentor/{mentorId}/confirmation", mentorId)
.cookie(profileIdCookie))
.andExpect(status().isOk());
}

@Test
void confirmMentor_withUnavailableData_thenReturn404() throws Exception {
doThrow(ResourceNotFoundException.class)
.when(introspectionService)
.confirmMentor(anyLong(), anyLong());

mockMvc.perform(put("/me/mentor/{mentorId}/confirmation", mentorId)
.cookie(profileIdCookie))
.andExpect(status().isNotFound());
}

@Test
void confirmMentor_withUnsuitableData_thenReturn400() throws Exception {
doThrow(BadRequestException.class)
.when(introspectionService)
.confirmMentor(anyLong(), anyLong());

mockMvc.perform(put("/me/mentor/{mentorId}/confirmation", mentorId)
.cookie(profileIdCookie))
.andExpect(status().isBadRequest());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import org.springframework.test.web.servlet.MockMvc;

import javax.servlet.http.Cookie;

import java.util.HashMap;
import java.util.Map;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ void getAppliedMentors_withValidData_thenReturns200() throws Exception {
void getAppliedMentors_withUnavailableData_thenReturns204() throws Exception {
doThrow(NoContentException.class)
.when(programService)
.getAppliedMentorsOfMentee(anyLong(), anyLong());
.getAppliedMentorsOfMentee(anyLong(), any(), anyLong());

mockMvc.perform(get("/programs/{id}/mentee/mentors", programId)
.cookie(profileIdCookie))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,25 @@
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.sefglobal.scholarx.exception.BadRequestException;
import org.sefglobal.scholarx.exception.NoContentException;
import org.sefglobal.scholarx.exception.ResourceNotFoundException;
import org.sefglobal.scholarx.exception.UnauthorizedException;
import org.sefglobal.scholarx.model.Mentee;
import org.sefglobal.scholarx.model.Mentor;
import org.sefglobal.scholarx.model.Program;
import org.sefglobal.scholarx.repository.MenteeRepository;
import org.sefglobal.scholarx.repository.MentorRepository;
import org.sefglobal.scholarx.repository.ProfileRepository;
import org.sefglobal.scholarx.util.EnrolmentState;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.doReturn;

Expand All @@ -34,6 +39,10 @@ public class IntrospectionServiceTest {
private IntrospectionService introspectionService;
private final Long programId = 1L;
private final long profileId = 1L;
private final long mentorId = 1L;
private final Mentor mentor = new Mentor();
private final Mentee mentee =
new Mentee("http://submission.url/");

@Test
void getLoggedInUser_withUnavailableData_thenThrowResourceNotFound() {
Expand Down Expand Up @@ -143,4 +152,69 @@ void getMentees_withUnavailableData_thenThrowNoContent() {
.isInstanceOf(NoContentException.class)
.hasMessage("No mentees exist for the required program: 1 for the profile: 1");
}

@Test
void confirmMentor_withValidData_thenReturnUpdatedData()
throws ResourceNotFoundException, BadRequestException {
mentee.setState(EnrolmentState.APPROVED);
Program program = new Program();
program.setId(programId);
mentor.setProgram(program);
doReturn(Optional.of(mentor))
.when(mentorRepository)
.findById(anyLong());
doReturn(Optional.of(mentee))
.when(menteeRepository)
.findByProfileIdAndMentorId(anyLong(), anyLong());

Mentee savedMentee = introspectionService.confirmMentor(mentorId, profileId);
assertThat(savedMentee).isNotNull();
assertThat(savedMentee.getState()).isEqualTo(EnrolmentState.APPROVED);
}

@Test
void confirmMentor_withUnavailableData_thenThrowResourceNotFound() {
doReturn(Optional.empty())
.when(mentorRepository)
.findById(anyLong());

Throwable thrown = catchThrowable(
() -> introspectionService.confirmMentor(mentorId, profileId));
assertThat(thrown)
.isInstanceOf(ResourceNotFoundException.class)
.hasMessage("Error, Mentor by id: 1 doesn't exist.");
}

@Test
void confirmMentor_withUnavailableData_thenThrowBadRequest() {
doReturn(Optional.of(mentor))
.when(mentorRepository)
.findById(anyLong());
doReturn(Optional.empty())
.when(menteeRepository)
.findByProfileIdAndMentorId(anyLong(), anyLong());

Throwable thrown = catchThrowable(
() -> introspectionService.confirmMentor(mentorId, profileId));
assertThat(thrown)
.isInstanceOf(BadRequestException.class)
.hasMessage("Error, User with id: 1 haven't applied for mentor by id: 1.");
}

@Test
void confirmMentor_withUnsuitableData_thenThrowBadRequest() {
mentee.setState(EnrolmentState.PENDING);
doReturn(Optional.of(mentor))
.when(mentorRepository)
.findById(anyLong());
doReturn(Optional.of(mentee))
.when(menteeRepository)
.findByProfileIdAndMentorId(anyLong(), anyLong());

Throwable thrown = catchThrowable(
() -> introspectionService.confirmMentor(mentorId, profileId));
assertThat(thrown)
.isInstanceOf(BadRequestException.class)
.hasMessage("Error, User with id: 1 is not approved by the mentor by id: 1.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import org.sefglobal.scholarx.util.ProgramState;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

Expand Down Expand Up @@ -291,7 +290,7 @@ void getAppliedMentorsOfMentee_withUnavailableData_thenThrowNoContent() {
.findAllByProgramIdAndProfileId(anyLong(), anyLong());

Throwable thrown = catchThrowable(
() -> programService.getAppliedMentorsOfMentee(programId, profileId));
() -> programService.getAppliedMentorsOfMentee(programId, new ArrayList<>(), profileId));
assertThat(thrown)
.isInstanceOf(NoContentException.class)
.hasMessage("Error, Mentee by program id: 1 and " +
Expand Down

0 comments on commit 2e59272

Please sign in to comment.