diff --git a/.github/workflows/deploy_frontend.yml b/.github/workflows/deploy_frontend.yml new file mode 100644 index 00000000..e090378e --- /dev/null +++ b/.github/workflows/deploy_frontend.yml @@ -0,0 +1,42 @@ +name: Frontend Deployment +on: + workflow_dispatch +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout backend + uses: actions/checkout@v2 + with: + ref: deployment + path: backend + - name: Checkout frontend + uses: actions/checkout@v2 + with: + repository: sef-global/scholarx-frontend + ref: master + path: frontend + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + - name: Install dependencies and Build Frontend + run: | + cd frontend + npm ci + npm run build + - name: Copy static files + run: | + cp frontend/dist/bundle.js backend/src/main/resources/static/ + cp frontend/dist/index.html backend/src/main/resources/static/ + - name: Create Pull Request + uses: peter-evans/create-pull-request@v3.12.1 + with: + path: backend + commit-message: '[Bot] Deploy the latest frontend' + title: '[Bot] Deploy the latest frontend' + body: | + Update report + - Auto-generated by [create-pull-request][1] + - Please add the new features/bug fixes list before merging + [1]: https://github.com/peter-evans/create-pull-request diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 00000000..344d4eb4 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,28 @@ +# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven + +name: Java CI with Maven + +on: + push: + branches: [ development ] + pull_request: + branches: [ development ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 1.8 + uses: actions/setup-java@v2 + with: + java-version: '8' + distribution: 'adopt' + cache: maven + - name: Configure build + run: cp src/main/resources/application.yml.example src/main/resources/application.yml + - name: Build and Run Tests with Maven + run: mvn clean install diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 62be52cd..00000000 --- a/.travis.yml +++ /dev/null @@ -1,23 +0,0 @@ -language: java -install: - - git clone https://github.com/sef-global/scholarx-frontend - - cd scholarx-frontend - - git checkout master - - npm install - - npm run build - - cd ../ -before_script: - - mkdir -p src/main/resources/static - - cp -r scholarx-frontend/dist/. src/main/resources/static/ - - sudo rm -R scholarx-frontend - - cp src/main/resources/application.yml.example src/main/resources/application.yml -script: - - mvn clean install -deploy: - provider: heroku - api_key: $HEROKU_API_KEY - app: sef-scholarx - on: - repo: sef-global/scholarx - branch: master - skip_cleanup: true diff --git a/README.md b/README.md index a476a261..f76a59fd 100644 --- a/README.md +++ b/README.md @@ -2,40 +2,88 @@ Backend of the ScholarX project -### Setting up the project for development +## Setting up the project for development -**Prerequisites** +### Prerequisites * Java * Maven -* MySQL +* PostgreSQL * Linkedin Social Login App * Gmail Account with an App Password -**Setup Linkedin Social Login App** +### Setup Linkedin Social Login App 1. Create a new Linkedin App ([help?](https://docs.ultimatemember.com/article/142-social-login-linkedin-app-setup)) 2. Click on `Auth` tab and add `http://localhost:8080/login/oauth2/code/linkedin` as an authorised redirect URL 3. Make Sure you have properly added the `Sign in with Linkedin product` under products tab -**Setup a gmail account with an app password** +### Setup a gmail account with an app password 1. Create a new gmail account if you don't have one already 2. Enable Two Factor Authorisation -3. Generate a new `App Password` ([help?](https://support.google.com/mail/answer/185833?hl=en-GB)) +3. Generate a new `App Password` ([help?](https://support.google.com/mail/answer/185833?hl=en-GB)) -**Steps** +### Run Locally 1. Fork and clone the repository -``` +```shell git clone https://github.com//scholarx ``` 2. Open the cloned repo, Find and open the `application.yml` file -3. Replace the `client-id` and `client-secret` with the values from the above linkedin social app -image -4. Replace the mail username and password values with the generated `App Password` and the corresponding gmail address -image -5. Replace the datasource dummy values with your local mysql server instance credentials -image -6. Run the application +3. Replace the `${client-id}` and `${client-secret}` with the values from the above linkedin social app +example: +```yaml + linkedin: + client-id: 324780jdsfg2u4 + client-secret: MsdfsdfggsqPFh + client-authentication-method: post + authorization-grant-type: authorization_code +``` + +4. Replace the mail `username` and `password` values with the generated `App Password` and the corresponding gmail address +example: +```yaml + mail: + host: smtp.gmail.com + port: 587 + username: samplemail@gmail.com + password: jhdfklsdjjadskt + properties: +``` +5. Replace the datasource dummy values with your local mysql server instance credentials +example: +```yaml + datasource: + url: jdbc:postgresql://localhost:5432/scholarx_DB?allowPublicKeyRetrieval=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8 + username: rootuser + password: rootpassword + platform: postgres ``` + +6. Run the application +```shell mvn spring-boot:run ``` + +### Configuring a MySQL Database (Optional) + +1. Add the `mysql-connector-java` dependency to the `pom.xml` file. +```xml + + mysql + mysql-connector-java + runtime + +``` + +2. Replace the `spring.jpa` and `spring.datasource` configurations in `application.yml` with the following configuration. +```yaml + jpa: + database: postgresql + hibernate: + ddl-auto: update + datasource: + url: jdbc:postgresql://${DB_URL}/${DB_NAME}?allowPublicKeyRetrieval=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8 + username: ${DB_USER_NAME} + password: ${DB_USER_PASSWORD} + platform: postgres +``` diff --git a/pom.xml b/pom.xml index 3bdd5078..f0061dbf 100644 --- a/pom.xml +++ b/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 @@ -19,58 +19,57 @@ spring-boot-starter-webflux - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-actuator - - - org.springframework.boot - spring-boot-starter-validation - - - org.springframework.boot - spring-boot-starter-security - - - org.springframework.boot - spring-boot-starter-data-jpa - - - org.springframework.boot - spring-boot-starter-mail - 2.3.10.RELEASE - - - org.springframework.boot - spring-boot-starter-tomcat - provided - - - org.springframework.boot - spring-boot-configuration-processor - true - - - org.thymeleaf - thymeleaf-spring5 - - - nz.net.ultraq.thymeleaf - thymeleaf-layout-dialect - - - mysql - mysql-connector-java - runtime - - - javax.servlet - servlet-api - 2.5 - provided + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-mail + 2.3.10.RELEASE + + + org.springframework.boot + spring-boot-starter-tomcat + provided + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.thymeleaf + thymeleaf-spring5 + + + nz.net.ultraq.thymeleaf + thymeleaf-layout-dialect + + + org.postgresql + postgresql + + + javax.servlet + servlet-api + 2.5 + provided org.springframework.boot @@ -90,7 +89,12 @@ org.springframework.security spring-security-core - 5.3.10.RELEASE + 5.5.7 + + + org.springframework.security + spring-security-test + 5.3.3.RELEASE @@ -99,45 +103,45 @@ 4.5.13 - org.springframework.boot - spring-boot-starter-test - test - - - org.junit.vintage - junit-vintage-engine - - - com.vaadin.external.google - android-json - - - - - io.springfox - springfox-swagger2 - ${swagger.version} - - - io.springfox - springfox-swagger-ui - ${swagger.version} - - - io.springfox - springfox-bean-validators - ${swagger.version} - - - commons-lang - commons-lang - 2.6 - - - org.projectlombok - lombok - true - + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + com.vaadin.external.google + android-json + + + + + io.springfox + springfox-swagger2 + ${swagger.version} + + + io.springfox + springfox-swagger-ui + ${swagger.version} + + + io.springfox + springfox-bean-validators + ${swagger.version} + + + commons-lang + commons-lang + 2.6 + + + org.projectlombok + lombok + true + @@ -158,6 +162,6 @@ - 2.9.2 - + 2.9.2 + diff --git a/pull_request_template.md b/pull_request_template.md index 2ec6c588..d392da9f 100644 --- a/pull_request_template.md +++ b/pull_request_template.md @@ -10,11 +10,6 @@ The purpose of this PR is to fix # ### Screenshots - -### Preview Link - - -https://pr-{PR_NUMBER}-sef-site.surge.sh/ ## Checklist - [x] This PR doesn't commit any keys, passwords, tokens, usernames, or other secrets. diff --git a/src/main/java/org/sefglobal/scholarx/config/SecurityConfig.java b/src/main/java/org/sefglobal/scholarx/config/SecurityConfig.java index eac48093..ca3b84bf 100644 --- a/src/main/java/org/sefglobal/scholarx/config/SecurityConfig.java +++ b/src/main/java/org/sefglobal/scholarx/config/SecurityConfig.java @@ -56,6 +56,8 @@ protected void configure(HttpSecurity http) throws Exception { .permitAll() .antMatchers("/api/programs/*/mentors") .permitAll() + .antMatchers("/api/mentors/*") + .permitAll() .antMatchers("/api/**") .authenticated() .anyRequest() diff --git a/src/main/java/org/sefglobal/scholarx/controller/AuthUserController.java b/src/main/java/org/sefglobal/scholarx/controller/AuthUserController.java index 11bf982e..7e52c9e2 100644 --- a/src/main/java/org/sefglobal/scholarx/controller/AuthUserController.java +++ b/src/main/java/org/sefglobal/scholarx/controller/AuthUserController.java @@ -65,15 +65,4 @@ public List getMentees( Profile profile = (Profile) authentication.getPrincipal(); return introspectionService.getMentees(id, profile.getId(), menteeStates); } - - @PutMapping("/mentor/{id}/confirmation") - @ResponseStatus(HttpStatus.OK) - public Mentee confirmMentor( - @PathVariable long id, - Authentication authentication - ) - throws ResourceNotFoundException, BadRequestException { - Profile profile = (Profile) authentication.getPrincipal(); - return introspectionService.confirmMentor(id, profile.getId()); - } } diff --git a/src/main/java/org/sefglobal/scholarx/controller/MenteeController.java b/src/main/java/org/sefglobal/scholarx/controller/MenteeController.java index 9d8fe734..1d8efa6f 100644 --- a/src/main/java/org/sefglobal/scholarx/controller/MenteeController.java +++ b/src/main/java/org/sefglobal/scholarx/controller/MenteeController.java @@ -1,14 +1,23 @@ package org.sefglobal.scholarx.controller; +import java.util.List; import java.util.Map; import javax.validation.Valid; import org.sefglobal.scholarx.exception.BadRequestException; import org.sefglobal.scholarx.exception.ResourceNotFoundException; +import org.sefglobal.scholarx.exception.UnauthorizedException; +import org.sefglobal.scholarx.model.Comment; import org.sefglobal.scholarx.model.Mentee; +import org.sefglobal.scholarx.model.Profile; +import org.sefglobal.scholarx.service.CommentService; import org.sefglobal.scholarx.service.MenteeService; import org.springframework.http.HttpStatus; +import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseStatus; @@ -19,20 +28,64 @@ public class MenteeController { private final MenteeService menteeService; + private final CommentService commentService; - public MenteeController(MenteeService menteeService) { + public MenteeController(MenteeService menteeService,CommentService commentService) { this.menteeService = menteeService; + this.commentService = commentService; + } + + @PostMapping("/{id}/comments") + @ResponseStatus(HttpStatus.CREATED) + public Comment addComment( + Authentication authentication, + @Valid @RequestBody Comment comment, + @PathVariable long id) + throws ResourceNotFoundException, UnauthorizedException { + Profile profile = (Profile) authentication.getPrincipal(); + return commentService.addMenteeComment(id,profile.getId(), comment); + } + + @GetMapping("/{id}/comments") + @ResponseStatus(HttpStatus.OK) + public List getMenteesComments( + Authentication authentication, + @PathVariable long id + ) + throws ResourceNotFoundException, BadRequestException, UnauthorizedException { + Profile profile = (Profile) authentication.getPrincipal(); + return commentService.getAllMenteeComments(id,profile.getId()); + } + + @PutMapping("/comment/{id}") + @ResponseStatus(HttpStatus.OK) + public Comment updateComment(@PathVariable long id, + Authentication authentication, + @Valid @RequestBody Comment comment) + throws ResourceNotFoundException, BadRequestException, UnauthorizedException { + Profile profile = (Profile) authentication.getPrincipal(); + return commentService.updateComment(id, profile.getId(), comment); + } + + @DeleteMapping("/comment/{id}") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void deleteMenteeComment(@PathVariable long id,Authentication authentication) + throws ResourceNotFoundException, UnauthorizedException { + Profile profile = (Profile) authentication.getPrincipal(); + commentService.deleteComment(id, profile.getId()); } @PutMapping("/{id}/state") @ResponseStatus(HttpStatus.OK) public Mentee approveOrRejectMentee(@PathVariable long id, + Authentication authentication, @Valid @RequestBody Map payload) - throws ResourceNotFoundException, BadRequestException { + throws ResourceNotFoundException, BadRequestException, UnauthorizedException { + Profile profile = (Profile) authentication.getPrincipal(); if (!payload.containsKey("isApproved")) { String msg = "Error, Value cannot be null."; throw new BadRequestException(msg); } - return menteeService.approveOrRejectMentee(id, payload.get("isApproved")); + return menteeService.approveOrRejectMentee(id, profile.getId(), payload.get("isApproved")); } } diff --git a/src/main/java/org/sefglobal/scholarx/controller/MentorController.java b/src/main/java/org/sefglobal/scholarx/controller/MentorController.java index 17183ec8..d0f13312 100644 --- a/src/main/java/org/sefglobal/scholarx/controller/MentorController.java +++ b/src/main/java/org/sefglobal/scholarx/controller/MentorController.java @@ -67,27 +67,4 @@ public List getMenteesOfMentor( throws ResourceNotFoundException, BadRequestException { return mentorService.getAllMenteesOfMentor(id, state); } - - @PutMapping("/{id}/mentee") - @ResponseStatus(HttpStatus.OK) - public Mentee updateMenteeData( - @PathVariable long id, - Authentication authentication, - @Valid @RequestBody Mentee mentee - ) - throws ResourceNotFoundException, BadRequestException { - Profile profile = (Profile) authentication.getPrincipal(); - return mentorService.updateMenteeData(profile.getId(), id, mentee); - } - - @GetMapping("/{id}/mentee") - @ResponseStatus(HttpStatus.OK) - public Mentee getLoggedInMentee( - @PathVariable long id, - Authentication authentication - ) - throws NoContentException { - Profile profile = (Profile) authentication.getPrincipal(); - return mentorService.getLoggedInMentee(id, profile.getId()); - } } diff --git a/src/main/java/org/sefglobal/scholarx/controller/ProgramController.java b/src/main/java/org/sefglobal/scholarx/controller/ProgramController.java index cf8022ff..5a32faba 100644 --- a/src/main/java/org/sefglobal/scholarx/controller/ProgramController.java +++ b/src/main/java/org/sefglobal/scholarx/controller/ProgramController.java @@ -9,7 +9,6 @@ import org.sefglobal.scholarx.service.ProgramService; import org.sefglobal.scholarx.util.EnrolmentState; import org.sefglobal.scholarx.util.ProgramState; -import org.sefglobal.scholarx.util.QuestionCategory; import org.springframework.http.HttpStatus; import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.GetMapping; @@ -60,11 +59,23 @@ public List getAllMentorsByProgramId( public Mentor applyAsMentor( @PathVariable long id, Authentication authentication, - @Valid @RequestBody List responses + @Valid @RequestBody Mentor mentor ) throws ResourceNotFoundException, BadRequestException { Profile profile = (Profile) authentication.getPrincipal(); - return programService.applyAsMentor(id, profile.getId(), responses); + return programService.applyAsMentor(id, profile.getId(), mentor); + } + + @PutMapping("/{id}/mentor") + @ResponseStatus(HttpStatus.OK) + public Mentor updateMentorApplication( + @PathVariable long id, + Authentication authentication, + @Valid @RequestBody Mentor mentor + ) + throws ResourceNotFoundException, BadRequestException { + Profile profile = (Profile) authentication.getPrincipal(); + return programService.updateMentorApplication(id, profile.getId(), mentor); } @GetMapping("/{id}/mentor") @@ -80,16 +91,14 @@ public Mentor getLoggedInMentor( @GetMapping("/{id}/mentee/mentors") @ResponseStatus(HttpStatus.OK) - public List getAppliedMentors( + public Mentor getAppliedMentor( @PathVariable long id, - @RequestParam(required = false) List menteeStates, Authentication authentication ) throws NoContentException { Profile profile = (Profile) authentication.getPrincipal(); - return programService.getAppliedMentorsOfMentee( + return programService.getAppliedMentorOfMentee( id, - menteeStates, profile.getId() ); } @@ -105,36 +114,26 @@ public Mentor getSelectedMentor( return programService.getSelectedMentor(id, profile.getId()); } - @GetMapping("/{id}/questions/{category}") + @PutMapping("/{id}/mentee") @ResponseStatus(HttpStatus.OK) - public List getQuestions(@PathVariable long id, - @PathVariable QuestionCategory category) throws ResourceNotFoundException { - return programService.getQuestions(id, category); - } - - @GetMapping("/{id}/responses/mentor") - @ResponseStatus(HttpStatus.OK) - public List getMentorResponses( - @PathVariable long id, - Authentication authentication, - @RequestParam(required = false) Long mentorId + public Mentee updateMenteeData( + @PathVariable long id, + Authentication authentication, + @Valid @RequestBody Mentee mentee ) - throws ResourceNotFoundException { - if (mentorId != null) { - return programService.getMentorResponses(mentorId); - } + throws ResourceNotFoundException, BadRequestException { Profile profile = (Profile) authentication.getPrincipal(); - return programService.getMentorResponses(id, profile.getId()); + return programService.updateMenteeData(profile.getId(), id, mentee); } - @PutMapping("/{id}/responses/mentor") - public List editMentorResponses( + @GetMapping("/{id}/mentee") + @ResponseStatus(HttpStatus.OK) + public Mentee getLoggedInMentee( @PathVariable long id, - Authentication authentication, - @RequestBody List responses + Authentication authentication ) - throws ResourceNotFoundException, BadRequestException { + throws NoContentException { Profile profile = (Profile) authentication.getPrincipal(); - return programService.editMentorResponses(id, profile.getId(), responses); + return programService.getLoggedInMentee(id, profile.getId()); } } diff --git a/src/main/java/org/sefglobal/scholarx/controller/admin/MenteeController.java b/src/main/java/org/sefglobal/scholarx/controller/admin/MenteeController.java index 1e1a5b5c..68d55adf 100644 --- a/src/main/java/org/sefglobal/scholarx/controller/admin/MenteeController.java +++ b/src/main/java/org/sefglobal/scholarx/controller/admin/MenteeController.java @@ -1,13 +1,15 @@ package org.sefglobal.scholarx.controller.admin; +import org.sefglobal.scholarx.exception.BadRequestException; import org.sefglobal.scholarx.exception.ResourceNotFoundException; +import org.sefglobal.scholarx.model.Mentee; import org.sefglobal.scholarx.service.MenteeService; +import org.sefglobal.scholarx.util.EnrolmentState; import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.Map; @RestController("MenteeAdminController") @RequestMapping("/api/admin/mentees") @@ -25,4 +27,19 @@ public void deleteMentee(@PathVariable long id) throws ResourceNotFoundException { menteeService.deleteMentee(id); } + + @PutMapping("/{id}/assign") + @ResponseStatus(HttpStatus.OK) + public Mentee updateAssignedMentor(@PathVariable long id, + @Valid @RequestBody Map payload) + throws ResourceNotFoundException, BadRequestException { + return menteeService.updateAssignedMentor(id, payload.get("mentorId")); + } + + @PutMapping("/{id}/state") + public Mentee changeState(@PathVariable long id, + @Valid @RequestBody Map payload) + throws ResourceNotFoundException, BadRequestException { + return menteeService.changeState(id, payload.get("state")); + } } diff --git a/src/main/java/org/sefglobal/scholarx/controller/admin/MentorController.java b/src/main/java/org/sefglobal/scholarx/controller/admin/MentorController.java index 030e77e1..fb97f21b 100644 --- a/src/main/java/org/sefglobal/scholarx/controller/admin/MentorController.java +++ b/src/main/java/org/sefglobal/scholarx/controller/admin/MentorController.java @@ -2,6 +2,8 @@ import java.util.Map; import javax.validation.Valid; + +import org.sefglobal.scholarx.exception.BadRequestException; import org.sefglobal.scholarx.exception.ResourceNotFoundException; import org.sefglobal.scholarx.model.Mentor; import org.sefglobal.scholarx.service.MentorService; @@ -28,7 +30,7 @@ public MentorController(MentorService mentorService) { @ResponseStatus(HttpStatus.OK) public Mentor updateState(@PathVariable long id, @Valid @RequestBody Map payload) - throws ResourceNotFoundException { + throws ResourceNotFoundException, BadRequestException { return mentorService.updateState(id, payload.get("state")); } } diff --git a/src/main/java/org/sefglobal/scholarx/controller/admin/ProgramController.java b/src/main/java/org/sefglobal/scholarx/controller/admin/ProgramController.java index 7404cf06..b81653b1 100644 --- a/src/main/java/org/sefglobal/scholarx/controller/admin/ProgramController.java +++ b/src/main/java/org/sefglobal/scholarx/controller/admin/ProgramController.java @@ -3,15 +3,13 @@ import java.util.List; import javax.validation.Valid; -import org.sefglobal.scholarx.exception.BadRequestException; import org.sefglobal.scholarx.exception.ResourceNotFoundException; +import org.sefglobal.scholarx.model.BulkEmailDto; import org.sefglobal.scholarx.model.Mentee; import org.sefglobal.scholarx.model.Mentor; import org.sefglobal.scholarx.model.Program; -import org.sefglobal.scholarx.model.Question; import org.sefglobal.scholarx.service.ProgramService; import org.sefglobal.scholarx.util.EnrolmentState; -import org.sefglobal.scholarx.util.QuestionCategory; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -73,12 +71,18 @@ public List getAllMenteesByProgramId(@PathVariable long id) return programService.getAllMenteesByProgramId(id); } - @PostMapping("/{id}/questions/{category}") + @GetMapping("/{id}/emails") @ResponseStatus(HttpStatus.OK) - public List addQuestions(@PathVariable long id, - @PathVariable QuestionCategory category, - @RequestBody List questions) - throws ResourceNotFoundException, BadRequestException { - return programService.addQuestions(id, category, questions); + public List getAllEmailAddresses(@PathVariable long id) + throws ResourceNotFoundException { + return programService.getEmailsAddresses(id); + } + + @PostMapping("/{id}/email") + @ResponseStatus(HttpStatus.OK) + public void sendBulkEmails(@PathVariable long id, + @Valid @RequestBody BulkEmailDto bulkEmailDto) + throws ResourceNotFoundException { + programService.sendBulkEmails(id, bulkEmailDto); } } diff --git a/src/main/java/org/sefglobal/scholarx/controller/admin/QuestionController.java b/src/main/java/org/sefglobal/scholarx/controller/admin/QuestionController.java deleted file mode 100644 index fb776403..00000000 --- a/src/main/java/org/sefglobal/scholarx/controller/admin/QuestionController.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.sefglobal.scholarx.controller.admin; - -import org.sefglobal.scholarx.exception.BadRequestException; -import org.sefglobal.scholarx.exception.ResourceNotFoundException; -import org.sefglobal.scholarx.model.Question; -import org.sefglobal.scholarx.service.QuestionService; -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -@RestController -@RequestMapping("/api/admin/questions") -public class QuestionController { - private final QuestionService questionService; - - public QuestionController(QuestionService questionService) { - this.questionService = questionService; - } - - @PutMapping - @ResponseStatus(HttpStatus.OK) - public List editQuestions(@RequestBody List questions) - throws ResourceNotFoundException, BadRequestException { - return questionService.editQuestions(questions); - } - - @DeleteMapping("/{id}") - @ResponseStatus(HttpStatus.NO_CONTENT) - public void deleteQuestion(@PathVariable long id) throws ResourceNotFoundException, BadRequestException { - questionService.deleteQuestion(id); - } -} diff --git a/src/main/java/org/sefglobal/scholarx/model/BulkEmailDto.java b/src/main/java/org/sefglobal/scholarx/model/BulkEmailDto.java new file mode 100644 index 00000000..c9b39d27 --- /dev/null +++ b/src/main/java/org/sefglobal/scholarx/model/BulkEmailDto.java @@ -0,0 +1,44 @@ +package org.sefglobal.scholarx.model; + +import org.sefglobal.scholarx.util.MailGroup; + +import java.util.List; + +public class BulkEmailDto { + private String subject; + private String message; + private List mailGroups; + private List additionalEmails; + + public String getSubject() { + return subject; + } + + public void setSubject(String subject) { + this.subject = subject; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public List getMailGroups() { + return mailGroups; + } + + public void setMailGroups(List mailGroups) { + this.mailGroups = mailGroups; + } + + public List getAdditionalEmails() { + return additionalEmails; + } + + public void setAdditionalEmails(List additionalEmails) { + this.additionalEmails = additionalEmails; + } +} diff --git a/src/main/java/org/sefglobal/scholarx/model/Comment.java b/src/main/java/org/sefglobal/scholarx/model/Comment.java new file mode 100644 index 00000000..4e22b976 --- /dev/null +++ b/src/main/java/org/sefglobal/scholarx/model/Comment.java @@ -0,0 +1,43 @@ +package org.sefglobal.scholarx.model; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; +import javax.persistence.ManyToOne; + +@Entity +@Table(name = "comment") +public class Comment extends BaseScholarxModel { + @ManyToOne + private Mentee mentee; + + @Column + private String comment; + + @ManyToOne + private Profile commented_by; + + public String getComment() { + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + } + + public Profile getCommented_by() { + return commented_by; + } + + public void setCommented_by(Profile commented_by) { + this.commented_by = commented_by; + } + + public Mentee getMentee() { + return mentee; + } + + public void setMentee(Mentee mentee) { + this.mentee = mentee; + } +} diff --git a/src/main/java/org/sefglobal/scholarx/model/EnrolledUser.java b/src/main/java/org/sefglobal/scholarx/model/EnrolledUser.java index ffe12036..50dbadfe 100644 --- a/src/main/java/org/sefglobal/scholarx/model/EnrolledUser.java +++ b/src/main/java/org/sefglobal/scholarx/model/EnrolledUser.java @@ -17,7 +17,7 @@ public abstract class EnrolledUser extends BaseScholarxModel { private Profile profile; @Enumerated(EnumType.STRING) - @Column(length = 10, nullable = false) + @Column(length = 20, nullable = false) private EnrolmentState state; @ManyToOne(optional = false) diff --git a/src/main/java/org/sefglobal/scholarx/model/Mentee.java b/src/main/java/org/sefglobal/scholarx/model/Mentee.java index ba7d59f0..67a322d2 100644 --- a/src/main/java/org/sefglobal/scholarx/model/Mentee.java +++ b/src/main/java/org/sefglobal/scholarx/model/Mentee.java @@ -15,29 +15,114 @@ public class Mentee extends EnrolledUser { public Mentee() { } - public Mentee(String submissionUrl) { - this.submissionUrl = submissionUrl; - } + @Column + private String university; + + @Column + private String course; + + @Column + private String year; + + @Column(columnDefinition = "TEXT") + private String intent; + + @Column(columnDefinition = "TEXT") + private String reasonForChoice; + + @Column(columnDefinition = "TEXT") + private String resumeUrl; + + @Column(columnDefinition = "TEXT") + private String achievements; @ManyToOne(optional = false) - private Mentor mentor; + private Mentor appliedMentor; + + @ManyToOne + private Mentor assignedMentor; + + @ManyToOne + private Mentor rejectedBy; + + public Mentor getAppliedMentor() { + return appliedMentor; + } + + public void setAppliedMentor(Mentor appliedMentor) { + this.appliedMentor = appliedMentor; + } + + public Mentor getAssignedMentor() { + return assignedMentor; + } + + public void setAssignedMentor(Mentor assignedMentor) { + this.assignedMentor = assignedMentor; + } + + public String getUniversity() { + return university; + } + + public void setUniversity(String university) { + this.university = university; + } - @Column(nullable = false) - private String submissionUrl; + public String getCourse() { + return course; + } + + public void setCourse(String course) { + this.course = course; + } + + public String getYear() { + return year; + } + + public void setYear(String year) { + this.year = year; + } + + public String getIntent() { + return intent; + } + + public void setIntent(String intent) { + this.intent = intent; + } + + public String getReasonForChoice() { + return reasonForChoice; + } + + public void setReasonForChoice(String reasonForChoice) { + this.reasonForChoice = reasonForChoice; + } + + + public Mentor getRejectedBy() { + return rejectedBy; + } + + public void setRejectedBy(Mentor rejectedBy) { + this.rejectedBy = rejectedBy; + } - public Mentor getMentor() { - return mentor; + public String getResumeUrl() { + return resumeUrl; } - public void setMentor(Mentor mentor) { - this.mentor = mentor; + public void setResumeUrl(String resumeUrl) { + this.resumeUrl = resumeUrl; } - public String getSubmissionUrl() { - return submissionUrl; + public String getAchievements() { + return achievements; } - public void setSubmissionUrl(String submissionUrl) { - this.submissionUrl = submissionUrl; + public void setAchievements(String achievements) { + this.achievements = achievements; } } diff --git a/src/main/java/org/sefglobal/scholarx/model/Mentor.java b/src/main/java/org/sefglobal/scholarx/model/Mentor.java index d873d7eb..2480c84e 100644 --- a/src/main/java/org/sefglobal/scholarx/model/Mentor.java +++ b/src/main/java/org/sefglobal/scholarx/model/Mentor.java @@ -1,32 +1,120 @@ package org.sefglobal.scholarx.model; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.sefglobal.scholarx.util.MentorCategory; -import javax.persistence.Entity; -import javax.persistence.OneToMany; -import javax.persistence.Table; +import javax.persistence.*; import java.util.ArrayList; import java.util.List; @Entity @Table(name = "mentor") -@JsonIgnoreProperties({"createdAt", "updatedAt", "mentees"}) +@JsonIgnoreProperties({"createdAt", "updatedAt", "assignedMentees", "appliedMentees", "rejectedMentees"}) public class Mentor extends EnrolledUser { - @OneToMany(mappedBy = "mentor") - private List mentorResponses; - public Mentor() { } - @OneToMany(mappedBy = "mentor") - private List mentees = new ArrayList<>(); + @Enumerated(EnumType.STRING) + @Column(nullable = false) + private MentorCategory category; + + @Column + private String expertise; + + @Column + private String institution; + + @Column + private String position; + + @Column(columnDefinition = "TEXT") + private String bio; + + @Column + private int slots; + + @Column + private int noOfAssignedMentees; + + @OneToMany(mappedBy = "assignedMentor") + private List assignedMentees = new ArrayList<>(); + + @OneToMany(mappedBy = "appliedMentor") + private List appliedMentees = new ArrayList<>(); + + @OneToMany(mappedBy = "rejectedBy") + private List rejectedMentees = new ArrayList<>(); + + public MentorCategory getCategory() { + return category; + } + + public void setCategory(MentorCategory category) { + this.category = category; + } + + public String getExpertise() { + return expertise; + } + + public void setExpertise(String expertise) { + this.expertise = expertise; + } + + public String getInstitution() { + return institution; + } + + public void setInstitution(String institution) { + this.institution = institution; + } + + public String getPosition() { + return position; + } + + public void setPosition(String position) { + this.position = position; + } + + public String getBio() { + return bio; + } + + public void setBio(String bio) { + this.bio = bio; + } + + public int getSlots() { + return slots; + } + + public void setSlots(int slots) { + this.slots = slots; + } + + public List getAssignedMentees() { + return assignedMentees; + } + + public void setAssignedMentees(List assignedMentees) { + this.assignedMentees = assignedMentees; + } + + public List getAppliedMentees() { + return appliedMentees; + } + + public void setAppliedMentees(List appliedMentees) { + this.appliedMentees = appliedMentees; + } - public List getMentees() { - return mentees; + public int getNoOfAssignedMentees() { + return noOfAssignedMentees; } - public void setMentees(List mentees) { - this.mentees = mentees; + public void setNoOfAssignedMentees(int noOfAssignedMentees) { + this.noOfAssignedMentees = noOfAssignedMentees; } } diff --git a/src/main/java/org/sefglobal/scholarx/model/MentorResponse.java b/src/main/java/org/sefglobal/scholarx/model/MentorResponse.java deleted file mode 100644 index b26d50fd..00000000 --- a/src/main/java/org/sefglobal/scholarx/model/MentorResponse.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.sefglobal.scholarx.model; - -import javax.persistence.*; -import java.io.Serializable; - -@Entity -@Table(name = "mentor_response") -public class MentorResponse implements Serializable { - - @EmbeddedId - MentorResponseId id; - - @ManyToOne(cascade = CascadeType.ALL) - @MapsId("questionId") - @JoinColumn(name = "question_id") - private Question question; - - @ManyToOne(cascade = CascadeType.ALL) - @MapsId("mentorId") - @JoinColumn(name = "mentor_id") - private Mentor mentor; - - @Column(nullable = false, columnDefinition = "TEXT") - private String response; - - public MentorResponse() {} - - public MentorResponse(Question question, Mentor mentor, String response) { - this.id = new MentorResponseId(question.getId(), mentor.getId()); - this.question = question; - this.mentor = mentor; - this.response = response; - } - - public MentorResponseId getId() { - return id; - } - - public void setId(MentorResponseId id) { - this.id = id; - } - - public Question getQuestion() { - return question; - } - - public void setQuestion(Question question) { - this.question = question; - } - - public Mentor getMentor() { - return mentor; - } - - public void setMentor(Mentor mentor) { - this.mentor = mentor; - } - - public String getResponse() { - return response; - } - - public void setResponse(String response) { - this.response = response; - } -} diff --git a/src/main/java/org/sefglobal/scholarx/model/MentorResponseId.java b/src/main/java/org/sefglobal/scholarx/model/MentorResponseId.java deleted file mode 100644 index 50db94c8..00000000 --- a/src/main/java/org/sefglobal/scholarx/model/MentorResponseId.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.sefglobal.scholarx.model; - -import javax.persistence.Column; -import javax.persistence.Embeddable; -import java.io.Serializable; -import java.util.Objects; - -@Embeddable -public class MentorResponseId implements Serializable { - @Column(name = "question_id") - private long questionId; - @Column(name = "mentor_id") - private long mentorId; - - public MentorResponseId() {} - - public MentorResponseId(long questionId, long mentorId) { - this.questionId = questionId; - this.mentorId = mentorId; - } - - public void setQuestionId(long questionId) { - this.questionId = questionId; - } - - public long getQuestionId() { - return questionId; - } - - public void setMentorId(long mentorId) { - this.mentorId = mentorId; - } - - public long getMentorId() { - return mentorId; - } - - @Override - public int hashCode() { - return Objects.hash(questionId, mentorId); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null || getClass() != obj.getClass()) return false; - MentorResponseId id = (MentorResponseId) obj; - return id.mentorId == this.mentorId && id.questionId == this.questionId; - } -} diff --git a/src/main/java/org/sefglobal/scholarx/model/Program.java b/src/main/java/org/sefglobal/scholarx/model/Program.java index 64a3776c..84b042f2 100644 --- a/src/main/java/org/sefglobal/scholarx/model/Program.java +++ b/src/main/java/org/sefglobal/scholarx/model/Program.java @@ -24,7 +24,7 @@ public class Program extends BaseScholarxModel { @Column private String headline; - @Column + @Column(columnDefinition="TEXT") private String imageUrl; @Column @@ -32,12 +32,9 @@ public class Program extends BaseScholarxModel { @JsonIgnore @Enumerated(EnumType.STRING) - @Column(length = 20, nullable = false) + @Column(length = 25, nullable = false) private ProgramState state; - @OneToMany(mappedBy = "program") - private List questions; - @OneToMany(mappedBy = "program") private List enrolledUsers = new ArrayList<>(); diff --git a/src/main/java/org/sefglobal/scholarx/model/Question.java b/src/main/java/org/sefglobal/scholarx/model/Question.java deleted file mode 100644 index 21eb6e71..00000000 --- a/src/main/java/org/sefglobal/scholarx/model/Question.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.sefglobal.scholarx.model; - -import org.sefglobal.scholarx.util.QuestionCategory; - -import javax.persistence.*; -import java.util.List; - -@Entity -@Table(name = "question") -public class Question extends BaseScholarxModel{ - - @Column(nullable = false, columnDefinition = "TEXT") - private String question; - - @Column(nullable = false) - private QuestionCategory category; - - @ManyToOne - @JoinColumn(name = "program_id") - private Program program; - - @OneToMany(mappedBy = "question") - private List mentorResponses; - - public Question() {} - - public Question(String question, QuestionCategory category, Program program) { - this.question = question; - this.category = category; - this.program = program; - } - - public String getQuestion() { - return question; - } - - public void setQuestion(String question) { - this.question = question; - } - - public QuestionCategory getCategory() { - return category; - } - - public void setCategory(QuestionCategory category) { - this.category = category; - } - - public Program getProgram() { - return program; - } - - public void setProgram(Program program) { - this.program = program; - } -} diff --git a/src/main/java/org/sefglobal/scholarx/model/SentEmail.java b/src/main/java/org/sefglobal/scholarx/model/SentEmail.java new file mode 100644 index 00000000..85c0bdca --- /dev/null +++ b/src/main/java/org/sefglobal/scholarx/model/SentEmail.java @@ -0,0 +1,77 @@ +package org.sefglobal.scholarx.model; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; +import javax.persistence.ManyToOne; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.sefglobal.scholarx.util.ProgramState; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; + +@Entity +@Table(name = "email") +@JsonIgnoreProperties({"createdAt"}) +public class SentEmail extends BaseScholarxModel { + @Column + private String email; + + @Column(columnDefinition = "TEXT") + private String message; + + @ManyToOne + private Program program; + + @ManyToOne + private Profile receiver; + + @Enumerated(EnumType.STRING) + @Column + private ProgramState state; + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public ProgramState getstate() { + return state; + } + public void setState(ProgramState state) { + this.state = state; + } + + public Program getProgramId() { + return program; + } + + public void setProgramId(Program program) { + this.program = program; + } + + public void setReceiver(Profile receiver) { + this.receiver = receiver; + } + + public Profile getReceiver() { + return receiver; + } + +} + + + + + + diff --git a/src/main/java/org/sefglobal/scholarx/repository/CommentRepository.java b/src/main/java/org/sefglobal/scholarx/repository/CommentRepository.java new file mode 100644 index 00000000..a3f39f08 --- /dev/null +++ b/src/main/java/org/sefglobal/scholarx/repository/CommentRepository.java @@ -0,0 +1,12 @@ +package org.sefglobal.scholarx.repository; + +import org.sefglobal.scholarx.model.Comment; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface CommentRepository extends JpaRepository { + List findAllByMenteeId(long id); +} diff --git a/src/main/java/org/sefglobal/scholarx/repository/EmailRepository.java b/src/main/java/org/sefglobal/scholarx/repository/EmailRepository.java new file mode 100644 index 00000000..211f3361 --- /dev/null +++ b/src/main/java/org/sefglobal/scholarx/repository/EmailRepository.java @@ -0,0 +1,11 @@ +package org.sefglobal.scholarx.repository; + +import org.sefglobal.scholarx.model.SentEmail; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import java.util.List; + +@Repository +public interface EmailRepository extends JpaRepository { + List findAllByProgram(long id); +} diff --git a/src/main/java/org/sefglobal/scholarx/repository/MenteeRepository.java b/src/main/java/org/sefglobal/scholarx/repository/MenteeRepository.java index 3335377a..11bd794b 100644 --- a/src/main/java/org/sefglobal/scholarx/repository/MenteeRepository.java +++ b/src/main/java/org/sefglobal/scholarx/repository/MenteeRepository.java @@ -15,17 +15,15 @@ @Transactional public interface MenteeRepository extends JpaRepository { - List findAllByMentorIdAndState(long id, EnrolmentState state); + List findAllByAssignedMentorIdAndState(long id, EnrolmentState state); - List findAllByMentorIdAndStateIn(long id, List states); - - List findAllByProgramIdAndProfileId(long programId, long profileId); + List findAllByAssignedMentorIdAndStateIn(long id, List states); List findAllByProgramIdAndProfileIdAndState(long programId, long profileId, EnrolmentState state); - List findAllByProgramIdAndProfileIdAndStateIn(long programId, long profileId, List states); + Optional findByProfileIdAndAppliedMentorId(long profileId, long mentorId); - Optional findByProfileIdAndMentorId(long profileId, long mentorId); + Optional findByProgramIdAndProfileId(long programId, long profileId); List findAllByProfileId(long profileId); @@ -33,6 +31,8 @@ public interface MenteeRepository extends JpaRepository { List findAllByProgramIdAndState(long programId, EnrolmentState state); + List findAllByProgramIdAndStateIn(long programId, List states); + @Modifying @Query( value = "DELETE " + diff --git a/src/main/java/org/sefglobal/scholarx/repository/MentorResponseRepository.java b/src/main/java/org/sefglobal/scholarx/repository/MentorResponseRepository.java deleted file mode 100644 index 68f53d0d..00000000 --- a/src/main/java/org/sefglobal/scholarx/repository/MentorResponseRepository.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.sefglobal.scholarx.repository; - -import org.sefglobal.scholarx.model.MentorResponse; -import org.sefglobal.scholarx.model.MentorResponseId; -import org.springframework.data.jpa.repository.JpaRepository; - -import java.util.List; - -public interface MentorResponseRepository extends JpaRepository { - List getAllByMentorId(long mentorId); -} diff --git a/src/main/java/org/sefglobal/scholarx/repository/ProfileRepository.java b/src/main/java/org/sefglobal/scholarx/repository/ProfileRepository.java index f40eb49c..89f854fd 100644 --- a/src/main/java/org/sefglobal/scholarx/repository/ProfileRepository.java +++ b/src/main/java/org/sefglobal/scholarx/repository/ProfileRepository.java @@ -8,7 +8,7 @@ @Repository public interface ProfileRepository extends JpaRepository { - Optional findByEmail(String email); + Optional findByUid(String uid); Boolean existsByUid(String uid); Boolean existsByEmail(String email); } diff --git a/src/main/java/org/sefglobal/scholarx/repository/QuestionRepository.java b/src/main/java/org/sefglobal/scholarx/repository/QuestionRepository.java deleted file mode 100644 index 001064a4..00000000 --- a/src/main/java/org/sefglobal/scholarx/repository/QuestionRepository.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.sefglobal.scholarx.repository; - -import org.sefglobal.scholarx.model.Program; -import org.sefglobal.scholarx.model.Question; -import org.sefglobal.scholarx.util.QuestionCategory; -import org.springframework.data.jpa.repository.JpaRepository; - -import java.util.List; - -public interface QuestionRepository extends JpaRepository { - List getAllByCategoryAndProgramId(QuestionCategory category, long programId); -} diff --git a/src/main/java/org/sefglobal/scholarx/service/CommentService.java b/src/main/java/org/sefglobal/scholarx/service/CommentService.java new file mode 100644 index 00000000..6f920912 --- /dev/null +++ b/src/main/java/org/sefglobal/scholarx/service/CommentService.java @@ -0,0 +1,113 @@ +package org.sefglobal.scholarx.service; + +import org.sefglobal.scholarx.exception.ResourceNotFoundException; +import org.sefglobal.scholarx.exception.UnauthorizedException; +import org.sefglobal.scholarx.model.Comment; +import org.sefglobal.scholarx.model.Mentee; +import org.sefglobal.scholarx.model.Profile; +import org.sefglobal.scholarx.repository.CommentRepository; +import org.sefglobal.scholarx.repository.MenteeRepository; +import org.sefglobal.scholarx.repository.ProfileRepository; +import org.sefglobal.scholarx.util.ProfileType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Service +public class CommentService { + private final static Logger log = LoggerFactory.getLogger(CommentService.class); + private final CommentRepository commentRepository; + private final ProfileRepository profileRepository; + private final MenteeRepository menteeRepository; + + public CommentService(ProfileRepository profileRepository,MenteeRepository menteeRepository, + CommentRepository commentRepository){ + this.commentRepository = commentRepository; + this.profileRepository = profileRepository; + this.menteeRepository = menteeRepository; + } + + public List getAllMenteeComments(long menteeId, long profileId) + throws ResourceNotFoundException, UnauthorizedException { + Optional optionalMentee = menteeRepository.findById(menteeId); + Optional optionalProfile = profileRepository.findById(profileId); + + if (!optionalMentee.isPresent()) { + String msg = "Error, Mentee by id: " + menteeId + " doesn't exist."; + log.error(msg); + throw new ResourceNotFoundException(msg); + } else if (!(optionalProfile.get().getType().equals(ProfileType.ADMIN) || + optionalMentee.get().getAssignedMentor().getProfile().getId() == profileId)) { + String msg = "Error, User by id: " + profileId + " is not allowed access."; + log.error(msg); + throw new UnauthorizedException(msg); + } + + return commentRepository.findAllByMenteeId(menteeId); + } + + public Comment addMenteeComment(long menteeId, long profileId, Comment menteeComment) + throws ResourceNotFoundException, UnauthorizedException { + Optional optionalProfile = profileRepository.findById(profileId); + Optional optionalMentee = menteeRepository.findById(menteeId); + + if (!optionalMentee.isPresent()) { + String msg = "Error, Mentee by id: " + menteeId + " doesn't exist."; + log.error(msg); + throw new ResourceNotFoundException(msg); + } + + if (!optionalProfile.isPresent()) { + String msg = "Error, User by id: " + profileId + " doesn't exist."; + log.error(msg); + throw new ResourceNotFoundException(msg); + } else if (!(optionalProfile.get().getType().equals(ProfileType.ADMIN) || + optionalMentee.get().getAssignedMentor().getProfile().getId() == profileId)) { + String msg = "Error, User by id: " + profileId + " is not allowed access."; + log.error(msg); + throw new UnauthorizedException(msg); + } + + Comment comment = new Comment(); + comment.setCommented_by(optionalProfile.get()); + comment.setComment(menteeComment.getComment()); + comment.setMentee(optionalMentee.get()); + return commentRepository.save(comment); + } + + public Comment updateComment(long id, long profileId, Comment menteeComment) + throws ResourceNotFoundException, UnauthorizedException { + Optional optionalComment = commentRepository.findById(id); + if (!optionalComment.isPresent()) { + String msg = "Error, Comment with id: " + id + " cannot be updated. " + + "Comment doesn't exist."; + log.error(msg); + throw new ResourceNotFoundException(msg); + } else if (optionalComment.get().getCommented_by().getId() != profileId) { + String msg = "Error, User by id: " + profileId + " is not allowed access."; + log.error(msg); + throw new UnauthorizedException(msg); + } + optionalComment.get().setComment(menteeComment.getComment()); + return commentRepository.save(optionalComment.get()); + } + + public void deleteComment(long id, long profileId) + throws ResourceNotFoundException, UnauthorizedException { + Optional optionalComment = commentRepository.findById(id); + if (!optionalComment.isPresent()) { + String msg = "Error, Comment with id: " + id + " cannot be deleted. " + + "Comment doesn't exist."; + log.error(msg); + throw new ResourceNotFoundException(msg); + } else if (optionalComment.get().getCommented_by().getId() != profileId) { + String msg = "Error, User by id: " + profileId + " is not allowed access."; + log.error(msg); + throw new UnauthorizedException(msg); + } + commentRepository.deleteById(id); + } +} diff --git a/src/main/java/org/sefglobal/scholarx/service/IntrospectionService.java b/src/main/java/org/sefglobal/scholarx/service/IntrospectionService.java index d21c8c1b..9e9ea18d 100644 --- a/src/main/java/org/sefglobal/scholarx/service/IntrospectionService.java +++ b/src/main/java/org/sefglobal/scholarx/service/IntrospectionService.java @@ -142,7 +142,7 @@ public List getMentoringPrograms(long id, EnrolmentState mentorState) * @param profileId which is the id of the {@link Profile} * @param menteeStates which is the list of states that {@link Mentee} objects should be * filtered from - * @return {@link List} of {@link Mentee} objects + * @return {@link List} of {@link Mentee} objects of a {@link Mentor} * * @throws ResourceNotFoundException if the user doesn't exist * @throws NoContentException if {@link Mentor} objects doesn't exist @@ -160,10 +160,10 @@ public List getMentees(long programId, long profileId, throw new ResourceNotFoundException(msg); } if (menteeStates == null || menteeStates.isEmpty()) { - mentees = optionalMentor.get().getMentees(); + mentees = optionalMentor.get().getAssignedMentees(); } else { mentees = menteeRepository - .findAllByMentorIdAndStateIn(optionalMentor.get().getId(), menteeStates); + .findAllByAssignedMentorIdAndStateIn(optionalMentor.get().getId(), menteeStates); } if (mentees.isEmpty()) { @@ -174,43 +174,4 @@ public List 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 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 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(); - } } diff --git a/src/main/java/org/sefglobal/scholarx/service/MenteeService.java b/src/main/java/org/sefglobal/scholarx/service/MenteeService.java index a3c5b851..75923373 100644 --- a/src/main/java/org/sefglobal/scholarx/service/MenteeService.java +++ b/src/main/java/org/sefglobal/scholarx/service/MenteeService.java @@ -2,9 +2,14 @@ import org.sefglobal.scholarx.exception.BadRequestException; 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.util.EnrolmentState; +import org.sefglobal.scholarx.util.ProgramState; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; @@ -16,9 +21,11 @@ public class MenteeService { private final static Logger log = LoggerFactory.getLogger(MenteeService.class); private final MenteeRepository menteeRepository; - - public MenteeService(MenteeRepository menteeRepository) { + private final MentorRepository mentorRepository; + + public MenteeService(MenteeRepository menteeRepository, MentorRepository mentorRepository) { this.menteeRepository = menteeRepository; + this.mentorRepository = mentorRepository; } /** @@ -43,15 +50,17 @@ public void deleteMentee(long id) * Update a {@link EnrolmentState} of a {@link Mentee} to Approved or Rejected * * @param menteeId which is the {@link Mentee} to be updated + * @param profileId which is the profile identifier of the requesting user * @param isApproved which states whether the {@link Mentee} to be approved or rejected * @return the updated {@link Mentee} * * @throws ResourceNotFoundException is thrown if the {@link Mentee} doesn't exist + * @throws UnauthorizedException is thrown if the requesting user is not the assigned mentor * @throws BadRequestException is thrown if the {@link Mentee} is removed * @throws BadRequestException is thrown if the {@link Boolean} is null */ - public Mentee approveOrRejectMentee(long menteeId, Boolean isApproved) - throws ResourceNotFoundException, BadRequestException { + public Mentee approveOrRejectMentee(long menteeId, long profileId, Boolean isApproved) + throws ResourceNotFoundException, BadRequestException, UnauthorizedException { if (null == isApproved){ String msg = "Error, Value cannot be null."; log.error(msg); @@ -64,6 +73,14 @@ public Mentee approveOrRejectMentee(long menteeId, Boolean isApproved) log.error(msg); throw new ResourceNotFoundException(msg); } + long assignedMentorProfileId = optionalMentee.get().getAssignedMentor().getProfile().getId(); + if (assignedMentorProfileId != profileId) { + String msg = "Error, Mentee cannot be approved/rejected. " + + "Mentee with id: " + menteeId + " is not a mentee " + + "of mentor with profile id: " + profileId + "."; + log.error(msg); + throw new UnauthorizedException(msg); + } if (EnrolmentState.REMOVED.equals(optionalMentee.get().getState())) { String msg = "Error, Mentee cannot be approved/rejected. " + "Mentee with id: " + menteeId + " is removed."; @@ -71,7 +88,109 @@ public Mentee approveOrRejectMentee(long menteeId, Boolean isApproved) throw new BadRequestException(msg); } + Mentor mentor = optionalMentee.get().getAssignedMentor(); + if (isApproved) { + mentor.setNoOfAssignedMentees(mentor.getNoOfAssignedMentees() + 1); + } else if (optionalMentee.get().getState().equals(EnrolmentState.ASSIGNED)) { + optionalMentee.get().setRejectedBy(mentor); + } else if (optionalMentee.get().getState().equals(EnrolmentState.APPROVED)) { + optionalMentee.get().setRejectedBy(mentor); + mentor.setNoOfAssignedMentees(mentor.getNoOfAssignedMentees() - 1); + } + optionalMentee.get().setState(isApproved?EnrolmentState.APPROVED:EnrolmentState.REJECTED); return menteeRepository.save(optionalMentee.get()); } + + /** + * Update a assigned {@link Mentor} of a {@link Mentee} + * + * @param menteeId which is the {@link Mentee} to be updated + * @param mentorId which is the id of assigned {@link Mentor} + * @return the updated {@link Mentee} + + * @throws ResourceNotFoundException is thrown if the {@link Mentee} doesn't exist + * @throws ResourceNotFoundException is thrown if the {@link Mentor} doesn't exist + * @throws BadRequestException is thrown if the {@link Mentor} id is not given + * @throws BadRequestException is thrown if the {@link Program} is not in a valid state + */ + public Mentee updateAssignedMentor(long menteeId, Long mentorId) + throws ResourceNotFoundException, BadRequestException { + if (null == mentorId) { + String msg = "Error, Value cannot be null."; + log.error(msg); + throw new BadRequestException(msg); + } + + Optional optionalMentee = menteeRepository.findById(menteeId); + if (!optionalMentee.isPresent()) { + String msg = "Error, Mentee cannot be updated. " + + "Mentee with id: " + menteeId + " doesn't exist."; + log.error(msg); + throw new ResourceNotFoundException(msg); + } + + Optional optionalMentor = mentorRepository.findById(mentorId); + if (!optionalMentor.isPresent()) { + String msg = "Error, Mentee cannot be updated. " + + "Mentor with id: " + mentorId + " doesn't exist."; + log.error(msg); + throw new ResourceNotFoundException(msg); + } + + ProgramState programState = optionalMentee.get().getProgram().getState(); + if (programState.equals(ProgramState.ADMIN_MENTEE_FILTRATION) || programState.equals(ProgramState.WILDCARD)) { + optionalMentee.get().setState(EnrolmentState.ASSIGNED); + } else { + String msg = "Error, Mentee cannot be updated. " + + "Program is not in a valid state."; + log.error(msg); + throw new BadRequestException(msg); + } + + Mentor previouslyAssignedMentor = optionalMentee.get().getAssignedMentor(); + if (previouslyAssignedMentor != null) { + previouslyAssignedMentor.setNoOfAssignedMentees(previouslyAssignedMentor.getNoOfAssignedMentees() - 1); + } + + optionalMentor.get().setNoOfAssignedMentees(optionalMentor.get().getNoOfAssignedMentees() + 1); + optionalMentee.get().setAssignedMentor(optionalMentor.get()); + return menteeRepository.save(optionalMentee.get()); + } + + public Mentee changeState(long menteeId, EnrolmentState enrolmentState) + throws ResourceNotFoundException, BadRequestException { + Optional optionalMentee = menteeRepository.findById(menteeId); + if (!optionalMentee.isPresent()) { + String msg = "Error, Mentee cannot be updated. " + + "Mentee with id "+ menteeId +" doesn't exist."; + log.error(msg); + throw new ResourceNotFoundException(msg); + } + ProgramState state = optionalMentee.get().getProgram().getState(); + if (!ProgramState.ADMIN_MENTEE_FILTRATION.equals(state) && !ProgramState.WILDCARD.equals(state)){ + String msg = "Error, Mentee cannot be updated. " + + "The program is not in a valid state."; + log.error(msg); + throw new BadRequestException(msg); + } + if (EnrolmentState.REJECTED.equals(enrolmentState) || EnrolmentState.APPROVED.equals(enrolmentState) + || EnrolmentState.ASSIGNED.equals(enrolmentState)){ + String msg = "Error, Mentee cannot be updated. " + + "EnrolmentState: "+ enrolmentState +" is not an applicable state."; + log.error(msg); + throw new BadRequestException(msg); + } + + + if(optionalMentee.get().getState().equals(EnrolmentState.ASSIGNED)){ + Mentor assignedMentor = optionalMentee.get().getAssignedMentor(); + assignedMentor.setNoOfAssignedMentees(assignedMentor.getNoOfAssignedMentees() - 1); + optionalMentee.get().setAssignedMentor(null); + mentorRepository.save(assignedMentor); + } + + optionalMentee.get().setState(enrolmentState); + return menteeRepository.save(optionalMentee.get()); + } } diff --git a/src/main/java/org/sefglobal/scholarx/service/MentorService.java b/src/main/java/org/sefglobal/scholarx/service/MentorService.java index 1f7a56f3..8653a461 100644 --- a/src/main/java/org/sefglobal/scholarx/service/MentorService.java +++ b/src/main/java/org/sefglobal/scholarx/service/MentorService.java @@ -1,17 +1,22 @@ package org.sefglobal.scholarx.service; +import com.google.common.collect.ImmutableList; import org.sefglobal.scholarx.exception.BadRequestException; import org.sefglobal.scholarx.exception.NoContentException; import org.sefglobal.scholarx.exception.ResourceNotFoundException; import org.sefglobal.scholarx.model.Mentee; import org.sefglobal.scholarx.model.Mentor; import org.sefglobal.scholarx.model.Profile; +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 org.sefglobal.scholarx.util.ProgramState; +import org.sefglobal.scholarx.util.ProgramUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @@ -24,6 +29,10 @@ public class MentorService { private final MentorRepository mentorRepository; private final MenteeRepository menteeRepository; private final ProfileRepository profileRepository; + private final List validMentorStates = ImmutableList.of(EnrolmentState.APPROVED, EnrolmentState.REJECTED, EnrolmentState.REMOVED); + + @Autowired + private ProgramUtil programUtil; public MentorService(MentorRepository mentorRepository, MenteeRepository menteeRepository, @@ -66,11 +75,18 @@ public Mentor getMentorById(long id) throws ResourceNotFoundException { * @param id which is the {@link Mentor} to be updated * @param enrolmentState which is the {@link EnrolmentState} of the program to be updated * @return the updated {@link Mentor} - * * @throws ResourceNotFoundException is thrown if the requesting {@link Mentor} doesn't exist + * @throws BadRequestException is thrown if the requesting {@link EnrolmentState} is not eligible for a mentor */ public Mentor updateState(long id, EnrolmentState enrolmentState) - throws ResourceNotFoundException { + throws ResourceNotFoundException, BadRequestException { + if (!validMentorStates.contains(enrolmentState)) { + String msg = "Error, Mentor with id: " + id + " cannot be updated. " + + enrolmentState + " is not an applicable state."; + log.error(msg); + throw new BadRequestException(msg); + } + Optional optionalMentor = mentorRepository.findById(id); if (!optionalMentor.isPresent()) { String msg = "Error, Mentor with id: " + id + " cannot be updated. " + @@ -94,6 +110,8 @@ public Mentor updateState(long id, EnrolmentState enrolmentState) * @throws ResourceNotFoundException is thrown if the applying user's {@link Profile} doesn't exist * @throws BadRequestException is thrown if the applying {@link Mentor} is not in applicable state * @throws BadRequestException is thrown if the applying user is already a {@link Mentor} + * @throws BadRequestException is thrown if the applying user has already applied for the {@link Mentor} + * @throws BadRequestException is thrown if the applying program {@link Program} is not in applicable state {@link ProgramState} */ public Mentee applyAsMentee(long mentorId, long profileId, Mentee mentee) throws ResourceNotFoundException, BadRequestException { @@ -111,6 +129,13 @@ public Mentee applyAsMentee(long mentorId, long profileId, Mentee mentee) throw new BadRequestException(msg); } + Program program = optionalMentor.get().getProgram(); + if (!ProgramState.MENTEE_APPLICATION.equals(optionalMentor.get().getProgram().getState())) { + String msg = "Error, Unable to apply as a mentee. " + + "Program with id: " + program.getId() + " is not in the applicable state."; + log.error(msg); + throw new BadRequestException(msg); + } Optional optionalProfile = profileRepository.findById(profileId); if (!optionalProfile.isPresent()) { String msg = "Error, Unable to apply as a mentee. " + @@ -120,7 +145,7 @@ public Mentee applyAsMentee(long mentorId, long profileId, Mentee mentee) } Optional alreadyRegisteredMentor = mentorRepository - .findByProfileIdAndProgramId(profileId, optionalMentor.get().getProgram().getId()); + .findByProfileIdAndProgramId(profileId, program.getId()); if (alreadyRegisteredMentor.isPresent() && alreadyRegisteredMentor.get().getState().equals(EnrolmentState.APPROVED)) { String msg = "Error, Unable to apply as a mentee. " + @@ -129,15 +154,41 @@ public Mentee applyAsMentee(long mentorId, long profileId, Mentee mentee) throw new BadRequestException(msg); } + Optional alreadyAppliedMentee = menteeRepository.findByProgramIdAndProfileId(program.getId(), profileId); + if (alreadyAppliedMentee.isPresent()) { + String msg = "Error, Unable to apply as a mentee. " + + "Profile with id: " + profileId + " has already applied for this program."; + log.error(msg); + throw new BadRequestException(msg); + } + mentee.setProfile(optionalProfile.get()); - mentee.setProgram(optionalMentor.get().getProgram()); - mentee.setMentor(optionalMentor.get()); + mentee.setProgram(program); + mentee.setAppliedMentor(optionalMentor.get()); + mentee.setCourse(mentee.getCourse()); + mentee.setUniversity(mentee.getUniversity()); + mentee.setYear(mentee.getYear()); + mentee.setIntent(mentee.getIntent()); + mentee.setReasonForChoice(mentee.getReasonForChoice()); + mentee.setResumeUrl(mentee.getResumeUrl()); + mentee.setAchievements(mentee.getAchievements()); mentee.setState(EnrolmentState.PENDING); - return menteeRepository.save(mentee); + Mentee savedMenteeEntity = menteeRepository.save(mentee); + + Thread thread = new Thread(() -> { + try { + programUtil.sendConfirmationEmails(profileId, Optional.of(program)); + } catch (Exception exception) { + log.error("Email service error: ", exception); + } + }); + thread.start(); + + return savedMenteeEntity; } /** - * Retrieves all the {@link Mentee} objects of a {@link Mentor} + * Retrieves all the Assigned {@link Mentee} objects of a {@link Mentor} * * @param mentorId which is the Mentor id of the {@link Mentor} * @param state which is the state of the {@link Mentee} objects to be filtered @@ -160,65 +211,8 @@ public List getAllMenteesOfMentor(long mentorId, Optional optionalMentee = menteeRepository.findByProfileIdAndMentorId(profileId, mentorId); - if (!optionalMentee.isPresent()) { - String msg = "Error, Mentee by profile id: " + profileId + " and " + - "mentor id: " + mentorId + " cannot be updated. " + - "Mentee doesn't exist."; - log.error(msg); - throw new ResourceNotFoundException(msg); - } - - Mentee existingMentee = optionalMentee.get(); - if (!mentee.getSubmissionUrl().isEmpty()) { - if (EnrolmentState.PENDING.equals(existingMentee.getState())) { - existingMentee.setSubmissionUrl(mentee.getSubmissionUrl()); - } else { - String msg = "Error, Application cannot be updated. " + - "Mentee is not in a valid state."; - log.error(msg); - throw new BadRequestException(msg); - } - } - return menteeRepository.save(existingMentee); - } - - /** - * Retrieves the {@link Mentee} of a user if the user is a mentee - * - * @param mentorId which is the id of the {@link Mentor} - * @param profileId which is the id of the {@link Profile} - * @return {@link Mentee} - * - * @throws NoContentException if the user hasn't applied for {@link Mentor} - */ - public Mentee getLoggedInMentee(long mentorId, long profileId) - throws NoContentException { - Optional optionalMentee = menteeRepository.findByProfileIdAndMentorId(profileId, mentorId); - if (!optionalMentee.isPresent()) { - String msg = "Error, User by profile id: " + profileId + " hasn't applied for " + - "mentor with id: " + mentorId + "."; - log.error(msg); - throw new NoContentException(msg); + return optionalMentor.get().getAssignedMentees(); } - return optionalMentee.get(); + return menteeRepository.findAllByAssignedMentorIdAndState(mentorId,state.get()); } } diff --git a/src/main/java/org/sefglobal/scholarx/service/ProfileService.java b/src/main/java/org/sefglobal/scholarx/service/ProfileService.java index 549a43f6..6391a8a1 100644 --- a/src/main/java/org/sefglobal/scholarx/service/ProfileService.java +++ b/src/main/java/org/sefglobal/scholarx/service/ProfileService.java @@ -31,11 +31,12 @@ public Profile processUserRegistration(Map attributes) } else if (StringUtils.isEmpty(oAuth2UserInfo.getEmail())) { throw new OAuth2AuthenticationProcessingException("Email not found from OAuth2 provider"); } - Optional profile = profileRepository.findByEmail(oAuth2UserInfo.getEmail()); + Optional profile = profileRepository.findByUid(oAuth2UserInfo.getUuid()); if (profile.isPresent()) { profile.get().setFirstName(oAuth2UserInfo.getFirstName()); profile.get().setLastName(oAuth2UserInfo.getLastName()); profile.get().setImageUrl(oAuth2UserInfo.getImageUrl()); + profile.get().setEmail(oAuth2UserInfo.getEmail()); return profileRepository.save(profile.get()); } else { return createProfile(oAuth2UserInfo); diff --git a/src/main/java/org/sefglobal/scholarx/service/ProgramService.java b/src/main/java/org/sefglobal/scholarx/service/ProgramService.java index 57ec015e..b01c69b7 100644 --- a/src/main/java/org/sefglobal/scholarx/service/ProgramService.java +++ b/src/main/java/org/sefglobal/scholarx/service/ProgramService.java @@ -1,5 +1,6 @@ package org.sefglobal.scholarx.service; +import com.google.common.collect.ImmutableList; import org.sefglobal.scholarx.exception.BadRequestException; import org.sefglobal.scholarx.exception.NoContentException; import org.sefglobal.scholarx.exception.ResourceNotFoundException; @@ -11,7 +12,13 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.*; +import javax.mail.MessagingException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; @Service public class ProgramService { @@ -20,24 +27,21 @@ public class ProgramService { private final ProfileRepository profileRepository; private final MentorRepository mentorRepository; private final MenteeRepository menteeRepository; - private final QuestionRepository questionRepository; - private final MentorResponseRepository mentorResponseRepository; @Autowired private ProgramUtil programUtil; + @Autowired + private EmailService emailService; + public ProgramService(ProgramRepository programRepository, ProfileRepository profileRepository, MentorRepository mentorRepository, - MenteeRepository menteeRepository, - QuestionRepository questionRepository, - MentorResponseRepository mentorResponseRepository) { + MenteeRepository menteeRepository) { this.programRepository = programRepository; this.profileRepository = profileRepository; this.mentorRepository = mentorRepository; this.menteeRepository = menteeRepository; - this.questionRepository = questionRepository; - this.mentorResponseRepository = mentorResponseRepository; } /** @@ -122,23 +126,68 @@ public Program updateProgram(long id, Program program) throws ResourceNotFoundEx */ public Program updateState(long id) throws ResourceNotFoundException { Optional program = programRepository.findById(id); + if (!program.isPresent()) { + String msg = "Error, Program with id: " + id + " cannot be updated. " + + "Program doesn't exist."; + log.error(msg); + throw new ResourceNotFoundException(msg); + } final ProgramState nextState = program.get().getState().next(); + + switch (nextState) { + case MENTEE_APPLICATION: + List mentors = mentorRepository.findAllByProgramIdAndState(id, EnrolmentState.PENDING); + for (Mentor mentor : mentors) { + mentor.setState(EnrolmentState.REJECTED); + } + break; + + case MENTEE_SELECTION: + List mentorList = mentorRepository.findAllByProgramId(id); + for (Mentor mentor: mentorList) { + mentor.setNoOfAssignedMentees(0); + } + break; + + case WILDCARD: + List mentees = menteeRepository.findAllByProgramIdAndStateIn( + id, ImmutableList.of(EnrolmentState.ASSIGNED, EnrolmentState.REJECTED)); + for (Mentee mentee : mentees) { + mentee.setState(EnrolmentState.REJECTED); + mentee.setRejectedBy(mentee.getAssignedMentor()); + mentee.setAssignedMentor(null); + } + break; + + case ONGOING: + List approvedMentees = menteeRepository.findAllByProgramIdAndState(id, EnrolmentState.ASSIGNED); + for (Mentee mentee : approvedMentees) { + mentee.setState(EnrolmentState.APPROVED); + } + List ignoredMentees = menteeRepository. + findAllByProgramIdAndStateIn(id, ImmutableList.of(EnrolmentState.POOL, EnrolmentState.PENDING, EnrolmentState.REJECTED)); + for (Mentee mentee : ignoredMentees) { + mentee.setState(EnrolmentState.FAILED_FROM_WILDCARD); + } + break; + } + Thread thread = new Thread(() -> { try { switch (nextState) { case MENTEE_APPLICATION: programUtil.sendMenteeApplicationEmails(id, program); break; + case ADMIN_MENTEE_FILTRATION: + programUtil.sendMenteeFiltrationEmails(id, program); + break; case MENTEE_SELECTION: programUtil.sendMenteeSelectionEmails(id, program); break; case ONGOING: programUtil.sendOnGoingEmails(id, program); break; - case MENTOR_CONFIRMATION: - programUtil.sendMentorConfirmationEmails(id, program); - break; } } catch (Exception exception) { log.error("Email service error: ", exception); @@ -146,22 +195,6 @@ public Program updateState(long id) throws ResourceNotFoundException { }); thread.start(); - if (!program.isPresent()) { - String msg = "Error, Program with id: " + id + " cannot be updated. " + - "Program doesn't exist."; - log.error(msg); - throw new ResourceNotFoundException(msg); - } - - if (ProgramState.ONGOING.equals(nextState)) { - List approvedMenteeList = menteeRepository.findAllByProgramIdAndState(id, EnrolmentState.APPROVED); - for (Mentee mentee : approvedMenteeList) { - long profileId = mentee.getProfile().getId(); - if (menteeRepository.findAllByProgramIdAndProfileIdAndState(id, profileId, EnrolmentState.APPROVED).size() != 1) { - menteeRepository.removeAllByProgramIdAndProfileId(id, profileId); - } - } - } program.get().setState(nextState); return programRepository.save(program.get()); } @@ -230,19 +263,20 @@ public List getAllMenteesByProgramId(long id) } /** - * Create new {@link Mentor} and Record new {@link MentorResponse} list + * Create new {@link Mentor} * * @param programId which is the program id for the requesting {@link Program} * @param profileId which is the profile id of the applying user's {@link Profile} - * @param responses which holds the responses to be added + * @param mentor which holds the mentor details * @return the created {@link Mentor} * * @throws ResourceNotFoundException is thrown if the applying {@link Program} doesn't exist * @throws ResourceNotFoundException is thrown if the applying user's {@link Profile} doesn't exist * @throws BadRequestException is thrown if the applying {@link Program} is * not in the applicable {@link ProgramState} + * @throws BadRequestException is thrown if the applying user has already applied for the {@link Program} */ - public Mentor applyAsMentor(long programId, long profileId, List responses) + public Mentor applyAsMentor(long programId, long profileId, Mentor mentor) throws ResourceNotFoundException, BadRequestException { Optional optionalProgram = programRepository.findById(programId); if (!optionalProgram.isPresent()) { @@ -266,122 +300,94 @@ public Mentor applyAsMentor(long programId, long profileId, List throw new ResourceNotFoundException(msg); } - Mentor mentor = new Mentor(); - mentor.setProfile(optionalProfile.get()); - mentor.setProgram(optionalProgram.get()); - mentor.setState(EnrolmentState.PENDING); - Mentor savedMentor = mentorRepository.save(mentor); - List processedResponses = new ArrayList<>(); - for (MentorResponse r: responses) { - Question question = questionRepository.getOne(r.getQuestion().getId()); - MentorResponse updatedResponse = new MentorResponse(question, savedMentor, r.getResponse()); - processedResponses.add(updatedResponse); - } - try { - mentorResponseRepository.saveAll(processedResponses); - } catch (Exception e) { - mentorRepository.delete(savedMentor); - throw e; + Optional duplicateMentor = mentorRepository.findByProfileIdAndProgramId(profileId, programId); + if (duplicateMentor.isPresent()) { + String msg = "Error, Unable to apply as a mentor. " + + "Profile with id: " + profileId + " has already applied as a mentor for the selected program."; + log.error(msg); + throw new BadRequestException(msg); } - return savedMentor; + + Mentor savedMentor = new Mentor(); + savedMentor.setProfile(optionalProfile.get()); + savedMentor.setProgram(optionalProgram.get()); + savedMentor.setCategory(mentor.getCategory()); + savedMentor.setBio(mentor.getBio()); + savedMentor.setExpertise(mentor.getExpertise()); + savedMentor.setInstitution(mentor.getInstitution()); + savedMentor.setPosition(mentor.getPosition()); + savedMentor.setSlots(mentor.getSlots()); + savedMentor.setState(EnrolmentState.PENDING); + Mentor savedMentorEntity = mentorRepository.save(savedMentor); + + Thread thread = new Thread(() -> { + try { + programUtil.sendConfirmationEmails(profileId, optionalProgram); + } catch (Exception exception) { + log.error("Email service error: ", exception); + } + }); + thread.start(); + + return savedMentorEntity; } /** - * Retrieves the {@link Mentor} of a user if the user is a mentor + * Update a {@link Mentor} * - * @param programId which is the id of the {@link Program} - * @param profileId which is the id of the {@link Profile} - * @return {@link Mentor} + * @param programId which is the program id for the mentor's {@link Program} + * @param profileId which is the profile id of the mentor's {@link Profile} + * @param mentor which holds the mentor details + * @return the updated {@link Mentor} * - * @throws ResourceNotFoundException if the requesting {@link Mentor} doesn't exist + * @throws ResourceNotFoundException is thrown if the mentor doesn't exist + * @throws BadRequestException is thrown if the {@link Program} is not in the applicable {@link ProgramState} */ - public Mentor getLoggedInMentor(long programId, long profileId) - throws ResourceNotFoundException { + public Mentor updateMentorApplication(long programId, long profileId, Mentor mentor) + throws ResourceNotFoundException, BadRequestException { Optional optionalMentor = mentorRepository.findByProfileIdAndProgramId(profileId, programId); if (!optionalMentor.isPresent()) { - String msg = "Error, Mentor by profile id: " + profileId + " and " + - "program id: " + programId + " doesn't exist."; + String msg = "Error, Unable to update mentor application. " + + "Mentor with profile id: " + profileId + " doesn't exist."; log.error(msg); throw new ResourceNotFoundException(msg); } - return optionalMentor.get(); - } - /** - * Retrieves the {@link MentorResponse} List of a {@link Mentor} - * - * @param programId which is the Id of the {@link Program} - * @param profileId which is the profile Id of the {@link Mentor} - * @return {@link MentorResponse} list - * @throws ResourceNotFoundException if a mentor doesn't exist by the given programId and profileId - */ - public List getMentorResponses(long programId, long profileId) throws ResourceNotFoundException { - Optional mentor = mentorRepository.findByProfileIdAndProgramId(profileId, programId); - if (!mentor.isPresent()) { - String msg = "Error, Mentor by profile id: " + profileId + " and " + - "program id: " + programId + " cannot be found. " + - "Mentor doesn't exist."; + if (!ProgramState.MENTOR_APPLICATION.equals(optionalMentor.get().getProgram().getState())) { + String msg = "Error, Unable to update mentor application. " + + "Program with id: " + programId + " is not in the valid state."; log.error(msg); - throw new ResourceNotFoundException(msg); + throw new BadRequestException(msg); } - return mentorResponseRepository.getAllByMentorId(mentor.get().getId()); - } - /** - * Retrives the {@link MentorResponse} List of a {@link Mentor} - * - * @param mentorId which is the id of the {@link Mentor} - * @return {@link MentorResponse} list - * @throws ResourceNotFoundException if a mentor doesn't exist by the given mentorId - */ - public List getMentorResponses(long mentorId) throws ResourceNotFoundException { - Optional mentor = mentorRepository.findById(mentorId); - if (!mentor.isPresent()) { - String msg = "Error, Mentor by mentor id: " + mentorId + " cannot be found. " + - "Mentor doesn't exist."; - log.error(msg); - throw new ResourceNotFoundException(msg); - } - return mentorResponseRepository.getAllByMentorId(mentor.get().getId()); + optionalMentor.get().setCategory(mentor.getCategory()); + optionalMentor.get().setBio(mentor.getBio()); + optionalMentor.get().setExpertise(mentor.getExpertise()); + optionalMentor.get().setInstitution(mentor.getInstitution()); + optionalMentor.get().setPosition(mentor.getPosition()); + optionalMentor.get().setSlots(mentor.getSlots()); + return mentorRepository.save(optionalMentor.get()); } /** - * Update the application question responses of a {@link Mentor} + * Retrieves the {@link Mentor} of a user if the user is a mentor * - * @param programId which is the id of the program - * @param profileId which is the profile id of the {@link Mentor} - * @param mentorResponses list of {@link MentorResponse}s to be updated - * @return the updated list of {@link MentorResponse} - * @throws ResourceNotFoundException if a mentor doesn't exist by the given profileId and programId - * @throws BadRequestException is thrown if the {@link Program} is not in the valid {@link ProgramState} + * @param programId which is the id of the {@link Program} + * @param profileId which is the id of the {@link Profile} + * @return {@link Mentor} + * + * @throws ResourceNotFoundException if the requesting {@link Mentor} doesn't exist */ - public List editMentorResponses(long programId, - long profileId, - List mentorResponses) - throws ResourceNotFoundException, BadRequestException { - Optional mentor = mentorRepository.findByProfileIdAndProgramId(profileId, programId); - if (!mentor.isPresent()) { + public Mentor getLoggedInMentor(long programId, long profileId) + throws ResourceNotFoundException { + Optional optionalMentor = mentorRepository.findByProfileIdAndProgramId(profileId, programId); + if (!optionalMentor.isPresent()) { String msg = "Error, Mentor by profile id: " + profileId + " and " + - "program id: " + programId + " cannot be found. " + - "Mentor doesn't exist."; + "program id: " + programId + " doesn't exist."; log.error(msg); throw new ResourceNotFoundException(msg); } - - if (!ProgramState.MENTOR_APPLICATION.equals(mentor.get().getProgram().getState())) { - String msg = "Error, Unable to edit mentor application. " + - "Program with id: " + programId + " is not in the valid state."; - log.error(msg); - throw new BadRequestException(msg); - } - - List updatedMentorResponses = new ArrayList<>(); - for (MentorResponse response: mentorResponses) { - MentorResponse queriedResponse = mentorResponseRepository.getOne(response.getId()); - queriedResponse.setResponse(response.getResponse()); - updatedMentorResponses.add(queriedResponse); - } - return mentorResponseRepository.saveAll(updatedMentorResponses); + return optionalMentor.get(); } /** @@ -389,31 +395,22 @@ public List editMentorResponses(long programId, * * @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 + * @return {@link Mentor} object * * @throws NoContentException if the user hasn't applied for {@link Mentor} objects */ - public List getAppliedMentorsOfMentee(long programId, List menteeStates, long profileId) + public Mentor getAppliedMentorOfMentee(long programId, long profileId) throws NoContentException { - List menteeList; - if (menteeStates == null || menteeStates.isEmpty()) { - menteeList = menteeRepository.findAllByProgramIdAndProfileId(programId, profileId); - } else { - menteeList = menteeRepository.findAllByProgramIdAndProfileIdAndStateIn(programId, profileId, menteeStates); - } - if (menteeList.isEmpty()) { + Optional mentee = menteeRepository.findByProgramIdAndProfileId(programId, profileId); + + if (!mentee.isPresent()) { String msg = "Error, Mentee by program id: " + programId + " and " + "profile id: " + profileId + " doesn't exist."; log.error(msg); throw new NoContentException(msg); } - List mentorList = new ArrayList<>(); - for (Mentee mentee : menteeList) { - mentorList.add(mentee.getMentor()); - } - return mentorList; + + return mentee.get().getAppliedMentor(); } /** @@ -427,18 +424,16 @@ public List getAppliedMentorsOfMentee(long programId, List menteeList = menteeRepository - .findAllByProgramIdAndProfileId(programId, profileId); - if (menteeList.isEmpty()) { + Optional optionalMentee = menteeRepository + .findByProgramIdAndProfileId(programId, profileId); + if (!optionalMentee.isPresent()) { String msg = "Error, Mentee by program id: " + programId + " and " + "profile id: " + profileId + " doesn't exist."; log.error(msg); throw new ResourceNotFoundException(msg); } - for (Mentee mentee : menteeList) { - if (EnrolmentState.APPROVED.equals(mentee.getState())) { - return mentee.getMentor(); - } + if (EnrolmentState.APPROVED.equals(optionalMentee.get().getState())) { + return optionalMentee.get().getAssignedMentor(); } String msg = "Error, Mentee is not approved by any mentor yet."; @@ -447,54 +442,163 @@ public Mentor getSelectedMentor(long programId, long profileId) } /** - * Retrieves the {@link Question} list for a given {@link Program} and a {@link QuestionCategory} + * Update the application of a {@link Mentee} * - * @param programId which is the if of the {@link Program} - * @param category which is the identifier of if the required set of questions are mentor ones or mentee ones - * @return {@link Question} Object list - * @throws ResourceNotFoundException if the {@link Program} doesn't exist + * @param profileId which is the Profile id of the {@link Mentee} to be updated + * @param programId which is the Program id of the {@link Mentee} to be updated + * @param mentee with the application of the mentee to be updated + * @return the updated {@link Mentee} + * + * @throws ResourceNotFoundException is thrown if the {@link Mentee} doesn't exist + * @throws ResourceNotFoundException is thrown if the {@link Mentor} doesn't exist + * @throws BadRequestException if the {@link Mentor} is not in the valid state + * @throws BadRequestException if the {@link Mentee} is not in the valid state + * @throws BadRequestException is thrown if the applying program {@link Program} is not in applicable state {@link ProgramState} */ - public List getQuestions(long programId, QuestionCategory category) throws ResourceNotFoundException { - Optional program = programRepository.findById(programId); - if (!program.isPresent()) { - String msg = "Error, Program by id: " + programId + " doesn't exist."; + public Mentee updateMenteeData(long profileId, long programId, Mentee mentee) + throws ResourceNotFoundException, BadRequestException { + Optional optionalMentee = menteeRepository.findByProgramIdAndProfileId(programId, profileId); + if (!optionalMentee.isPresent()) { + String msg = "Error, Mentee by profile id: " + profileId + " and " + + "program id: " + programId + " cannot be updated. " + + "Mentee doesn't exist."; log.error(msg); throw new ResourceNotFoundException(msg); } - return questionRepository.getAllByCategoryAndProgramId(category, program.get().getId()); + if (!ProgramState.MENTEE_APPLICATION.equals(optionalMentee.get().getProgram().getState())) { + String msg = "Error, Unable to update mentee application. " + + "Program with id: " + programId + " is not in the valid state."; + log.error(msg); + throw new BadRequestException(msg); + } + Optional optionalMentor = mentorRepository.findById(mentee.getAppliedMentor().getId()); + if (!optionalMentor.isPresent()) { + String msg = "Error, Mentee by profile id: " + profileId + " and " + + "program id: " + programId + " cannot be updated. " + + "Applied Mentor doesn't exist."; + log.error(msg); + throw new ResourceNotFoundException(msg); + } + if (!EnrolmentState.APPROVED.equals(optionalMentor.get().getState())) { + String msg = "Error, Unable to apply as a mentee. " + + "Mentor is not in the applicable state."; + log.error(msg); + throw new BadRequestException(msg); + } + + Mentee existingMentee = optionalMentee.get(); + if (EnrolmentState.PENDING.equals(existingMentee.getState())) { + existingMentee.setAppliedMentor(optionalMentor.get()); + existingMentee.setIntent(mentee.getIntent()); + existingMentee.setUniversity(mentee.getUniversity()); + existingMentee.setYear(mentee.getYear()); + existingMentee.setReasonForChoice(mentee.getReasonForChoice()); + existingMentee.setResumeUrl(mentee.getResumeUrl()); + existingMentee.setAchievements(mentee.getAchievements()); + } else { + String msg = "Error, Application cannot be updated. " + + "Mentee is not in a valid state."; + log.error(msg); + throw new BadRequestException(msg); + } + return menteeRepository.save(existingMentee); } /** - *Adds new {@link Question} objects to the {@link Program} mentor/mentee application forms + * Retrieves the {@link Mentee} of a user if the user is a mentee * * @param programId which is the id of the {@link Program} - * @param category which is the identifier of whether the question is a {@link Mentor} one or a {@link Mentee} one - * @param questions which is the list of questions - * @return {@link Question} Object list + * @param profileId which is the id of the {@link Profile} + * @return {@link Mentee} + * @throws NoContentException if the user hasn't applied for {@link Program} + */ + public Mentee getLoggedInMentee(long programId, long profileId) + throws NoContentException { + Optional optionalMentee = menteeRepository.findByProgramIdAndProfileId(programId, profileId); + if (!optionalMentee.isPresent()) { + String msg = "Error, User by profile id: " + profileId + " hasn't applied for " + + "program with id: " + programId + "."; + log.error(msg); + throw new NoContentException(msg); + } + return optionalMentee.get(); + } + + /** + * Retrieves all the emails from {@link EnrolledUser} + * + * @param programId which is the id of the {@link Program} + * @return {@link List} * @throws ResourceNotFoundException if the {@link Program} doesn't exist - * @throws BadRequestException if the {@link Program} is not in valid state */ - public List addQuestions(long programId, QuestionCategory category, List questions) - throws ResourceNotFoundException, BadRequestException { + public List getEmailsAddresses(long programId) + throws ResourceNotFoundException { Optional program = programRepository.findById(programId); if (!program.isPresent()) { String msg = "Error, Program by id: " + programId + " doesn't exist."; log.error(msg); throw new ResourceNotFoundException(msg); } - if (!ProgramState.CREATED.equals(program.get().getState())) { - String msg = "Error, Unable to add question. " + - "Program with id: " + programId + " is not in the valid state."; - log.error(msg); - throw new BadRequestException(msg); + List enrolledUsers = program.get().getEnrolledUsers(); + List emails = new ArrayList(); + + for(EnrolledUser user: enrolledUsers) { + emails.add(user.getProfile().getEmail()); } + return emails; + } - List processedQuestions = new ArrayList<>(); - for (Question q: questions) { - q.setProgram(program.get()); - q.setCategory(category); - processedQuestions.add(q); + /** + * Sends bulk emails to the recipients in {@link BulkEmailDto} + * + * @param programId which is the id of the {@link Program} + * @param bulkEmailDto which contains the recipients and the message + * @throws ResourceNotFoundException if the program doesn't exist + */ + public void sendBulkEmails(long programId, BulkEmailDto bulkEmailDto) + throws ResourceNotFoundException { + Optional optionalProgram = programRepository.findById(programId); + if (!optionalProgram.isPresent()) { + String msg = "Error, Program with id: " + programId + " doesn't exist."; + log.error(msg); + throw new ResourceNotFoundException(msg); + } + Set emails = new HashSet<>(); + for (MailGroup mailGroup : bulkEmailDto.getMailGroups()) { + if (mailGroup.equals(MailGroup.ALL)){ + optionalProgram.get().getEnrolledUsers() + .forEach(user -> emails.add(user.getProfile().getEmail())); + } else if (mailGroup.equals(MailGroup.ALL_MENTORS)){ + mentorRepository.findAllByProgramId(programId) + .forEach(mentor -> emails.add(mentor.getProfile().getEmail())); + } else if (mailGroup.equals(MailGroup.ALL_MENTEES)){ + menteeRepository.findAllByProgramId(programId) + .forEach(mentee -> emails.add(mentee.getProfile().getEmail())); + } else if (mailGroup.equals(MailGroup.APPROVED_MENTORS)){ + mentorRepository.findAllByProgramIdAndState(programId, EnrolmentState.APPROVED) + .forEach(mentor -> emails.add(mentor.getProfile().getEmail())); + } else if (mailGroup.equals(MailGroup.REJECTED_MENTORS)){ + mentorRepository.findAllByProgramIdAndState(programId, EnrolmentState.REJECTED) + .forEach(mentor -> emails.add(mentor.getProfile().getEmail())); + } else if (mailGroup.equals(MailGroup.APPROVED_MENTEES)) { + menteeRepository.findAllByProgramIdAndState(programId, EnrolmentState.APPROVED) + .forEach(mentee -> emails.add(mentee.getProfile().getEmail())); + } else if (mailGroup.equals(MailGroup.DISCARDED_MENTEES)) { + menteeRepository.findAllByProgramIdAndStateIn(programId, ImmutableList.of(EnrolmentState.DISCARDED, EnrolmentState.FAILED_FROM_WILDCARD)) + .forEach(mentee -> emails.add(mentee.getProfile().getEmail())); + } } - return questionRepository.saveAll(processedQuestions); + + emails.addAll(bulkEmailDto.getAdditionalEmails()); + Thread thread = new Thread(() -> { + for (String email : emails) { + try { + emailService.sendEmail(email, bulkEmailDto.getSubject(), bulkEmailDto.getMessage(), true); + } catch (MessagingException | IOException exception) { + log.error("Email service error: ", exception); + } + } + }); + thread.start(); } } diff --git a/src/main/java/org/sefglobal/scholarx/service/QuestionService.java b/src/main/java/org/sefglobal/scholarx/service/QuestionService.java deleted file mode 100644 index d06455a1..00000000 --- a/src/main/java/org/sefglobal/scholarx/service/QuestionService.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.sefglobal.scholarx.service; - -import org.sefglobal.scholarx.exception.BadRequestException; -import org.sefglobal.scholarx.exception.ResourceNotFoundException; -import org.sefglobal.scholarx.model.Question; -import org.sefglobal.scholarx.repository.QuestionRepository; -import org.sefglobal.scholarx.util.ProgramState; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Service; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -@Service -public class QuestionService { - private final Logger log = LoggerFactory.getLogger(QuestionService.class); - private final QuestionRepository questionRepository; - - public QuestionService(QuestionRepository questionRepository) { - this.questionRepository = questionRepository; - } - - /** - * Updates existing {@link Question} records by a given set of {@link Question} - * - * @param questions the set of {@link Question} that needs to be updated - * @return List of updated {@link Question} - * @throws ResourceNotFoundException if a given {@link Question} doesn't exist on the database - * @throws BadRequestException if the Program is not in the valid state - */ - public List editQuestions(List questions) throws ResourceNotFoundException, BadRequestException { - List updatedQuestions = new ArrayList<>(); - for(Question q: questions) { - Optional question = questionRepository.findById(q.getId()); - if (!question.isPresent()) { - String msg = "Error, question by id:" + q.getId() + " doesn't exist."; - log.error(msg); - throw new ResourceNotFoundException(msg); - } - if (!ProgramState.CREATED.equals(question.get().getProgram().getState())) { - String msg = "Error, Unable to edit question by id:" + q.getId() + ". " + - "Program is not in the valid state."; - log.error(msg); - throw new BadRequestException(msg); - } - question.get().setQuestion(q.getQuestion()); - updatedQuestions.add(question.get()); - } - return questionRepository.saveAll(updatedQuestions); - } - - /** - * Deletes existing {@link Question} records by a given {@link Question} id - * - * @param id which is the id of the {@link Question} that needs to be deleted - * @throws ResourceNotFoundException if a {@link Question} by the given id doesn't exist - * @throws BadRequestException if the Program is not in the valid state - */ - public void deleteQuestion(long id) throws ResourceNotFoundException, BadRequestException { - Optional question = questionRepository.findById(id); - if (!question.isPresent()) { - String msg = "Error, question by id:" + id + " doesn't exist."; - log.error(msg); - throw new ResourceNotFoundException(msg); - } - if (!ProgramState.CREATED.equals(question.get().getProgram().getState())) { - String msg = "Error, Unable to delete question. " + - "Program is not in the valid state."; - log.error(msg); - throw new BadRequestException(msg); - } - - questionRepository.delete(question.get()); - } -} diff --git a/src/main/java/org/sefglobal/scholarx/util/EnrolmentState.java b/src/main/java/org/sefglobal/scholarx/util/EnrolmentState.java index 854d6653..92808b30 100644 --- a/src/main/java/org/sefglobal/scholarx/util/EnrolmentState.java +++ b/src/main/java/org/sefglobal/scholarx/util/EnrolmentState.java @@ -2,8 +2,12 @@ public enum EnrolmentState { PENDING, + POOL, + ASSIGNED, APPROVED, + DISCARDED, REJECTED, + FAILED_FROM_WILDCARD, REMOVED; public boolean isHigherThanOrEqual(EnrolmentState state){ diff --git a/src/main/java/org/sefglobal/scholarx/util/MailGroup.java b/src/main/java/org/sefglobal/scholarx/util/MailGroup.java new file mode 100644 index 00000000..62614723 --- /dev/null +++ b/src/main/java/org/sefglobal/scholarx/util/MailGroup.java @@ -0,0 +1,11 @@ +package org.sefglobal.scholarx.util; + +public enum MailGroup { + ALL, + ALL_MENTORS, + ALL_MENTEES, + APPROVED_MENTORS, + REJECTED_MENTORS, + APPROVED_MENTEES, + DISCARDED_MENTEES, +} diff --git a/src/main/java/org/sefglobal/scholarx/util/MentorCategory.java b/src/main/java/org/sefglobal/scholarx/util/MentorCategory.java new file mode 100644 index 00000000..a8b57215 --- /dev/null +++ b/src/main/java/org/sefglobal/scholarx/util/MentorCategory.java @@ -0,0 +1,10 @@ +package org.sefglobal.scholarx.util; + +public enum MentorCategory { + ENGINEERING, + LIFE_SCIENCES, + COMPUTER_SCIENCE, + DATASCIENCE_AND_AI, + PHYSICAL_SCIENCE, + OTHER +} diff --git a/src/main/java/org/sefglobal/scholarx/util/ProgramState.java b/src/main/java/org/sefglobal/scholarx/util/ProgramState.java index a892e009..a07b1fbe 100644 --- a/src/main/java/org/sefglobal/scholarx/util/ProgramState.java +++ b/src/main/java/org/sefglobal/scholarx/util/ProgramState.java @@ -5,8 +5,9 @@ public enum ProgramState { MENTOR_APPLICATION, MENTOR_SELECTION, MENTEE_APPLICATION, + ADMIN_MENTEE_FILTRATION, MENTEE_SELECTION, - MENTOR_CONFIRMATION, + WILDCARD, ONGOING, COMPLETED, REMOVED; diff --git a/src/main/java/org/sefglobal/scholarx/util/ProgramUtil.java b/src/main/java/org/sefglobal/scholarx/util/ProgramUtil.java index 7ef64adb..b952b974 100644 --- a/src/main/java/org/sefglobal/scholarx/util/ProgramUtil.java +++ b/src/main/java/org/sefglobal/scholarx/util/ProgramUtil.java @@ -2,13 +2,19 @@ import org.sefglobal.scholarx.model.Mentee; import org.sefglobal.scholarx.model.Mentor; +import org.sefglobal.scholarx.model.Profile; import org.sefglobal.scholarx.model.Program; +import org.sefglobal.scholarx.model.SentEmail; +import org.sefglobal.scholarx.repository.EmailRepository; import org.sefglobal.scholarx.repository.MenteeRepository; import org.sefglobal.scholarx.repository.MentorRepository; +import org.sefglobal.scholarx.repository.ProfileRepository; import org.sefglobal.scholarx.service.EmailService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.mail.MessagingException; import java.io.IOException; @@ -16,12 +22,22 @@ @Component public class ProgramUtil { + private static final Logger log=LoggerFactory.getLogger(ProgramUtil.class); + private final EmailRepository emailRepository; + + public ProgramUtil(EmailRepository emailRepository){ + this.emailRepository = emailRepository; + } + @Autowired MentorRepository mentorRepository; @Autowired MenteeRepository menteeRepository; + @Autowired + ProfileRepository profileRepository; + @Autowired private EmailService emailService; @@ -45,6 +61,14 @@ public void sendMenteeApplicationEmails(long id, Optional program) thro emailService.sendEmail(mentor.getProfile().getEmail(), StringUtils.capitalize(mentor.getState().name()), message, false); + SentEmail email = new SentEmail(); + email.setEmail(mentor.getProfile().getEmail()); + email.setMessage(message); + email.setProgramId(program.get()); + email.setReceiver(mentor.getProfile()); + email.setState(program.get().getState()); + emailRepository.save(email); + } else if (mentor.getState().name().equals("REJECTED")) { message = "Dear " + mentor.getProfile().getFirstName() + ",

" + @@ -57,24 +81,20 @@ public void sendMenteeApplicationEmails(long id, Optional program) thro emailService.sendEmail(mentor.getProfile().getEmail(), StringUtils.capitalize(mentor.getState().name()), message, false); + SentEmail email = new SentEmail(); + email.setEmail(mentor.getProfile().getEmail()); + email.setMessage(message); + email.setProgramId(program.get()); + email.setReceiver(mentor.getProfile()); + email.setState(program.get().getState()); + emailRepository.save(email); + } } } - public void sendMenteeSelectionEmails(long id, Optional program) throws IOException, MessagingException { - List approvedMentors = mentorRepository.findAllByProgramIdAndState(id, EnrolmentState.APPROVED); + public void sendMenteeFiltrationEmails(long id, Optional program) throws MessagingException, IOException { List mentees = getMenteesWithoutDuplicatesByProgramId(id); - - // Notify mentors - for (Mentor mentor : approvedMentors) { - - String message = "Dear " + mentor.getProfile().getFirstName() + ",

" + - "You have student applications waiting to be reviewed. You can approve or reject your mentees " + - "by visiting the ScholarX dashboard."; - - emailService.sendEmail(mentor.getProfile().getEmail(), program.get().getTitle(), message, true); - } - // Notify mentees for (Mentee mentee : mentees) { String message = "Dear " + mentee.getProfile().getFirstName() + ",

" + @@ -85,33 +105,154 @@ public void sendMenteeSelectionEmails(long id, Optional program) throws "for any clarifications."; emailService.sendEmail(mentee.getProfile().getEmail(), program.get().getTitle(), message, false); + + SentEmail email = new SentEmail(); + email.setEmail(mentee.getProfile().getEmail()); + email.setMessage(message); + email.setProgramId(program.get()); + email.setReceiver(mentee.getProfile()); + email.setState(program.get().getState()); + emailRepository.save(email); + } + } + + public void sendMenteeSelectionEmails(long id, Optional program) throws IOException, MessagingException { + List approvedMentors = mentorRepository.findAllByProgramIdAndState(id, EnrolmentState.APPROVED); + // Notify mentors + for (Mentor mentor : approvedMentors) { + + String message = "Dear " + mentor.getProfile().getFirstName() + ",

" + + + "It is with much pleasure we inform you that we have completed the first round of mentor-mentee matching.
" + + "There are a few points that we would like to share with you with regard to the mentee applications.
"+ + "
    "+ + "
  • The minimum word limit for each question of the application was introduced halfway through the application"+ + "period in order to enhance competitiveness. Due to this reason, the applications which were received at the earliest"+ + " stage might contain relatively short answers.
  • "+ + "
  • Mentor-mentee matching process consists of two rounds.
  • "+ + "
  • Some mentors have received an excess number of applications and we have selected potential mentees for those mentors"+ + "after a filtering process. We kindly request you to go through these applications and select the mentees of your choice"+ + "and decline the mentees who are not commendable enough before 28th April 11.59 p.m (IST), so that we can replace them during"+ + "the second round of matching.
  • "+ + "
  • Some mentors have received less than the number of available slots or none, owing to facts such as lack of compatibility"+ + "of subject areas, more mentors representing the same subject area etc. We will be choosing the potential mentees for those mentors"+ + "as well during the second round of matching.

  • "+ + "We appreciate your enthusiasm in being a part of this journey and kindly request your cooperation in completing this matching process as well.
    "+ + "If you have any further queries please don't hesitate to contact us at"+ + "sustainableedufoundation@gmail.com"; + + emailService.sendEmail(mentor.getProfile().getEmail(), program.get().getTitle(), message, true); + + SentEmail email = new SentEmail(); + email.setEmail(mentor.getProfile().getEmail()); + email.setMessage(message); + email.setProgramId(program.get()); + email.setReceiver(mentor.getProfile()); + email.setState(program.get().getState()); + emailRepository.save(email); } } public void sendOnGoingEmails(long id, Optional program) throws IOException, MessagingException { List approvedMentors = mentorRepository.findAllByProgramIdAndState(id, EnrolmentState.APPROVED); + List approvedMentees = menteeRepository.findAllByProgramIdAndState(id, EnrolmentState.APPROVED); + List discardedMentees = menteeRepository.findAllByProgramIdAndState(id, EnrolmentState.FAILED_FROM_WILDCARD); for (Mentor mentor : approvedMentors) { String message = "Dear " + mentor.getProfile().getFirstName() + ",

    " + - "Congratulations!
    Students have accepted you as their mentor. " + + "Congratulations!
    Your list of students is now finalised. " + "You can check your mentees and their contact details by visiting the ScholarX dashboard. " + "Please make the first contact with them as we have instructed them to wait for your email."; + + String logMsg = "Email sent to mentor " + mentor.getProfile().getFirstName() + " " + mentor.getProfile().getLastName() + " " + + "of " + mentor.getProfile().getEmail(); + log.info(logMsg); emailService.sendEmail(mentor.getProfile().getEmail(), program.get().getTitle(), message, true); + + SentEmail email = new SentEmail(); + email.setEmail(mentor.getProfile().getEmail()); + email.setMessage(message); + email.setProgramId(program.get()); + email.setReceiver(mentor.getProfile()); + email.setState(program.get().getState()); + emailRepository.save(email); } - } - public void sendMentorConfirmationEmails(long id, Optional program) throws IOException, MessagingException { - List mentees = getMenteesWithoutDuplicatesByProgramId(id); + for (Mentee mentee: approvedMentees) { + Profile assignedMentor = mentee.getAssignedMentor().getProfile(); + String message = "Dear " + mentee.getProfile().getFirstName() + ",

    " + + "Congratulations!
    You have been accepted as a mentee to be mentored under " + + assignedMentor.getFirstName() + " " + assignedMentor.getLastName() + ".
    " + + "You can check your mentor and their details by visiting the ScholarX dashboard. " + + "Please make sure not to contact your mentor until they do as we have instructed them to " + + "make the first contact.
    "+ + "We will be holding an induction session for all successful ScholarX applicants over the coming " + + "weeks to take you through next steps of the program and answer any questions you may have about " + + "the matching process that was undertaken to enable the mentor-mentee pairing."; - String message = "You can check your mentor by visiting the dashboard"; + String logMsg = "Email sent to mentee " + mentee.getProfile().getFirstName() + " " + mentee.getProfile().getLastName() + " " + + "of " + mentee.getProfile().getEmail(); - for (Mentee mentee : mentees) { + log.info(logMsg); + emailService.sendEmail(mentee.getProfile().getEmail(), program.get().getTitle(), message, true); + + SentEmail email = new SentEmail(); + email.setEmail(mentee.getProfile().getEmail()); + email.setMessage(message); + email.setProgramId(program.get()); + email.setReceiver(mentee.getProfile()); + email.setState(program.get().getState()); + emailRepository.save(email); + } + + for (Mentee mentee: discardedMentees) { + String message = "Dear " + mentee.getProfile().getFirstName() + ",

    " + + "Thank you very much for taking your time to apply for the " + program.get().getTitle() + " program. " + + "However, We regret to inform you that your application couldn't make the cut this time." + + "We encourage you to try again next year and follow us on our social media channels for " + + "future programs. If you have any clarifications, please reach out to us via " + + "sustainableedufoundation@gmail.com" + + "You can check your application details by visiting the ScholarX dashboard."; + + String logMsg = "Email sent to mentee " + mentee.getProfile().getFirstName() + " " + mentee.getProfile().getLastName() + " " + + "of " + mentee.getProfile().getEmail(); + log.info(logMsg); + + emailService.sendEmail(mentee.getProfile().getEmail(), program.get().getTitle(), message, true); + + SentEmail email = new SentEmail(); + email.setEmail(mentee.getProfile().getEmail()); + email.setMessage(message); + email.setProgramId(program.get()); + email.setReceiver(mentee.getProfile()); + email.setState(program.get().getState()); + emailRepository.save(email); } } + public void sendConfirmationEmails(long profileId, Optional program) throws MessagingException, IOException { + Optional profile = profileRepository.findById(profileId); + String message = "Dear " + profile.get().getFirstName() + ",

    " + + "Thank you very much for applying to the " + program.get().getTitle() + " program. Your application has been received. " + + "You can view/edit your application by visiting the ScholarX dashboard. " + + "Reach out to us via " + + "sustainableedufoundation@gmail.com " + + "for any clarifications."; + + emailService.sendEmail(profile.get().getEmail(), program.get().getTitle(), message, true); + + SentEmail email = new SentEmail(); + email.setEmail(profile.get().getEmail()); + email.setMessage(message); + email.setProgramId(program.get()); + email.setReceiver(profile.get()); + email.setState(program.get().getState()); + emailRepository.save(email); + } + /** * Removes mentee duplicates */ diff --git a/src/main/java/org/sefglobal/scholarx/util/QuestionCategory.java b/src/main/java/org/sefglobal/scholarx/util/QuestionCategory.java deleted file mode 100644 index b63f76c7..00000000 --- a/src/main/java/org/sefglobal/scholarx/util/QuestionCategory.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.sefglobal.scholarx.util; - -public enum QuestionCategory { - MENTEE, - MENTOR; -} diff --git a/src/main/resources/application.yml.example b/src/main/resources/application.yml.example index caeb9fff..c4fc815e 100644 --- a/src/main/resources/application.yml.example +++ b/src/main/resources/application.yml.example @@ -21,15 +21,14 @@ spring: user-name-attribute: id email-address-uri: https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~)) jpa: - properties: - hibernate: - dialect: org.hibernate.dialect.MySQL5InnoDBDialect + database: postgresql hibernate: ddl-auto: update datasource: - url: jdbc:mysql://${DB_URL}/${DB_NAME}?allowPublicKeyRetrieval=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8 + url: jdbc:postgresql://${DB_URL}/${DB_NAME}?allowPublicKeyRetrieval=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8 username: ${DB_USER_NAME} password: ${DB_USER_PASSWORD} + platform: postgres mail: host: smtp.gmail.com port: 587 @@ -43,3 +42,9 @@ spring: enable: true jmx: unique-names: true +server: + servlet: + session: + cookie: + max-age: 2d + timeout: 2d diff --git a/src/main/resources/templates/scholarx.html b/src/main/resources/templates/scholarx.html index d0cf81b7..05d7d5a0 100644 --- a/src/main/resources/templates/scholarx.html +++ b/src/main/resources/templates/scholarx.html @@ -108,10 +108,8 @@

    Best regards,
    - Dharana Jayawardane,
    - Program Manager,
    - ScholarX,
    - Sustainable Education Foundation + ScholarX Team,
    + Sustainable Education Foundation.

    View Dashboard + + Join our Slack +

    diff --git a/src/main/test/java/org/sefglobal/scholarx/controller/IntrospectionControllerTest.java b/src/main/test/java/org/sefglobal/scholarx/controller/IntrospectionControllerTest.java deleted file mode 100644 index 8171e5b3..00000000 --- a/src/main/test/java/org/sefglobal/scholarx/controller/IntrospectionControllerTest.java +++ /dev/null @@ -1,177 +0,0 @@ -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; -import org.sefglobal.scholarx.service.IntrospectionService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.test.web.servlet.MockMvc; - -import javax.servlet.http.Cookie; - -import static org.mockito.ArgumentMatchers.any; -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) -public class IntrospectionControllerTest { - @Autowired - private MockMvc mockMvc; - @MockBean - private IntrospectionService introspectionService; - private final Long programId = 1L; - private final Long mentorId = 1L; - private final Cookie profileIdCookie = new Cookie("profileId", "1"); - - @Test - void getLoggedInUser_withValidData_thenReturns200() throws Exception { - mockMvc.perform(get("/me") - .cookie(profileIdCookie)) - .andExpect(status().isOk()); - } - - @Test - void getLoggedInMentor_withUnavailableData_thenReturns404() throws Exception { - doThrow(ResourceNotFoundException.class) - .when(introspectionService) - .getLoggedInUser(anyLong()); - - mockMvc.perform(get("/me") - .cookie(profileIdCookie)) - .andExpect(status().isNotFound()); - } - - @Test - void getLoggedInMentor_withUnsuitableData_thenReturns401() throws Exception { - doThrow(UnauthorizedException.class) - .when(introspectionService) - .getLoggedInUser(anyLong()); - - mockMvc.perform(get("/me") - .cookie(profileIdCookie)) - .andExpect(status().isUnauthorized()); - } - - @Test - void getMenteeingPrograms_withValidData_thenReturns200() throws Exception { - mockMvc.perform(get("/me/programs/mentee") - .cookie(profileIdCookie)) - .andExpect(status().isOk()); - } - - @Test - void getMenteeingPrograms_withUnavailableData_thenReturns404() throws Exception { - doThrow(ResourceNotFoundException.class) - .when(introspectionService) - .getMenteeingPrograms(anyLong()); - - mockMvc.perform(get("/me/programs/mentee") - .cookie(profileIdCookie)) - .andExpect(status().isNotFound()); - } - - @Test - void getMenteeingPrograms_withUnavailableData_thenReturns204() throws Exception { - doThrow(NoContentException.class) - .when(introspectionService) - .getMenteeingPrograms(anyLong()); - - mockMvc.perform(get("/me/programs/mentee") - .cookie(profileIdCookie)) - .andExpect(status().isNoContent()); - } - - @Test - void getMentoringPrograms_withValidData_thenReturns200() throws Exception { - mockMvc.perform(get("/me/programs/mentor") - .cookie(profileIdCookie)) - .andExpect(status().isOk()); - } - - @Test - void getMentoringPrograms_withUnavailableData_thenReturns404() throws Exception { - doThrow(ResourceNotFoundException.class) - .when(introspectionService) - .getMentoringPrograms(anyLong()); - - mockMvc.perform(get("/me/programs/mentor") - .cookie(profileIdCookie)) - .andExpect(status().isNotFound()); - } - - @Test - void getMentoringPrograms_withUnavailableData_thenReturns204() throws Exception { - doThrow(NoContentException.class) - .when(introspectionService) - .getMentoringPrograms(anyLong()); - - mockMvc.perform(get("/me/programs/mentor") - .cookie(profileIdCookie)) - .andExpect(status().isNoContent()); - } - - @Test - void getMentees_withValidData_thenReturns200() throws Exception { - mockMvc.perform(get("/me/programs/{id}/mentees", programId) - .cookie(profileIdCookie)) - .andExpect(status().isOk()); - } - - @Test - void getMentees_withUnavailableData_thenReturns404() throws Exception { - doThrow(ResourceNotFoundException.class) - .when(introspectionService) - .getMentees(anyLong(), anyLong(), any()); - - mockMvc.perform(get("/me/programs/{id}/mentees", programId) - .cookie(profileIdCookie)) - .andExpect(status().isNotFound()); - } - - @Test - void getMentees_withUnavailableData_thenReturns204() throws Exception { - doThrow(NoContentException.class) - .when(introspectionService) - .getMentees(anyLong(), anyLong(), any()); - - mockMvc.perform(get("/me/programs/{id}/mentees", programId) - .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()); - } -} diff --git a/src/main/test/java/org/sefglobal/scholarx/controller/MenteeControllerTest.java b/src/main/test/java/org/sefglobal/scholarx/controller/MenteeControllerTest.java deleted file mode 100644 index fe110ed1..00000000 --- a/src/main/test/java/org/sefglobal/scholarx/controller/MenteeControllerTest.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.sefglobal.scholarx.controller; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Test; -import org.sefglobal.scholarx.controller.admin.MenteeController; -import org.sefglobal.scholarx.exception.BadRequestException; -import org.sefglobal.scholarx.exception.ResourceNotFoundException; -import org.sefglobal.scholarx.service.MenteeService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.test.web.servlet.MockMvc; - -import java.util.HashMap; -import java.util.Map; - -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.doThrow; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@WebMvcTest(controllers = {MenteeController.class, org.sefglobal.scholarx.controller.MenteeController.class}) -public class MenteeControllerTest { - @Autowired - private MockMvc mockMvc; - @Autowired - private ObjectMapper objectMapper; - @MockBean - private MenteeService menteeService; - private final Long menteeId = 1L; - - @Test - void deleteMentee_withValidData_thenReturns204() throws Exception { - mockMvc.perform(delete("/admin/mentees/{id}", menteeId)) - .andExpect(status().isNoContent()); - } - - @Test - void deleteMentee_withUnavailableData_thenReturns404() throws Exception { - doThrow(ResourceNotFoundException.class) - .when(menteeService) - .deleteMentee(anyLong()); - - mockMvc.perform(delete("/admin/mentees/{id}", menteeId)) - .andExpect(status().isNotFound()); - } - - @Test - void approveOrRejectMentee_withValidData_thenReturns200() throws Exception { - Map payload = new HashMap<>(); - payload.put("isApproved", true); - mockMvc.perform(put("/mentees/{menteeId}/state", menteeId) - .contentType("application/json") - .content(objectMapper.writeValueAsString(payload))) - .andExpect(status().isOk()); - } - - @Test - void approveOrRejectMentee_withUnavailableData_thenReturn404() throws Exception { - Map payload = new HashMap<>(); - payload.put("isApproved", true); - doThrow(ResourceNotFoundException.class) - .when(menteeService) - .approveOrRejectMentee(anyLong(), anyBoolean()); - - mockMvc.perform(put("/mentees/{menteeId}/state", menteeId) - .contentType("application/json") - .content(objectMapper.writeValueAsString(payload))) - .andExpect(status().isNotFound()); - } - - @Test - void approveOrRejectMentee_withUnsuitableData_thenReturn400() throws Exception { - Map payload = new HashMap<>(); - payload.put("isApproved", true); - doThrow(BadRequestException.class) - .when(menteeService) - .approveOrRejectMentee(anyLong(), anyBoolean()); - - mockMvc.perform(put("/mentees/{menteeId}/state", menteeId) - .contentType("application/json") - .content(objectMapper.writeValueAsString(payload))) - .andExpect(status().isBadRequest()); - } -} diff --git a/src/main/test/java/org/sefglobal/scholarx/controller/MentorControllerTest.java b/src/main/test/java/org/sefglobal/scholarx/controller/MentorControllerTest.java deleted file mode 100644 index 827f354b..00000000 --- a/src/main/test/java/org/sefglobal/scholarx/controller/MentorControllerTest.java +++ /dev/null @@ -1,218 +0,0 @@ -package org.sefglobal.scholarx.controller; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; -import org.sefglobal.scholarx.controller.admin.MentorController; -import org.sefglobal.scholarx.exception.BadRequestException; -import org.sefglobal.scholarx.exception.NoContentException; -import org.sefglobal.scholarx.exception.ResourceNotFoundException; -import org.sefglobal.scholarx.model.Mentee; -import org.sefglobal.scholarx.service.MentorService; -import org.sefglobal.scholarx.util.EnrolmentState; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.test.web.servlet.MockMvc; - -import javax.servlet.http.Cookie; -import java.util.HashMap; -import java.util.Map; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.*; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@WebMvcTest(controllers = {MentorController.class, org.sefglobal.scholarx.controller.MentorController.class}) -public class MentorControllerTest { - @Autowired - private MockMvc mockMvc; - @Autowired - private ObjectMapper objectMapper; - @MockBean - private MentorService mentorService; - private final Long mentorId = 1L; - private final Mentee mentee = - new Mentee("http://scholarx/SCHOLARX-2020/submission"); - final Cookie profileIdCookie = new Cookie("profileId", "1"); - - @Test - void getMentors_withValidData_thenReturns200() throws Exception { - mockMvc.perform(get("/mentors")) - .andExpect(status().isOk()); - } - - @Test - void getMentorById_withValidData_thenReturns200() throws Exception { - mockMvc.perform(get("/mentors/{id}", mentorId)) - .andExpect(status().isOk()); - } - - @Test - void getMentorById_withUnavailableData_thenReturns404() throws Exception { - doThrow(ResourceNotFoundException.class) - .when(mentorService) - .getMentorById(anyLong()); - - mockMvc.perform(get("/mentors/{id}", mentorId)) - .andExpect(status().isNotFound()); - } - - @Test - void updateState_withValidData_thenReturns200() throws Exception { - Map payload = new HashMap<>(); - payload.put("state", EnrolmentState.APPROVED); - mockMvc.perform(put("/admin/mentors/{id}/state", mentorId) - .contentType("application/json") - .content(objectMapper.writeValueAsString(payload))) - .andExpect(status().isOk()); - } - - @Test - void updateState_withUnavailableData_thenReturn404() throws Exception { - Map payload = new HashMap<>(); - payload.put("state", EnrolmentState.APPROVED); - doThrow(ResourceNotFoundException.class) - .when(mentorService) - .updateState(anyLong(), any(EnrolmentState.class)); - - mockMvc.perform(put("/admin/mentors/{id}/state", mentorId) - .contentType("application/json") - .content(objectMapper.writeValueAsString(payload))) - .andExpect(status().isNotFound()); - } - - @Test - void applyAsMentee_withValidData_thenReturns201() throws Exception { - mockMvc.perform(post("/mentors/{id}/mentee", mentorId) - .cookie(profileIdCookie) - .contentType("application/json") - .content(objectMapper.writeValueAsString(mentee))) - .andExpect(status().isCreated()); - } - - @Test - void applyAsMentee_withValidData_thenReturnsValidResponseBody() throws Exception { - mockMvc.perform(post("/mentors/{id}/mentee", mentorId) - .cookie(profileIdCookie) - .contentType("application/json") - .content(objectMapper.writeValueAsString(mentee))) - .andReturn(); - - ArgumentCaptor menteeArgumentCaptor = ArgumentCaptor.forClass(Mentee.class); - verify(mentorService, times(1)).applyAsMentee(anyLong(), anyLong(), menteeArgumentCaptor.capture()); - - mentee.setState(null); - String expectedResponse = objectMapper.writeValueAsString(mentee); - String actualResponse = objectMapper.writeValueAsString(menteeArgumentCaptor.getValue()); - assertThat(actualResponse).isEqualTo(expectedResponse); - } - - @Test - void applyAsMentee_withUnavailableData_thenReturn404() throws Exception { - doThrow(ResourceNotFoundException.class) - .when(mentorService) - .applyAsMentee(anyLong(), anyLong(), any(Mentee.class)); - - mockMvc.perform(post("/mentors/{id}/mentee", mentorId) - .cookie(profileIdCookie) - .contentType("application/json") - .content(objectMapper.writeValueAsString(mentee))) - .andExpect(status().isNotFound()); - } - - @Test - void applyAsMentee_withUnavailableData_thenReturn400() throws Exception { - doThrow(BadRequestException.class) - .when(mentorService) - .applyAsMentee(anyLong(), anyLong(), any(Mentee.class)); - - mockMvc.perform(post("/mentors/{id}/mentee", mentorId) - .cookie(profileIdCookie) - .contentType("application/json") - .content(objectMapper.writeValueAsString(mentee))) - .andExpect(status().isBadRequest()); - } - - @Test - void getMenteesOfMentor_withValidData_thenReturns200() throws Exception { - mockMvc.perform(get("/mentors/{mentorId}/mentees", mentorId)) - .andExpect(status().isOk()); - } - - @Test - void getMenteesOfMentor_withUnavailableData_thenReturns404() throws Exception { - doThrow(ResourceNotFoundException.class) - .when(mentorService) - .getAllMenteesOfMentor(anyLong(), any()); - - mockMvc.perform(get("/mentors/{mentorId}/mentees", mentorId)) - .andExpect(status().isNotFound()); - } - - @Test - void getMenteesOfMentor_withUnsuitableData_thenReturns400() throws Exception { - doThrow(BadRequestException.class) - .when(mentorService) - .getAllMenteesOfMentor(anyLong(), any()); - - mockMvc.perform(get("/mentors/{mentorId}/mentees", mentorId)) - .andExpect(status().isBadRequest()); - } - - @Test - void updateMenteeData_withValidData_thenReturns200() throws Exception { - mockMvc.perform(put("/mentors/{mentorId}/mentee", mentorId) - .cookie(profileIdCookie) - .contentType("application/json") - .content(objectMapper.writeValueAsString(mentee))) - .andExpect(status().isOk()); - } - - @Test - void updateMenteeData_withUnavailableData_thenReturn404() throws Exception { - doThrow(ResourceNotFoundException.class) - .when(mentorService) - .updateMenteeData(anyLong(), anyLong(), any(Mentee.class)); - - mockMvc.perform(put("/mentors/{mentorId}/mentee", mentorId) - .cookie(profileIdCookie) - .contentType("application/json") - .content(objectMapper.writeValueAsString(mentee))) - .andExpect(status().isNotFound()); - } - - @Test - void updateMenteeData_withUnsuitableData_thenReturn400() throws Exception { - doThrow(BadRequestException.class) - .when(mentorService) - .updateMenteeData(anyLong(), anyLong(), any(Mentee.class)); - - mockMvc.perform(put("/mentors/{mentorId}/mentee", mentorId) - .cookie(profileIdCookie) - .contentType("application/json") - .content(objectMapper.writeValueAsString(mentee))) - .andExpect(status().isBadRequest()); - } - - @Test - void getLoggedInMentee_withValidData_thenReturns200() throws Exception { - mockMvc.perform(get("/mentors/{mentorId}/mentee", mentorId) - .cookie(profileIdCookie)) - .andExpect(status().isOk()); - } - - @Test - void getLoggedInMentee_withUnavailableData_thenReturns204() throws Exception { - doThrow(NoContentException.class) - .when(mentorService) - .getLoggedInMentee(anyLong(), anyLong()); - - mockMvc.perform(get("/mentors/{mentorId}/mentee", mentorId) - .cookie(profileIdCookie)) - .andExpect(status().isNoContent()); - } -} diff --git a/src/main/test/java/org/sefglobal/scholarx/controller/ProgramControllerTest.java b/src/main/test/java/org/sefglobal/scholarx/controller/ProgramControllerTest.java deleted file mode 100644 index e27ead6f..00000000 --- a/src/main/test/java/org/sefglobal/scholarx/controller/ProgramControllerTest.java +++ /dev/null @@ -1,306 +0,0 @@ -package org.sefglobal.scholarx.controller; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; -import org.sefglobal.scholarx.controller.admin.ProgramController; -import org.sefglobal.scholarx.exception.BadRequestException; -import org.sefglobal.scholarx.exception.NoContentException; -import org.sefglobal.scholarx.exception.ResourceNotFoundException; -import org.sefglobal.scholarx.model.Mentor; -import org.sefglobal.scholarx.model.Program; -import org.sefglobal.scholarx.service.ProgramService; -import org.sefglobal.scholarx.util.ProgramState; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.test.web.servlet.MockMvc; - -import javax.servlet.http.Cookie; - -import java.util.ArrayList; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.*; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@WebMvcTest(controllers = {ProgramController.class, org.sefglobal.scholarx.controller.ProgramController.class}) -public class ProgramControllerTest { - @Autowired - private MockMvc mockMvc; - @Autowired - private ObjectMapper objectMapper; - @MockBean - private ProgramService programService; - private final Long programId = 1L; - private final Program program - = new Program("SCHOLARX-2020", - "SCHOLARX program of 2020", - "http://scholarx/images/SCHOLARX-2020", - "http://scholarx/SCHOLARX-2020/home", - ProgramState.CREATED); - private final Mentor mentor - = new Mentor("Sample application", - "Sample prerequisites"); - final Cookie profileIdCookie = new Cookie("profileId", "1"); - - @Test - void addProgram_withValidData_thenReturns201() throws Exception { - mockMvc.perform(post("/admin/programs") - .contentType("application/json") - .content(objectMapper.writeValueAsString(program))) - .andExpect(status().isCreated()); - } - - @Test - void addProgram_withValidData_thenReturnsValidResponseBody() throws Exception { - mockMvc.perform(post("/admin/programs") - .contentType("application/json") - .content(objectMapper.writeValueAsString(program))) - .andReturn(); - - ArgumentCaptor programCaptor = ArgumentCaptor.forClass(Program.class); - verify(programService, times(1)).addProgram(programCaptor.capture()); - - program.setState(null); - String expectedResponse = objectMapper.writeValueAsString(program); - String actualResponse = objectMapper.writeValueAsString(programCaptor.getValue()); - assertThat(actualResponse).isEqualTo(expectedResponse); - } - - @Test - void updateState_withValidData_thenReturns200() throws Exception { - mockMvc.perform(put("/admin/programs/{id}/state", programId) - .contentType("application/json") - .content(objectMapper.writeValueAsString(program.getState()))) - .andExpect(status().isOk()); - } - - @Test - void updateState_withUnavailableData_thenReturn404() throws Exception { - doThrow(ResourceNotFoundException.class) - .when(programService) - .updateState(anyLong()); - - mockMvc.perform(put("/admin/programs/{id}/state", programId) - .contentType("application/json") - .content(objectMapper.writeValueAsString(program.getState()))) - .andExpect(status().isNotFound()); - } - - @Test - void updateProgram_withValidData_thenReturns200() throws Exception { - mockMvc.perform(put("/admin/programs/{id}", programId) - .contentType("application/json") - .content(objectMapper.writeValueAsString(program))) - .andExpect(status().isOk()); - } - - @Test - void updateProgram_withUnavailableData_thenReturn404() throws Exception { - doThrow(ResourceNotFoundException.class) - .when(programService) - .updateProgram(anyLong(), any(Program.class)); - - mockMvc.perform(put("/admin/programs/{id}", programId) - .contentType("application/json") - .content(objectMapper.writeValueAsString(program))) - .andExpect(status().isNotFound()); - } - - @Test - void deleteProgram_withValidData_thenReturns204() throws Exception { - mockMvc.perform(delete("/admin/programs/{id}", programId)) - .andExpect(status().isNoContent()); - } - - @Test - void deleteProgram_withUnavailableData_thenReturn404() throws Exception { - doThrow(ResourceNotFoundException.class) - .when(programService) - .deleteProgram(anyLong()); - - mockMvc.perform(delete("/admin/programs/{id}", programId)) - .andExpect(status().isNotFound()); - } - - @Test - void getPrograms_withValidData_thenReturns200() throws Exception { - mockMvc.perform(get("/programs")) - .andExpect(status().isOk()); - } - - @Test - void getProgramById_withValidData_thenReturns200() throws Exception { - mockMvc.perform(get("/programs/{id}", programId)) - .andExpect(status().isOk()); - } - - @Test - void getProgramById_withUnavailableData_thenReturns404() throws Exception { - doThrow(ResourceNotFoundException.class) - .when(programService) - .getProgramById(anyLong()); - - mockMvc.perform(get("/programs/{id}", programId)) - .andExpect(status().isNotFound()); - } - - @Test - void getAllMentorsByProgramId_withValidData_thenReturns200() throws Exception { - mockMvc.perform(get("/programs/{id}/mentors", programId)) - .andExpect(status().isOk()); - } - - @Test - void getAllMentorsByProgramId_withUnavailableData_thenReturns404() throws Exception { - doThrow(ResourceNotFoundException.class) - .when(programService) - .getAllMentorsByProgramId(anyLong(), any()); - - mockMvc.perform(get("/programs/{id}/mentors", programId)) - .andExpect(status().isNotFound()); - } - - @Test - void applyAsMentor_withValidData_thenReturns201() throws Exception { - mockMvc.perform(post("/programs/{id}/mentor", programId) - .cookie(profileIdCookie) - .contentType("application/json") - .content(objectMapper.writeValueAsString(mentor))) - .andExpect(status().isCreated()); - } - - @Test - void applyAsMentor_withValidData_thenReturnsValidResponseBody() throws Exception { - mockMvc.perform(post("/programs/{id}/mentor", programId) - .cookie(profileIdCookie) - .contentType("application/json") - .content(objectMapper.writeValueAsString(mentor))) - .andReturn(); - - ArgumentCaptor mentorArgumentCaptor = ArgumentCaptor.forClass(Mentor.class); - verify(programService, times(1)).applyAsMentor(anyLong(), anyLong(), mentorArgumentCaptor.capture()); - - mentor.setState(null); - String expectedResponse = objectMapper.writeValueAsString(mentor); - String actualResponse = objectMapper.writeValueAsString(mentorArgumentCaptor.getValue()); - assertThat(actualResponse).isEqualTo(expectedResponse); - } - - @Test - void applyAsMentor_withUnavailableData_thenReturn404() throws Exception { - doThrow(ResourceNotFoundException.class) - .when(programService) - .applyAsMentor(anyLong(), anyLong(), any(Mentor.class)); - - mockMvc.perform(post("/programs/{id}/mentor", programId) - .cookie(profileIdCookie) - .contentType("application/json") - .content(objectMapper.writeValueAsString(mentor))) - .andExpect(status().isNotFound()); - } - - @Test - void applyAsMentor_withUnavailableData_thenReturn400() throws Exception { - doThrow(BadRequestException.class) - .when(programService) - .applyAsMentor(anyLong(), anyLong(), any(Mentor.class)); - - mockMvc.perform(post("/programs/{id}/mentor", programId) - .cookie(profileIdCookie) - .contentType("application/json") - .content(objectMapper.writeValueAsString(mentor))) - .andExpect(status().isBadRequest()); - } - - @Test - void getLoggedInMentor_withValidData_thenReturns200() throws Exception { - mockMvc.perform(get("/programs/{id}/mentor", programId) - .cookie(profileIdCookie)) - .andExpect(status().isOk()); - } - - @Test - void getLoggedInMentor_withUnavailableData_thenReturns404() throws Exception { - doThrow(ResourceNotFoundException.class) - .when(programService) - .getLoggedInMentor(anyLong(), anyLong()); - - mockMvc.perform(get("/programs/{id}/mentor", programId) - .cookie(profileIdCookie)) - .andExpect(status().isNotFound()); - } - - @Test - void updateMentorData_withValidData_thenReturns200() throws Exception { - mockMvc.perform(put("/programs/{programId}/application", programId) - .cookie(profileIdCookie) - .contentType("application/json") - .content(objectMapper.writeValueAsString(mentor))) - .andExpect(status().isOk()); - } - - @Test - void updateMentorData_withUnavailableData_thenReturn404() throws Exception { - doThrow(ResourceNotFoundException.class) - .when(programService) - .updateMentorData(anyLong(), anyLong(), any(Mentor.class)); - - mockMvc.perform(put("/programs/{programId}/application", programId) - .cookie(profileIdCookie) - .contentType("application/json") - .content(objectMapper.writeValueAsString(mentor))) - .andExpect(status().isNotFound()); - } - - @Test - void getAppliedMentors_withValidData_thenReturns200() throws Exception { - mockMvc.perform(get("/programs/{id}/mentee/mentors", programId) - .cookie(profileIdCookie)) - .andExpect(status().isOk()); - } - - @Test - void getAppliedMentors_withUnavailableData_thenReturns204() throws Exception { - doThrow(NoContentException.class) - .when(programService) - .getAppliedMentorsOfMentee(anyLong(), any(), anyLong()); - - mockMvc.perform(get("/programs/{id}/mentee/mentors", programId) - .cookie(profileIdCookie)) - .andExpect(status().isNoContent()); - } - - @Test - void getSelectedMentor_withValidData_thenReturns200() throws Exception { - mockMvc.perform(get("/programs/{id}/mentee/mentor", programId) - .cookie(profileIdCookie)) - .andExpect(status().isOk()); - } - - @Test - void getSelectedMentor_withUnavailableData_thenReturns404() throws Exception { - doThrow(ResourceNotFoundException.class) - .when(programService) - .getSelectedMentor(anyLong(), anyLong()); - - mockMvc.perform(get("/programs/{id}/mentee/mentor", programId) - .cookie(profileIdCookie)) - .andExpect(status().isNotFound()); - } - - @Test - void getSelectedMentor_withUnavailableData_thenReturns204() throws Exception { - doThrow(NoContentException.class) - .when(programService) - .getSelectedMentor(anyLong(), anyLong()); - - mockMvc.perform(get("/programs/{id}/mentee/mentor", programId) - .cookie(profileIdCookie)) - .andExpect(status().isNoContent()); - } -} diff --git a/src/main/test/java/org/sefglobal/scholarx/service/MenteeServiceTest.java b/src/main/test/java/org/sefglobal/scholarx/service/MenteeServiceTest.java deleted file mode 100644 index 45c6ff6c..00000000 --- a/src/main/test/java/org/sefglobal/scholarx/service/MenteeServiceTest.java +++ /dev/null @@ -1,94 +0,0 @@ -package org.sefglobal.scholarx.service; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -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.ResourceNotFoundException; -import org.sefglobal.scholarx.model.Mentee; -import org.sefglobal.scholarx.model.Mentor; -import org.sefglobal.scholarx.repository.MenteeRepository; -import org.sefglobal.scholarx.util.EnrolmentState; - -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.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.doReturn; - -@ExtendWith(MockitoExtension.class) -public class MenteeServiceTest { - @Mock - private MenteeRepository menteeRepository; - @InjectMocks - private MenteeService menteeService; - private final Long menteeId = 1L; - private final Mentor mentor = - new Mentor("Sample application", - "Sample prerequisites"); - - @Test - void deleteMentee_withUnavailableData_thenThrowResourceNotFound() { - doReturn(Optional.empty()) - .when(menteeRepository) - .findById(anyLong()); - - Throwable thrown = catchThrowable( - () -> menteeService.deleteMentee(menteeId)); - assertThat(thrown) - .isInstanceOf(ResourceNotFoundException.class) - .hasMessage("Error, Mentee with id: 1 cannot be deleted. " + - "Mentee doesn't exist."); - } - - @Test - void approveOrRejectMentee_withValidData_thenReturnUpdatedData() - throws ResourceNotFoundException, BadRequestException { - final Mentee mentee = new Mentee(); - mentee.setState(EnrolmentState.PENDING); - doReturn(Optional.of(mentee)) - .when(menteeRepository) - .findById(anyLong()); - doReturn(mentee) - .when(menteeRepository) - .save(any(Mentee.class)); - - Mentee savedMentee = menteeService.approveOrRejectMentee(menteeId, true); - assertThat(savedMentee).isNotNull(); - assertThat(savedMentee.getState()).isEqualTo(EnrolmentState.APPROVED); - } - - @Test - void approveOrRejectMentee_withUnavailableData_thenThrowResourceNotFound() { - doReturn(Optional.empty()) - .when(menteeRepository) - .findById(anyLong()); - - Throwable thrown = catchThrowable( - () -> menteeService.approveOrRejectMentee(menteeId, true)); - assertThat(thrown) - .isInstanceOf(ResourceNotFoundException.class) - .hasMessage("Error, Mentee cannot be approved/rejected. " + - "Mentee with id: 1 doesn't exist."); - } - - @Test - void approveOrRejectMentee_withUnsuitableData_thenThrowBadRequest() { - final Mentee mentee = new Mentee(); - mentee.setState(EnrolmentState.REMOVED); - doReturn(Optional.of(mentee)) - .when(menteeRepository) - .findById(anyLong()); - - Throwable thrown = catchThrowable( - () -> menteeService.approveOrRejectMentee(menteeId, true)); - assertThat(thrown) - .isInstanceOf(BadRequestException.class) - .hasMessage("Error, Mentee cannot be approved/rejected. " + - "Mentee with id: 1 is removed."); - } -} diff --git a/src/test/java/org/sefglobal/scholarx/controller/AuthUserControllerTest.java b/src/test/java/org/sefglobal/scholarx/controller/AuthUserControllerTest.java new file mode 100644 index 00000000..cb488205 --- /dev/null +++ b/src/test/java/org/sefglobal/scholarx/controller/AuthUserControllerTest.java @@ -0,0 +1,137 @@ +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.model.Profile; +import org.sefglobal.scholarx.service.IntrospectionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.doThrow; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication; +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 = AuthUserController.class) +public class AuthUserControllerTest { + @Autowired + private MockMvc mockMvc; + @MockBean + private IntrospectionService introspectionService; + private final Long programId = 1L; + private final Long mentorId = 1L; + + public static Authentication getOauthAuthentication() { + Profile profile = new Profile(); + profile.setId(1); + profile.setFirstName("John"); + profile.setLastName("Doe"); + return new OAuth2AuthenticationToken(profile, null, "linkedin"); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getMenteeingPrograms_withValidData_thenReturns200() throws Exception { + mockMvc.perform(get("/api/me/programs/mentee") + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isOk()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getMenteeingPrograms_withUnavailableData_thenReturns404() throws Exception { + doThrow(ResourceNotFoundException.class) + .when(introspectionService) + .getMenteeingPrograms(anyLong()); + + mockMvc.perform(get("/api/me/programs/mentee") + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isNotFound()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getMenteeingPrograms_withUnavailableData_thenReturns204() throws Exception { + doThrow(NoContentException.class) + .when(introspectionService) + .getMenteeingPrograms(anyLong()); + + mockMvc.perform(get("/api/me/programs/mentee") + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isNoContent()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getMentoringPrograms_withValidData_thenReturns200() throws Exception { + mockMvc.perform(get("/api/me/programs/mentor") + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isOk()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getMentoringPrograms_withUnavailableData_thenReturns404() throws Exception { + doThrow(ResourceNotFoundException.class) + .when(introspectionService) + .getMentoringPrograms(anyLong(), any()); + + mockMvc.perform(get("/api/me/programs/mentor") + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isNotFound()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getMentoringPrograms_withUnavailableData_thenReturns204() throws Exception { + doThrow(NoContentException.class) + .when(introspectionService) + .getMentoringPrograms(anyLong(), any()); + + mockMvc.perform(get("/api/me/programs/mentor") + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isNoContent()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getMentees_withValidData_thenReturns200() throws Exception { + mockMvc.perform(get("/api/me/programs/{id}/mentees", programId) + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isOk()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getMentees_withUnavailableData_thenReturns404() throws Exception { + doThrow(ResourceNotFoundException.class) + .when(introspectionService) + .getMentees(anyLong(), anyLong(), any()); + + mockMvc.perform(get("/api/me/programs/{id}/mentees", programId) + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isNotFound()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getMentees_withUnavailableData_thenReturns204() throws Exception { + doThrow(NoContentException.class) + .when(introspectionService) + .getMentees(anyLong(), anyLong(), any()); + + mockMvc.perform(get("/api/me/programs/{id}/mentees", programId) + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isNoContent()); + } +} diff --git a/src/test/java/org/sefglobal/scholarx/controller/MenteeControllerTest.java b/src/test/java/org/sefglobal/scholarx/controller/MenteeControllerTest.java new file mode 100644 index 00000000..66b5ca08 --- /dev/null +++ b/src/test/java/org/sefglobal/scholarx/controller/MenteeControllerTest.java @@ -0,0 +1,252 @@ +package org.sefglobal.scholarx.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.sefglobal.scholarx.exception.BadRequestException; +import org.sefglobal.scholarx.exception.ResourceNotFoundException; +import org.sefglobal.scholarx.exception.UnauthorizedException; +import org.sefglobal.scholarx.model.Comment; +import org.sefglobal.scholarx.model.Profile; +import org.sefglobal.scholarx.service.MenteeService; +import org.sefglobal.scholarx.service.CommentService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; + +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.*; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(controllers = {MenteeController.class, org.sefglobal.scholarx.controller.admin.MenteeController.class}) +public class MenteeControllerTest { + @Autowired + private MockMvc mockMvc; + @Autowired + private ObjectMapper objectMapper; + @MockBean + private MenteeService menteeService; + @MockBean + private CommentService commentService; + private final Long menteeId = 1L; + private final Long mentorId = 1L; + private final Long commentId = 1L; + + private final Comment comment = new Comment(); + + + public static Authentication getOauthAuthentication() { + Profile profile = new Profile(); + profile.setId(1); + profile.setFirstName("John"); + profile.setLastName("Doe"); + return new OAuth2AuthenticationToken(profile, null, "linkedin"); + } + + @Test + @WithMockUser(username = "admin", authorities = {"ADMIN"}) + void deleteMentee_withValidData_thenReturns204() throws Exception { + mockMvc.perform(delete("/api/admin/mentees/{id}", menteeId)) + .andExpect(status().isNoContent()); + } + + @Test + @WithMockUser(username = "admin", authorities = {"ADMIN"}) + void deleteMentee_withUnavailableData_thenReturns404() throws Exception { + doThrow(ResourceNotFoundException.class) + .when(menteeService) + .deleteMentee(anyLong()); + + mockMvc.perform(delete("/api/admin/mentees/{id}", menteeId)) + .andExpect(status().isNotFound()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void approveOrRejectMentee_withValidData_thenReturns200() throws Exception { + Map payload = new HashMap<>(); + payload.put("isApproved", true); + mockMvc.perform(put("/api/mentees/{menteeId}/state", menteeId) + .contentType("application/json") + .content(objectMapper.writeValueAsString(payload)) + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isOk()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void approveOrRejectMentee_withUnavailableData_thenReturn404() throws Exception { + Map payload = new HashMap<>(); + payload.put("isApproved", true); + doThrow(ResourceNotFoundException.class) + .when(menteeService) + .approveOrRejectMentee(anyLong(), anyLong(), anyBoolean()); + + mockMvc.perform(put("/api/mentees/{menteeId}/state", menteeId) + .contentType("application/json") + .content(objectMapper.writeValueAsString(payload)) + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isNotFound()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void approveOrRejectMentee_withUnsuitableData_thenReturn403() throws Exception { + Map payload = new HashMap<>(); + payload.put("isApproved", true); + doThrow(UnauthorizedException.class) + .when(menteeService) + .approveOrRejectMentee(anyLong(), anyLong(), anyBoolean()); + + mockMvc.perform(put("/api/mentees/{menteeId}/state", menteeId) + .contentType("application/json") + .content(objectMapper.writeValueAsString(payload)) + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isUnauthorized()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void approveOrRejectMentee_withUnsuitableData_thenReturn400() throws Exception { + Map payload = new HashMap<>(); + payload.put("isApproved", true); + doThrow(BadRequestException.class) + .when(menteeService) + .approveOrRejectMentee(anyLong(), anyLong(), anyBoolean()); + + mockMvc.perform(put("/api/mentees/{menteeId}/state", menteeId) + .contentType("application/json") + .content(objectMapper.writeValueAsString(payload)) + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isBadRequest()); + } + + @Test + @WithMockUser(username = "user", authorities = {"ADMIN"}) + void updateAssignedMentor_withValidData_thenReturns200() throws Exception { + Map payload = new HashMap<>(); + payload.put("mentorId", mentorId); + mockMvc.perform(put("/api/admin/mentees/{menteeId}/assign", menteeId) + .contentType("application/json") + .content(objectMapper.writeValueAsString(payload))) + .andExpect(status().isOk()); + } + + @Test + @WithMockUser(username = "user", authorities = {"ADMIN"}) + void updateAssignedMentor_withUnavailableData_thenReturns404() throws Exception { + Map payload = new HashMap<>(); + payload.put("mentorId", mentorId); + doThrow(ResourceNotFoundException.class) + .when(menteeService) + .updateAssignedMentor(anyLong(), anyLong()); + + mockMvc.perform(put("/api/admin/mentees/{menteeId}/assign", menteeId) + .contentType("application/json") + .content(objectMapper.writeValueAsString(payload))) + .andExpect(status().isNotFound()); + } + + @Test + @WithMockUser(username = "user", authorities = {"ADMIN"}) + void updateAssignedMentor_withUnsuitableData_thenReturns400() throws Exception { + Map payload = new HashMap<>(); + payload.put("mentorId", mentorId); + doThrow(BadRequestException.class) + .when(menteeService) + .updateAssignedMentor(anyLong(), anyLong()); + + mockMvc.perform(put("/api/admin/mentees/{menteeId}/assign", menteeId) + .contentType("application/json") + .content(objectMapper.writeValueAsString(payload))) + .andExpect(status().isBadRequest()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void addComment_withValidData_thenReturn201() throws Exception { + mockMvc.perform(post("/api/mentees/{id}/comments",menteeId) + .with(authentication(getOauthAuthentication())) + .contentType("application/json") + .content(objectMapper.writeValueAsString(comment))) + .andExpect(status().isCreated()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void addComment_withValidData_thenReturnsValidResponseBody() throws Exception { + mockMvc.perform(post("/api/mentees/{id}/comments",menteeId) + .with(authentication(getOauthAuthentication())) + .contentType("application/json") + .content(objectMapper.writeValueAsString(comment))) + .andReturn(); + + ArgumentCaptor commentCaptor = ArgumentCaptor.forClass(Comment.class); + verify(commentService, times(1)).addMenteeComment(anyLong(),anyLong(),commentCaptor.capture()); + + String expectedResponse = objectMapper.writeValueAsString(comment); + String actualResponse = objectMapper.writeValueAsString(commentCaptor.getValue()); + assertThat(actualResponse).isEqualTo(expectedResponse); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getMenteeComments_withValidData_thenReturns200() throws Exception { + mockMvc.perform(get("/api/mentees/{id}/comments",menteeId) + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isOk()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getMenteeComments_withUnavailableData_thenReturns404() throws Exception { + doThrow(ResourceNotFoundException.class) + .when(commentService) + .getAllMenteeComments(anyLong(),anyLong()); + + mockMvc.perform(get("/api/mentees/{id}/comments", menteeId) + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isNotFound()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void deleteMenteeComment_withValidData_thenReturns204() throws Exception { + mockMvc.perform(delete("/api/mentees//comment/{id}", commentId) + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isNoContent()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void deleteMenteeComment_withUnavailableData_thenReturns404() throws Exception { + doThrow(ResourceNotFoundException.class) + .when(commentService) + .deleteComment(anyLong(),anyLong()); + + mockMvc.perform(delete("/api/mentees//comment/{id}", commentId) + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isNotFound()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void updateComment_withValidData_thenReturns200() throws Exception { + mockMvc.perform(put("/api/mentees/comment/{id}", commentId) + .contentType("application/json") + .with(authentication(getOauthAuthentication())) + .content(objectMapper.writeValueAsString(comment))) + .andExpect(status().isOk()); + } +} diff --git a/src/test/java/org/sefglobal/scholarx/controller/MentorControllerTest.java b/src/test/java/org/sefglobal/scholarx/controller/MentorControllerTest.java new file mode 100644 index 00000000..058757a2 --- /dev/null +++ b/src/test/java/org/sefglobal/scholarx/controller/MentorControllerTest.java @@ -0,0 +1,187 @@ +package org.sefglobal.scholarx.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.sefglobal.scholarx.controller.admin.MentorController; +import org.sefglobal.scholarx.exception.BadRequestException; +import org.sefglobal.scholarx.exception.NoContentException; +import org.sefglobal.scholarx.exception.ResourceNotFoundException; +import org.sefglobal.scholarx.model.Mentee; +import org.sefglobal.scholarx.model.Profile; +import org.sefglobal.scholarx.service.MentorService; +import org.sefglobal.scholarx.util.EnrolmentState; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; + +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.*; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(controllers = {MentorController.class, org.sefglobal.scholarx.controller.MentorController.class}) +public class MentorControllerTest { + @Autowired + private MockMvc mockMvc; + @Autowired + private ObjectMapper objectMapper; + @MockBean + private MentorService mentorService; + private final Long mentorId = 1L; + private final Mentee mentee = new Mentee(); + + public static Authentication getOauthAuthentication() { + Profile profile = new Profile(); + profile.setId(1); + profile.setFirstName("John"); + profile.setLastName("Doe"); + return new OAuth2AuthenticationToken(profile, null, "linkedin"); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getMentors_withValidData_thenReturns200() throws Exception { + mockMvc.perform(get("/api/mentors")) + .andExpect(status().isOk()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getMentorById_withValidData_thenReturns200() throws Exception { + mockMvc.perform(get("/api/mentors/{id}", mentorId)) + .andExpect(status().isOk()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getMentorById_withUnavailableData_thenReturns404() throws Exception { + doThrow(ResourceNotFoundException.class) + .when(mentorService) + .getMentorById(anyLong()); + + mockMvc.perform(get("/api/mentors/{id}", mentorId)) + .andExpect(status().isNotFound()); + } + + @Test + @WithMockUser(username = "admin", authorities = {"ADMIN"}) + void updateState_withValidData_thenReturns200() throws Exception { + Map payload = new HashMap<>(); + payload.put("state", EnrolmentState.APPROVED); + mockMvc.perform(put("/api/admin/mentors/{id}/state", mentorId) + .contentType("application/json") + .content(objectMapper.writeValueAsString(payload))) + .andExpect(status().isOk()); + } + + @Test + @WithMockUser(username = "admin", authorities = {"ADMIN"}) + void updateState_withUnavailableData_thenReturn404() throws Exception { + Map payload = new HashMap<>(); + payload.put("state", EnrolmentState.APPROVED); + doThrow(ResourceNotFoundException.class) + .when(mentorService) + .updateState(anyLong(), any(EnrolmentState.class)); + + mockMvc.perform(put("/api/admin/mentors/{id}/state", mentorId) + .contentType("application/json") + .content(objectMapper.writeValueAsString(payload))) + .andExpect(status().isNotFound()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void applyAsMentee_withValidData_thenReturns201() throws Exception { + mockMvc.perform(post("/api/mentors/{id}/mentee", mentorId) + .with(authentication(getOauthAuthentication())) + .contentType("application/json") + .content(objectMapper.writeValueAsString(mentee))) + .andExpect(status().isCreated()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void applyAsMentee_withValidData_thenReturnsValidResponseBody() throws Exception { + mockMvc.perform(post("/api/mentors/{id}/mentee", mentorId) + .with(authentication(getOauthAuthentication())) + .contentType("application/json") + .content(objectMapper.writeValueAsString(mentee))) + .andReturn(); + + ArgumentCaptor menteeArgumentCaptor = ArgumentCaptor.forClass(Mentee.class); + verify(mentorService, times(1)).applyAsMentee(anyLong(), anyLong(), menteeArgumentCaptor.capture()); + + mentee.setState(null); + String expectedResponse = objectMapper.writeValueAsString(mentee); + String actualResponse = objectMapper.writeValueAsString(menteeArgumentCaptor.getValue()); + assertThat(actualResponse).isEqualTo(expectedResponse); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void applyAsMentee_withUnavailableData_thenReturn404() throws Exception { + doThrow(ResourceNotFoundException.class) + .when(mentorService) + .applyAsMentee(anyLong(), anyLong(), any(Mentee.class)); + + mockMvc.perform(post("/api/mentors/{id}/mentee", mentorId) + .with(authentication(getOauthAuthentication())) + .contentType("application/json") + .content(objectMapper.writeValueAsString(mentee))) + .andExpect(status().isNotFound()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void applyAsMentee_withUnavailableData_thenReturn400() throws Exception { + doThrow(BadRequestException.class) + .when(mentorService) + .applyAsMentee(anyLong(), anyLong(), any(Mentee.class)); + + mockMvc.perform(post("/api/mentors/{id}/mentee", mentorId) + .with(authentication(getOauthAuthentication())) + .contentType("application/json") + .content(objectMapper.writeValueAsString(mentee))) + .andExpect(status().isBadRequest()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getMenteesOfMentor_withValidData_thenReturns200() throws Exception { + mockMvc.perform(get("/api/mentors/{mentorId}/mentees", mentorId)) + .andExpect(status().isOk()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getMenteesOfMentor_withUnavailableData_thenReturns404() throws Exception { + doThrow(ResourceNotFoundException.class) + .when(mentorService) + .getAllMenteesOfMentor(anyLong(), any()); + + mockMvc.perform(get("/api/mentors/{mentorId}/mentees", mentorId)) + .andExpect(status().isNotFound()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getMenteesOfMentor_withUnsuitableData_thenReturns400() throws Exception { + doThrow(BadRequestException.class) + .when(mentorService) + .getAllMenteesOfMentor(anyLong(), any()); + + mockMvc.perform(get("/api/mentors/{mentorId}/mentees", mentorId)) + .andExpect(status().isBadRequest()); + } +} diff --git a/src/test/java/org/sefglobal/scholarx/controller/ProgramControllerTest.java b/src/test/java/org/sefglobal/scholarx/controller/ProgramControllerTest.java new file mode 100644 index 00000000..642a2923 --- /dev/null +++ b/src/test/java/org/sefglobal/scholarx/controller/ProgramControllerTest.java @@ -0,0 +1,379 @@ +package org.sefglobal.scholarx.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.sefglobal.scholarx.controller.admin.ProgramController; +import org.sefglobal.scholarx.exception.BadRequestException; +import org.sefglobal.scholarx.exception.NoContentException; +import org.sefglobal.scholarx.exception.ResourceNotFoundException; +import org.sefglobal.scholarx.model.Mentee; +import org.sefglobal.scholarx.model.Mentor; +import org.sefglobal.scholarx.model.Profile; +import org.sefglobal.scholarx.model.Program; +import org.sefglobal.scholarx.service.ProgramService; +import org.sefglobal.scholarx.util.ProgramState; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.*; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(controllers = {ProgramController.class, org.sefglobal.scholarx.controller.ProgramController.class}) +public class ProgramControllerTest { + @Autowired + private MockMvc mockMvc; + @Autowired + private ObjectMapper objectMapper; + @MockBean + private ProgramService programService; + private final Long programId = 1L; + private final Program program + = new Program("SCHOLARX-2020", + "SCHOLARX program of 2020", + "http://scholarx/images/SCHOLARX-2020", + "http://scholarx/SCHOLARX-2020/home", + ProgramState.CREATED); + private final Mentee mentee = new Mentee(); + + public static Authentication getOauthAuthentication() { + Profile profile = new Profile(); + profile.setId(1); + profile.setFirstName("John"); + profile.setLastName("Doe"); + return new OAuth2AuthenticationToken(profile, null, "linkedin"); + } + + @Test + @WithMockUser(username = "user", authorities = {"ADMIN"}) + void addProgram_withValidData_thenReturns201() throws Exception { + mockMvc.perform(post("/api/admin/programs") + .contentType("application/json") + .content(objectMapper.writeValueAsString(program))) + .andExpect(status().isCreated()); + } + + @Test + @WithMockUser(username = "user", authorities = {"ADMIN"}) + void addProgram_withValidData_thenReturnsValidResponseBody() throws Exception { + mockMvc.perform(post("/api/admin/programs") + .contentType("application/json") + .content(objectMapper.writeValueAsString(program))) + .andReturn(); + + ArgumentCaptor programCaptor = ArgumentCaptor.forClass(Program.class); + verify(programService, times(1)).addProgram(programCaptor.capture()); + + program.setState(null); + String expectedResponse = objectMapper.writeValueAsString(program); + String actualResponse = objectMapper.writeValueAsString(programCaptor.getValue()); + assertThat(actualResponse).isEqualTo(expectedResponse); + } + + @Test + @WithMockUser(username = "user", authorities = {"ADMIN"}) + void updateState_withValidData_thenReturns200() throws Exception { + mockMvc.perform(put("/api/admin/programs/{id}/state", programId) + .contentType("application/json") + .content(objectMapper.writeValueAsString(program.getState()))) + .andExpect(status().isOk()); + } + + @Test + @WithMockUser(username = "user", authorities = {"ADMIN"}) + void updateState_withUnavailableData_thenReturn404() throws Exception { + doThrow(ResourceNotFoundException.class) + .when(programService) + .updateState(anyLong()); + + mockMvc.perform(put("/api/admin/programs/{id}/state", programId) + .contentType("application/json") + .content(objectMapper.writeValueAsString(program.getState()))) + .andExpect(status().isNotFound()); + } + + @Test + @WithMockUser(username = "user", authorities = {"ADMIN"}) + void updateProgram_withValidData_thenReturns200() throws Exception { + mockMvc.perform(put("/api/admin/programs/{id}", programId) + .contentType("application/json") + .content(objectMapper.writeValueAsString(program))) + .andExpect(status().isOk()); + } + + @Test + @WithMockUser(username = "user", authorities = {"ADMIN"}) + void updateProgram_withUnavailableData_thenReturn404() throws Exception { + doThrow(ResourceNotFoundException.class) + .when(programService) + .updateProgram(anyLong(), any(Program.class)); + + mockMvc.perform(put("/api/admin/programs/{id}", programId) + .contentType("application/json") + .content(objectMapper.writeValueAsString(program))) + .andExpect(status().isNotFound()); + } + + @Test + @WithMockUser(username = "user", authorities = {"ADMIN"}) + void deleteProgram_withValidData_thenReturns204() throws Exception { + mockMvc.perform(delete("/api/admin/programs/{id}", programId)) + .andExpect(status().isNoContent()); + } + + @Test + @WithMockUser(username = "user", authorities = {"ADMIN"}) + void deleteProgram_withUnavailableData_thenReturn404() throws Exception { + doThrow(ResourceNotFoundException.class) + .when(programService) + .deleteProgram(anyLong()); + + mockMvc.perform(delete("/api/admin/programs/{id}", programId)) + .andExpect(status().isNotFound()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getPrograms_withValidData_thenReturns200() throws Exception { + mockMvc.perform(get("/api/programs")) + .andExpect(status().isOk()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getProgramById_withValidData_thenReturns200() throws Exception { + mockMvc.perform(get("/api/programs/{id}", programId)) + .andExpect(status().isOk()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getProgramById_withUnavailableData_thenReturns404() throws Exception { + doThrow(ResourceNotFoundException.class) + .when(programService) + .getProgramById(anyLong()); + + mockMvc.perform(get("/api/programs/{id}", programId)) + .andExpect(status().isNotFound()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getAllMentorsByProgramId_withValidData_thenReturns200() throws Exception { + mockMvc.perform(get("/api/programs/{id}/mentors", programId)) + .andExpect(status().isOk()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getAllMentorsByProgramId_withUnavailableData_thenReturns404() throws Exception { + doThrow(ResourceNotFoundException.class) + .when(programService) + .getAllMentorsByProgramId(anyLong(), any()); + + mockMvc.perform(get("/api/programs/{id}/mentors", programId)) + .andExpect(status().isNotFound()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void applyAsMentor_withValidData_thenReturns201() throws Exception { + mockMvc.perform(post("/api/programs/{id}/mentor", programId) + .with(authentication(getOauthAuthentication())) + .contentType("application/json") + .content(objectMapper.writeValueAsString(new Mentor()))) + .andExpect(status().isCreated()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void updateMentorApplication_withValidData_thenReturns200() throws Exception { + mockMvc.perform(put("/api/programs/{id}/mentor", programId) + .with(authentication(getOauthAuthentication())) + .contentType("application/json") + .content(objectMapper.writeValueAsString(new Mentor()))) + .andExpect(status().isOk()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void updateMentorApplication_withUnavailableData_thenReturn404() throws Exception { + doThrow(ResourceNotFoundException.class) + .when(programService) + .updateMentorApplication(anyLong(), anyLong(), any(Mentor.class)); + + mockMvc.perform(put("/api/programs/{id}/mentor", programId) + .with(authentication(getOauthAuthentication())) + .contentType("application/json") + .content(objectMapper.writeValueAsString(new Mentor()))) + .andExpect(status().isNotFound()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void updateMentorApplication_withInvalidData_thenReturn400() throws Exception { + doThrow(BadRequestException.class) + .when(programService) + .updateMentorApplication(anyLong(), anyLong(), any(Mentor.class)); + + mockMvc.perform(put("/api/programs/{id}/mentor", programId) + .with(authentication(getOauthAuthentication())) + .contentType("application/json") + .content(objectMapper.writeValueAsString(new Mentor()))) + .andExpect(status().isBadRequest()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getLoggedInMentor_withValidData_thenReturns200() throws Exception { + mockMvc.perform(get("/api/programs/{id}/mentor", programId) + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isOk()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getLoggedInMentor_withUnavailableData_thenReturns404() throws Exception { + doThrow(ResourceNotFoundException.class) + .when(programService) + .getLoggedInMentor(anyLong(), anyLong()); + + mockMvc.perform(get("/api/programs/{id}/mentor", programId) + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isNotFound()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getAppliedMentors_withValidData_thenReturns200() throws Exception { + mockMvc.perform(get("/api/programs/{id}/mentee/mentors", programId) + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isOk()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getAppliedMentors_withUnavailableData_thenReturns204() throws Exception { + doThrow(NoContentException.class) + .when(programService) + .getAppliedMentorOfMentee(anyLong(), anyLong()); + + mockMvc.perform(get("/api/programs/{id}/mentee/mentors", programId) + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isNoContent()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getSelectedMentor_withValidData_thenReturns200() throws Exception { + mockMvc.perform(get("/api/programs/{id}/mentee/mentor", programId) + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isOk()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getSelectedMentor_withUnavailableData_thenReturns404() throws Exception { + doThrow(ResourceNotFoundException.class) + .when(programService) + .getSelectedMentor(anyLong(), anyLong()); + + mockMvc.perform(get("/api/programs/{id}/mentee/mentor", programId) + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isNotFound()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getSelectedMentor_withUnavailableData_thenReturns204() throws Exception { + doThrow(NoContentException.class) + .when(programService) + .getSelectedMentor(anyLong(), anyLong()); + + mockMvc.perform(get("/api/programs/{id}/mentee/mentor", programId) + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isNoContent()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getAllMenteesByProgramId_withUnavailableData_thenReturns404() throws Exception { + doThrow(ResourceNotFoundException.class) + .when(programService) + .getAllMenteesByProgramId(anyLong()); + + mockMvc.perform(get("/api/programs/{id}/mentees", programId) + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isNotFound()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void updateMenteeData_withUnavailableData_thenReturn404() throws Exception { + doThrow(ResourceNotFoundException.class) + .when(programService) + .updateMenteeData(anyLong(), anyLong(), any(Mentee.class)); + + mockMvc.perform(put("/api/programs/{programId}/mentee", programId) + .with(authentication(getOauthAuthentication())) + .contentType("application/json") + .content(objectMapper.writeValueAsString(mentee))) + .andExpect(status().isNotFound()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void updateMenteeData_withUnsuitableData_thenReturn400() throws Exception { + doThrow(BadRequestException.class) + .when(programService) + .updateMenteeData(anyLong(), anyLong(), any(Mentee.class)); + + mockMvc.perform(put("/api/programs/{programId}/mentee", programId) + .with(authentication(getOauthAuthentication())) + .contentType("application/json") + .content(objectMapper.writeValueAsString(mentee))) + .andExpect(status().isBadRequest()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void updateMenteeData_withValidData_thenReturns200() throws Exception { + mockMvc.perform(put("/api/programs/{programId}/mentee", programId) + .with(authentication(getOauthAuthentication())) + .contentType("application/json") + .content(objectMapper.writeValueAsString(mentee))) + .andExpect(status().isOk()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getLoggedInMentee_withValidData_thenReturns200() throws Exception { + mockMvc.perform(get("/api/programs/{programId}/mentee", programId) + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isOk()); + } + + @Test + @WithMockUser(username = "user", authorities = {"DEFAULT"}) + void getLoggedInMentee_withUnavailableData_thenReturns204() throws Exception { + + doThrow(NoContentException.class) + .when(programService) + .getLoggedInMentee(anyLong(), anyLong()); + + mockMvc.perform(get("/api/programs/{programId}/mentee", programId) + .with(authentication(getOauthAuthentication()))) + .andExpect(status().isNoContent()); + + } +} diff --git a/src/test/java/org/sefglobal/scholarx/service/CommentServiceTest.java b/src/test/java/org/sefglobal/scholarx/service/CommentServiceTest.java new file mode 100644 index 00000000..2718a94f --- /dev/null +++ b/src/test/java/org/sefglobal/scholarx/service/CommentServiceTest.java @@ -0,0 +1,229 @@ +package org.sefglobal.scholarx.service; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.sefglobal.scholarx.exception.ResourceNotFoundException; +import org.sefglobal.scholarx.exception.UnauthorizedException; +import org.sefglobal.scholarx.model.Comment; +import org.sefglobal.scholarx.model.Mentee; +import org.sefglobal.scholarx.model.Mentor; +import org.sefglobal.scholarx.model.Profile; +import org.sefglobal.scholarx.repository.CommentRepository; +import org.sefglobal.scholarx.repository.MenteeRepository; +import org.sefglobal.scholarx.repository.ProfileRepository; +import org.sefglobal.scholarx.util.ProfileType; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; +import static org.mockito.Mockito.doReturn; + +@ExtendWith(MockitoExtension.class) +class CommentServiceTest { + private final Long menteeId = 1L; + private final Long profileId = 1L; + private final Long commentId = 1L; + @Mock + private CommentRepository commentRepository; + @Mock + private ProfileRepository profileRepository; + @Mock + private MenteeRepository menteeRepository; + @InjectMocks + private CommentService commentService; + + @Test + void getAllMenteeCommentsByMenteeId_withAvailableData_thenReturnDataFromRepository() + throws UnauthorizedException, ResourceNotFoundException { + Mentee mentee = new Mentee(); + doReturn(Optional.of(mentee)) + .when(menteeRepository) + .findById(menteeId); + Profile profile = new Profile(); + profile.setType(ProfileType.ADMIN); + doReturn(Optional.of(profile)) + .when(profileRepository) + .findById(profileId); + List comments = new ArrayList<>(); + doReturn(comments).when(commentRepository) + .findAllByMenteeId(menteeId); + List returnedData = commentService.getAllMenteeComments(menteeId, profileId); + assertThat(returnedData).isEqualTo(comments); + } + + @Test + void getAllMenteeCommentsByMenteeId__withUnavailableMenteeId_thenThrowResourceNotFoundException() { + doReturn(Optional.empty()) + .when(menteeRepository) + .findById(menteeId); + Profile profile = new Profile(); + profile.setType(ProfileType.ADMIN); + doReturn(Optional.of(profile)) + .when(profileRepository) + .findById(profileId); + Throwable thrown = catchThrowable( + () -> commentService.getAllMenteeComments(menteeId, profileId)); + assertThat(thrown) + .isInstanceOf(ResourceNotFoundException.class) + .hasMessage("Error, Mentee by id: 1 doesn't exist."); + } + + @Test + void getAllMenteeCommentsByMenteeId__withUnavailableProfileId_thenThrowUnauthorizedException() { + Mentee mentee = new Mentee(); + Profile profile = new Profile(); + profile.setId(2L); + Mentor mentor = new Mentor(); + mentor.setProfile(profile); + mentee.setAssignedMentor(mentor); + doReturn(Optional.of(mentee)) + .when(menteeRepository) + .findById(menteeId); + profile.setType(ProfileType.DEFAULT); + doReturn(Optional.of(profile)) + .when(profileRepository) + .findById(profileId); + Throwable thrown = catchThrowable( + () -> commentService.getAllMenteeComments(menteeId, profileId)); + assertThat(thrown) + .isInstanceOf(UnauthorizedException.class) + .hasMessage("Error, User by id: 1 is not allowed access."); + } + + + @Test + void addMenteeCommentByMenteeIdAndProfileId_withUnavailableMenteeId_thenThrowResourceNotFoundException() { + doReturn(Optional.empty()) + .when(menteeRepository) + .findById(menteeId); + Comment comment = new Comment(); + Throwable thrown = catchThrowable( + () -> commentService.addMenteeComment(menteeId, profileId, comment)); + assertThat(thrown) + .isInstanceOf(ResourceNotFoundException.class) + .hasMessage("Error, Mentee by id: 1 doesn't exist."); + } + + @Test + void addMenteeCommentByMenteeIdAndProfileId_withUnavailableProfileId_thenThrowResourceNotFoundException() { + Mentee mentee = new Mentee(); + doReturn(Optional.of(mentee)) + .when(menteeRepository) + .findById(menteeId); + doReturn(Optional.empty()) + .when(profileRepository) + .findById(profileId); + Comment comment = new Comment(); + Throwable thrown = catchThrowable( + () -> commentService.addMenteeComment(menteeId, profileId, comment)); + assertThat(thrown) + .isInstanceOf(ResourceNotFoundException.class) + .hasMessage("Error, User by id: 1 doesn't exist."); + } + + @Test + void addMenteeCommentByMenteeIdAndProfileId_withUnavailableProfileId_thenThrowUnauthorizedException() { + Mentee mentee = new Mentee(); + Profile profile = new Profile(); + profile.setId(2L); + Mentor mentor = new Mentor(); + mentor.setProfile(profile); + mentee.setAssignedMentor(mentor); + Comment comment = new Comment(); + doReturn(Optional.of(mentee)) + .when(menteeRepository) + .findById(menteeId); + profile.setType(ProfileType.DEFAULT); + doReturn(Optional.of(profile)) + .when(profileRepository) + .findById(profileId); + Throwable thrown = catchThrowable( + () -> commentService.addMenteeComment(menteeId, profileId, comment)); + assertThat(thrown) + .isInstanceOf(UnauthorizedException.class) + .hasMessage("Error, User by id: 1 is not allowed access."); + } + + @Test + void updateCommentWithCommentId_withValidData_thenReturnUpdatedData() + throws UnauthorizedException, ResourceNotFoundException { + Mentee mentee = new Mentee(); + mentee.setId(menteeId); + Profile profile = new Profile(); + profile.setId(profileId); + Comment comment = new Comment(); + comment.setCommented_by(profile); + doReturn(Optional.of(comment)) + .when(commentRepository) + .findById(commentId); + + doReturn(comment) + .when(commentRepository) + .save(comment); + Comment updateComment = commentService.updateComment(commentId, profileId, comment); + assertThat(updateComment).isNotNull(); + } + + @Test + void updateCommentWithCommentId_withUnAvailableData_thenThrowResourceNotFoundException() { + doReturn(Optional.empty()) + .when(commentRepository) + .findById(commentId); + Comment comment = new Comment(); + Throwable thrown = catchThrowable( + () -> commentService.updateComment(commentId, profileId, comment)); + assertThat(thrown) + .isInstanceOf(ResourceNotFoundException.class) + .hasMessage("Error, Comment with id: 1 cannot be updated. Comment doesn't exist."); + } + + @Test + void updateCommentWithCommentId_withUnAvailableData_thenThrowUnauthorizedException() { + Comment comment = new Comment(); + Profile profile = new Profile(); + profile.setId(profileId); + comment.setCommented_by(profile); + doReturn(Optional.of(comment)) + .when(commentRepository) + .findById(commentId); + Throwable thrown = catchThrowable( + () -> commentService.updateComment(commentId, 2L, comment)); + assertThat(thrown) + .isInstanceOf(UnauthorizedException.class) + .hasMessage("Error, User by id: 2 is not allowed access."); + } + + @Test + void deleteComment_withUnavailableData_thenThrowResourceNotFound() { + doReturn(Optional.empty()) + .when(commentRepository) + .findById(commentId); + Throwable thrown = catchThrowable( + () -> commentService.deleteComment(commentId, profileId)); + assertThat(thrown) + .isInstanceOf(ResourceNotFoundException.class) + .hasMessage("Error, Comment with id: 1 cannot be deleted. Comment doesn't exist."); + } + + @Test + void deleteComment_withUnavailableData_thenThrowUnauthorizedException() { + Comment comment = new Comment(); + Profile profile = new Profile(); + profile.setId(profileId); + comment.setCommented_by(profile); + doReturn(Optional.of(comment)) + .when(commentRepository) + .findById(commentId); + Throwable thrown = catchThrowable( + () -> commentService.deleteComment(commentId, 2L)); + assertThat(thrown) + .isInstanceOf(UnauthorizedException.class) + .hasMessage("Error, User by id: 2 is not allowed access."); + } +} diff --git a/src/main/test/java/org/sefglobal/scholarx/service/IntrospectionServiceTest.java b/src/test/java/org/sefglobal/scholarx/service/IntrospectionServiceTest.java similarity index 66% rename from src/main/test/java/org/sefglobal/scholarx/service/IntrospectionServiceTest.java rename to src/test/java/org/sefglobal/scholarx/service/IntrospectionServiceTest.java index 5a03c774..895b9bbe 100644 --- a/src/main/test/java/org/sefglobal/scholarx/service/IntrospectionServiceTest.java +++ b/src/test/java/org/sefglobal/scholarx/service/IntrospectionServiceTest.java @@ -41,8 +41,7 @@ public class IntrospectionServiceTest { 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/"); + private final Mentee mentee = new Mentee(); @Test void getLoggedInUser_withUnavailableData_thenThrowResourceNotFound() { @@ -58,7 +57,7 @@ void getLoggedInUser_withUnavailableData_thenThrowResourceNotFound() { } @Test - void getLoggedInUser_withUnsuitableData_thenThrowResourceNotFound() { + void getLoggedInUser_withUnsuitableData_thenThrowUnauthorized() { Throwable thrown = catchThrowable( () -> introspectionService.getLoggedInUser(-1)); assertThat(thrown) @@ -102,7 +101,7 @@ void getMentoringPrograms_withUnavailableData_thenThrowResourceNotFound() { .existsById(anyLong()); Throwable thrown = catchThrowable( - () -> introspectionService.getMentoringPrograms(profileId)); + () -> introspectionService.getMentoringPrograms(profileId, EnrolmentState.APPROVED)); assertThat(thrown) .isInstanceOf(ResourceNotFoundException.class) .hasMessage("Error, Profile with id: 1 doesn't exist."); @@ -113,12 +112,9 @@ void getMentoringPrograms_withUnavailableData_thenThrowNoContent() { doReturn(true) .when(profileRepository) .existsById(anyLong()); - doReturn(new ArrayList()) - .when(mentorRepository) - .findAllByProfileId(anyLong()); Throwable thrown = catchThrowable( - () -> introspectionService.getMentoringPrograms(profileId)); + () -> introspectionService.getMentoringPrograms(profileId, EnrolmentState.APPROVED)); assertThat(thrown) .isInstanceOf(NoContentException.class) .hasMessage("Error, User has not enrolled in any program as a mentor."); @@ -152,69 +148,4 @@ 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."); - } } diff --git a/src/test/java/org/sefglobal/scholarx/service/MenteeServiceTest.java b/src/test/java/org/sefglobal/scholarx/service/MenteeServiceTest.java new file mode 100644 index 00000000..ba00fe0b --- /dev/null +++ b/src/test/java/org/sefglobal/scholarx/service/MenteeServiceTest.java @@ -0,0 +1,207 @@ +package org.sefglobal.scholarx.service; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +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.ResourceNotFoundException; +import org.sefglobal.scholarx.exception.UnauthorizedException; +import org.sefglobal.scholarx.model.Mentee; +import org.sefglobal.scholarx.model.Mentor; +import org.sefglobal.scholarx.model.Profile; +import org.sefglobal.scholarx.model.Program; +import org.sefglobal.scholarx.repository.MenteeRepository; +import org.sefglobal.scholarx.repository.MentorRepository; +import org.sefglobal.scholarx.util.EnrolmentState; +import org.sefglobal.scholarx.util.ProgramState; + +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.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.doReturn; + +@ExtendWith(MockitoExtension.class) +public class MenteeServiceTest { + @Mock + private MenteeRepository menteeRepository; + @Mock + private MentorRepository mentorRepository; + + @InjectMocks + private MenteeService menteeService; + private final Long menteeId = 1L; + private final Long profileId = 1L; + private final Long mentorId = 1L; + private final Mentor mentor = new Mentor(); + + @Test + void deleteMentee_withUnavailableData_thenThrowResourceNotFound() { + doReturn(Optional.empty()) + .when(menteeRepository) + .findById(anyLong()); + + Throwable thrown = catchThrowable( + () -> menteeService.deleteMentee(menteeId)); + assertThat(thrown) + .isInstanceOf(ResourceNotFoundException.class) + .hasMessage("Error, Mentee with id: 1 cannot be deleted. " + + "Mentee doesn't exist."); + } + + @Test + void approveOrRejectMentee_withValidData_thenReturnUpdatedData() + throws ResourceNotFoundException, BadRequestException, UnauthorizedException { + final Mentee mentee = new Mentee(); + mentee.setState(EnrolmentState.PENDING); + Profile profile = new Profile(); + profile.setId(profileId); + mentor.setProfile(profile); + mentee.setAssignedMentor(mentor); + + doReturn(Optional.of(mentee)) + .when(menteeRepository) + .findById(anyLong()); + doReturn(mentee) + .when(menteeRepository) + .save(any(Mentee.class)); + + Mentee savedMentee = menteeService.approveOrRejectMentee(menteeId, profileId, true); + assertThat(savedMentee).isNotNull(); + assertThat(savedMentee.getState()).isEqualTo(EnrolmentState.APPROVED); + } + + @Test + void approveOrRejectMentee_withUnavailableData_thenThrowResourceNotFound() { + doReturn(Optional.empty()) + .when(menteeRepository) + .findById(anyLong()); + + Throwable thrown = catchThrowable( + () -> menteeService.approveOrRejectMentee(menteeId, profileId, true)); + assertThat(thrown) + .isInstanceOf(ResourceNotFoundException.class) + .hasMessage("Error, Mentee cannot be approved/rejected. " + + "Mentee with id: 1 doesn't exist."); + } + + @Test + void approveOrRejectMentee_withUnsuitableData_thenThrowUnauthorized() { + final Mentee mentee = new Mentee(); + mentee.setState(EnrolmentState.PENDING); + mentor.setProfile(new Profile()); + mentee.setAssignedMentor(mentor); + + doReturn(Optional.of(mentee)) + .when(menteeRepository) + .findById(anyLong()); + + Throwable thrown = catchThrowable( + () -> menteeService.approveOrRejectMentee(menteeId, profileId, true)); + assertThat(thrown) + .isInstanceOf(UnauthorizedException.class) + .hasMessage("Error, Mentee cannot be approved/rejected. " + + "Mentee with id: 1 is not a mentee of " + + "mentor with profile id: 1."); + } + + @Test + void approveOrRejectMentee_withUnsuitableData_thenThrowBadRequest() { + final Mentee mentee = new Mentee(); + mentee.setState(EnrolmentState.REMOVED); + Profile profile = new Profile(); + profile.setId(profileId); + mentor.setProfile(profile); + mentee.setAssignedMentor(mentor); + + doReturn(Optional.of(mentee)) + .when(menteeRepository) + .findById(anyLong()); + + Throwable thrown = catchThrowable( + () -> menteeService.approveOrRejectMentee(menteeId, profileId, true)); + assertThat(thrown) + .isInstanceOf(BadRequestException.class) + .hasMessage("Error, Mentee cannot be approved/rejected. " + + "Mentee with id: 1 is removed."); + } + + @Test + void updateAssignedMentor_withValidData_thenReturnUpdatedData() + throws ResourceNotFoundException, BadRequestException { + final Mentee mentee = new Mentee(); + final Program program = new Program(); + program.setState(ProgramState.WILDCARD); + mentee.setProgram(program); + doReturn(Optional.of(mentee)) + .when(menteeRepository) + .findById(anyLong()); + doReturn(Optional.of(mentor)) + .when(mentorRepository) + .findById(anyLong()); + doReturn(mentee) + .when(menteeRepository) + .save(any(Mentee.class)); + + Mentee savedMentee = menteeService.updateAssignedMentor(menteeId, mentorId); + assertThat(savedMentee).isNotNull(); + } + + @Test + void updateAssignedMentor_withUnavailableMentee_thenThrowResourceNotFound() { + doReturn(Optional.empty()) + .when(menteeRepository) + .findById(anyLong()); + + Throwable thrown = catchThrowable( + () -> menteeService.updateAssignedMentor(menteeId, mentorId)); + assertThat(thrown) + .isInstanceOf(ResourceNotFoundException.class) + .hasMessage("Error, Mentee cannot be updated. " + + "Mentee with id: 1 doesn't exist."); + } + + @Test + void updateAssignedMentor_withUnavailableMentor_thenThrowResourceNotFound() { + final Mentee mentee = new Mentee(); + doReturn(Optional.of(mentee)) + .when(menteeRepository) + .findById(anyLong()); + doReturn(Optional.empty()) + .when(mentorRepository) + .findById(anyLong()); + + Throwable thrown = catchThrowable( + () -> menteeService.updateAssignedMentor(menteeId, mentorId)); + assertThat(thrown) + .isInstanceOf(ResourceNotFoundException.class) + .hasMessage("Error, Mentee cannot be updated. " + + "Mentor with id: 1 doesn't exist."); + } + + @Test + void updateAssignedMentor_withUnsuitableData_thenThrowBadRequest() { + final Mentee mentee = new Mentee(); + final Program program = new Program(); + program.setState(ProgramState.CREATED); + mentee.setProgram(program); + doReturn(Optional.of(mentee)) + .when(menteeRepository) + .findById(anyLong()); + doReturn(Optional.of(mentor)) + .when(mentorRepository) + .findById(anyLong()); + + Throwable thrown = catchThrowable( + () -> menteeService.updateAssignedMentor(menteeId, mentorId)); + assertThat(thrown) + .isInstanceOf(BadRequestException.class) + .hasMessage("Error, Mentee cannot be updated. " + + "Program is not in a valid state."); + + } +} diff --git a/src/main/test/java/org/sefglobal/scholarx/service/MentorServiceTest.java b/src/test/java/org/sefglobal/scholarx/service/MentorServiceTest.java similarity index 73% rename from src/main/test/java/org/sefglobal/scholarx/service/MentorServiceTest.java rename to src/test/java/org/sefglobal/scholarx/service/MentorServiceTest.java index 509a08af..7343c6ac 100644 --- a/src/main/test/java/org/sefglobal/scholarx/service/MentorServiceTest.java +++ b/src/test/java/org/sefglobal/scholarx/service/MentorServiceTest.java @@ -11,15 +11,18 @@ import org.sefglobal.scholarx.model.Mentee; import org.sefglobal.scholarx.model.Mentor; import org.sefglobal.scholarx.model.Profile; +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 org.sefglobal.scholarx.util.ProgramState; import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.doReturn; @@ -39,8 +42,7 @@ public class MentorServiceTest { private final Long profileId = 1L; private final Mentor mentor = new Mentor(); private final Profile profile = new Profile(); - private final Mentee mentee = - new Mentee("http://submission.url/"); + private final Mentee mentee = new Mentee(); @Test void getMentorById_withUnavailableData_thenThrowResourceNotFound() { @@ -57,7 +59,7 @@ void getMentorById_withUnavailableData_thenThrowResourceNotFound() { @Test void updateState_withValidData_thenReturnUpdatedData() - throws ResourceNotFoundException { + throws ResourceNotFoundException, BadRequestException { doReturn(Optional.of(mentor)) .when(mentorRepository) .findById(anyLong()); @@ -69,23 +71,43 @@ void updateState_withValidData_thenReturnUpdatedData() assertThat(savedMentor).isNotNull(); } + @Test + void updateState_withInvalidData_thenThrowsBadRequestException() { + Throwable thrown = catchThrowable( + () -> mentorService.updateState(mentorId, EnrolmentState.ASSIGNED)); + assertThat(thrown) + .isInstanceOf(BadRequestException.class) + .hasMessage("Error, Mentor with id: 1 cannot be updated. " + + "ASSIGNED is not an applicable state."); + } + @Test void applyAsMentee_withValidData_thenReturnCreatedData() throws ResourceNotFoundException, BadRequestException { final Mentor mentor = new Mentor(); mentor.setState(EnrolmentState.APPROVED); + Program program = new Program(); + program.setState(ProgramState.MENTEE_APPLICATION); + mentor.setProgram(program); + doReturn(Optional.of(mentor)) .when(mentorRepository) .findById(anyLong()); doReturn(Optional.of(profile)) .when(profileRepository) .findById(anyLong()); + doReturn(Optional.empty()) + .when(mentorRepository) + .findByProfileIdAndProgramId(anyLong(), anyLong()); + doReturn(Optional.empty()) + .when(menteeRepository) + .findByProgramIdAndProfileId(anyLong(), anyLong()); doReturn(mentee) .when(menteeRepository) .save(any(Mentee.class)); - Mentee savedMentee = mentorService.applyAsMentee(programId, profileId, mentee); + Mentee savedMentee = mentorService.applyAsMentee(mentorId, profileId, mentee); assertThat(savedMentee).isNotNull(); } @@ -125,6 +147,10 @@ void applyAsMentee_withUnavailableProfile_thenThrowResourceNotFound() { final Mentor mentor = new Mentor(); mentor.setState(EnrolmentState.APPROVED); + Program program = new Program(); + program.setState(ProgramState.MENTEE_APPLICATION); + mentor.setProgram(program); + doReturn(Optional.of(mentor)) .when(mentorRepository) .findById(anyLong()); @@ -166,63 +192,4 @@ void getAllMenteesOfMentor_withUnsuitableData_thenThrowBadRequest() { .isInstanceOf(BadRequestException.class) .hasMessage("Error, Mentor by id: 1 is not an approved mentor."); } - - @Test - void updateMenteeData_withValidData_thenReturnUpdatedData() - throws ResourceNotFoundException, BadRequestException { - mentee.setState(EnrolmentState.PENDING); - mentee.setMentor(mentor); - doReturn(Optional.of(mentee)) - .when(menteeRepository) - .findByProfileIdAndMentorId(anyLong(), anyLong()); - doReturn(mentee) - .when(menteeRepository) - .save(any(Mentee.class)); - - Mentee savedMentee = mentorService.updateMenteeData(profileId, mentorId, mentee); - assertThat(savedMentee).isNotNull(); - } - - @Test - void updateMenteeData_withUnavailableData_thenThrowResourceNotFound() { - doReturn(Optional.empty()) - .when(menteeRepository) - .findByProfileIdAndMentorId(anyLong(), anyLong()); - - Throwable thrown = catchThrowable( - () -> mentorService.updateMenteeData(profileId, mentorId, mentee)); - assertThat(thrown) - .isInstanceOf(ResourceNotFoundException.class) - .hasMessage("Error, Mentee by profile id: 1 and mentor id: 1 cannot be updated. " + - "Mentee doesn't exist."); - } - - @Test - void updateMenteeData_withUnsuitableData_thenThrowBadRequest() { - mentee.setState(EnrolmentState.APPROVED); - doReturn(Optional.of(mentee)) - .when(menteeRepository) - .findByProfileIdAndMentorId(anyLong(), anyLong()); - - Throwable thrown = catchThrowable( - () -> mentorService.updateMenteeData(profileId, mentorId, mentee)); - assertThat(thrown) - .isInstanceOf(BadRequestException.class) - .hasMessage("Error, Application cannot be updated. " + - "Mentee is not in a valid state."); - } - - @Test - void getLoggedInMentee_withUnavailableData_thenThrowNoContent() { - doReturn(Optional.empty()) - .when(menteeRepository) - .findByProfileIdAndMentorId(anyLong(), anyLong()); - - Throwable thrown = catchThrowable( - () -> mentorService.getLoggedInMentee(mentorId, profileId)); - assertThat(thrown) - .isInstanceOf(NoContentException.class) - .hasMessage("Error, User by profile id: 1 " + - "hasn't applied for mentor with id: 1."); - } } diff --git a/src/main/test/java/org/sefglobal/scholarx/service/ProgramServiceTest.java b/src/test/java/org/sefglobal/scholarx/service/ProgramServiceTest.java similarity index 61% rename from src/main/test/java/org/sefglobal/scholarx/service/ProgramServiceTest.java rename to src/test/java/org/sefglobal/scholarx/service/ProgramServiceTest.java index 75c6a086..00d16fac 100644 --- a/src/main/test/java/org/sefglobal/scholarx/service/ProgramServiceTest.java +++ b/src/test/java/org/sefglobal/scholarx/service/ProgramServiceTest.java @@ -8,14 +8,8 @@ import org.sefglobal.scholarx.exception.BadRequestException; import org.sefglobal.scholarx.exception.NoContentException; import org.sefglobal.scholarx.exception.ResourceNotFoundException; -import org.sefglobal.scholarx.model.Mentee; -import org.sefglobal.scholarx.model.Mentor; -import org.sefglobal.scholarx.model.Profile; -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.repository.ProgramRepository; +import org.sefglobal.scholarx.model.*; +import org.sefglobal.scholarx.repository.*; import org.sefglobal.scholarx.util.EnrolmentState; import org.sefglobal.scholarx.util.ProgramState; @@ -46,13 +40,12 @@ public class ProgramServiceTest { private final Long profileId = 1L; private final Program program = new Program("SCHOLARX-2020", "SCHOLARX program of 2020", - "http://scholarx/images/SCHOLARX-2020", - "http://scholarx/SCHOLARX-2020/home", ProgramState.CREATED); - private final Mentor mentor = - new Mentor("Sample application", - "Sample prerequisites"); - private final Profile profile = - new Profile(); + "https://scholarx/images/SCHOLARX-2020", + "https://scholarx/SCHOLARX-2020/home", ProgramState.CREATED); + private final Mentor mentor = new Mentor(); + private final Profile profile = new Profile(); + private final Mentee mentee = new Mentee(); + @Test void updateState_withValidData_thenReturnUpdatedData() @@ -155,8 +148,8 @@ void applyAsMentor_withValidData_thenReturnCreatedData() throws ResourceNotFoundException, BadRequestException { final Program program = new Program("SCHOLARX-2020", "SCHOLARX program of 2020", - "http://scholarx/images/SCHOLARX-2020", - "http://scholarx/SCHOLARX-2020/home", + "https://scholarx/images/SCHOLARX-2020", + "https://scholarx/SCHOLARX-2020/home", ProgramState.MENTOR_APPLICATION); doReturn(Optional.of(program)) @@ -205,8 +198,8 @@ void applyAsMentor_withUnsuitableData_thenThrowBadRequest() { void applyAsMentor_withUnavailableProfile_thenThrowResourceNotFound() { final Program program = new Program("SCHOLARX-2020", "SCHOLARX program of 2020", - "http://scholarx/images/SCHOLARX-2020", - "http://scholarx/SCHOLARX-2020/home", + "https://scholarx/images/SCHOLARX-2020", + "https://scholarx/SCHOLARX-2020/home", ProgramState.MENTOR_APPLICATION); doReturn(Optional.of(program)) @@ -225,25 +218,15 @@ void applyAsMentor_withUnavailableProfile_thenThrowResourceNotFound() { } @Test - void getLoggedInMentor_withUnavailableData_thenThrowResourceNotFound() { - doReturn(Optional.empty()) - .when(mentorRepository) - .findByProfileIdAndProgramId(anyLong(), anyLong()); - - Throwable thrown = catchThrowable( - () -> programService.getLoggedInMentor(programId, profileId)); - assertThat(thrown) - .isInstanceOf(ResourceNotFoundException.class) - .hasMessage("Error, Mentor by profile id: 1 " + - "and program id: 1 doesn't exist."); - } - - @Test - void updateMentorData_withValidData_thenReturnUpdatedData() + void updateMentorApplication_withValidData_thenReturnUpdatedData() throws ResourceNotFoundException, BadRequestException { - mentor.setState(EnrolmentState.PENDING); - program.setState(ProgramState.MENTOR_APPLICATION); + final Program program = + new Program("SCHOLARX-2020", "SCHOLARX program of 2020", + "https://scholarx/images/SCHOLARX-2020", + "https://scholarx/SCHOLARX-2020/home", + ProgramState.MENTOR_APPLICATION); mentor.setProgram(program); + doReturn(Optional.of(mentor)) .when(mentorRepository) .findByProfileIdAndProgramId(anyLong(), anyLong()); @@ -251,47 +234,67 @@ void updateMentorData_withValidData_thenReturnUpdatedData() .when(mentorRepository) .save(any(Mentor.class)); - Mentor savedMentor = programService.updateMentorData(profileId, programId, mentor); + Mentor savedMentor = programService.updateMentorApplication(programId, profileId, mentor); assertThat(savedMentor).isNotNull(); } @Test - void updateMentorData_withUnavailableData_thenThrowResourceNotFound() { + void updateMentorApplication_withUnavailableData_thenThrowResourceNotFound() { doReturn(Optional.empty()) .when(mentorRepository) .findByProfileIdAndProgramId(anyLong(), anyLong()); Throwable thrown = catchThrowable( - () -> programService.updateMentorData(profileId, programId, mentor)); + () -> programService.updateMentorApplication(programId, profileId, mentor)); assertThat(thrown) .isInstanceOf(ResourceNotFoundException.class) - .hasMessage("Error, Mentor by profile id: 1 and program id: 1 cannot be updated. " + - "Mentor doesn't exist."); + .hasMessage("Error, Unable to update mentor application. " + + "Mentor with profile id: 1 doesn't exist."); } @Test - void updateMentorData_withUnsuitableData_thenThrowBadRequest() { - mentor.setState(EnrolmentState.APPROVED); + void updateMentorApplication_withUnsuitableData_thenThrowBadRequest() { + final Program program = + new Program("SCHOLARX-2020", "SCHOLARX program of 2020", + "https://scholarx/images/SCHOLARX-2020", + "https://scholarx/SCHOLARX-2020/home", + ProgramState.MENTOR_SELECTION); + mentor.setProgram(program); + doReturn(Optional.of(mentor)) .when(mentorRepository) .findByProfileIdAndProgramId(anyLong(), anyLong()); Throwable thrown = catchThrowable( - () -> programService.updateMentorData(profileId, programId, mentor)); + () -> programService.updateMentorApplication(programId, profileId, mentor)); assertThat(thrown) .isInstanceOf(BadRequestException.class) - .hasMessage("Error, Application cannot be updated. " + - "Mentor is not in a valid state."); + .hasMessage("Error, Unable to update mentor application. " + + "Program with id: 1 is not in the valid state."); } @Test - void getAppliedMentorsOfMentee_withUnavailableData_thenThrowNoContent() { - doReturn(new ArrayList<>()) + void getLoggedInMentor_withUnavailableData_thenThrowResourceNotFound() { + doReturn(Optional.empty()) + .when(mentorRepository) + .findByProfileIdAndProgramId(anyLong(), anyLong()); + + Throwable thrown = catchThrowable( + () -> programService.getLoggedInMentor(programId, profileId)); + assertThat(thrown) + .isInstanceOf(ResourceNotFoundException.class) + .hasMessage("Error, Mentor by profile id: 1 " + + "and program id: 1 doesn't exist."); + } + + @Test + void getAppliedMentorOfMentee_withUnavailableData_thenThrowNoContent() { + doReturn(Optional.empty()) .when(menteeRepository) - .findAllByProgramIdAndProfileId(anyLong(), anyLong()); + .findByProgramIdAndProfileId(anyLong(), anyLong()); Throwable thrown = catchThrowable( - () -> programService.getAppliedMentorsOfMentee(programId, new ArrayList<>(), profileId)); + () -> programService.getAppliedMentorOfMentee(programId, profileId)); assertThat(thrown) .isInstanceOf(NoContentException.class) .hasMessage("Error, Mentee by program id: 1 and " + @@ -300,9 +303,9 @@ void getAppliedMentorsOfMentee_withUnavailableData_thenThrowNoContent() { @Test void getSelectedMentorOfMentee_withUnavailableData_thenThrowResourceNotFound() { - doReturn(new ArrayList<>()) + doReturn(Optional.empty()) .when(menteeRepository) - .findAllByProgramIdAndProfileId(anyLong(), anyLong()); + .findByProgramIdAndProfileId(anyLong(), anyLong()); Throwable thrown = catchThrowable( () -> programService.getSelectedMentor(programId, profileId)); @@ -314,11 +317,10 @@ void getSelectedMentorOfMentee_withUnavailableData_thenThrowResourceNotFound() { @Test void getSelectedMentorOfMentee_withUnavailableData_thenThrowNoContent() { - List mentees = new ArrayList<>(); - mentees.add(new Mentee("SubmissionURL")); - doReturn(mentees) + Mentee mentee = new Mentee(); + doReturn(Optional.of(mentee)) .when(menteeRepository) - .findAllByProgramIdAndProfileId(anyLong(), anyLong()); + .findByProgramIdAndProfileId(anyLong(), anyLong()); Throwable thrown = catchThrowable( () -> programService.getSelectedMentor(programId, profileId)); @@ -326,4 +328,111 @@ void getSelectedMentorOfMentee_withUnavailableData_thenThrowNoContent() { .isInstanceOf(NoContentException.class) .hasMessage("Error, Mentee is not approved by any mentor yet."); } + + @Test + void getAllMenteesByProgramId_withUnavailableProgramId_thenThrowResourceNotFoundException() { + doReturn(false) + .when(programRepository) + .existsById(programId); + + Throwable thrown = catchThrowable( + () -> programService.getAllMenteesByProgramId(programId)); + assertThat(thrown) + .isInstanceOf(ResourceNotFoundException.class) + .hasMessage("Error, Program by id: 1 doesn't exist"); + } + + @Test + void getAllMenteesByProgramId_withAvailableData_thenReturnDataFromRepository() throws ResourceNotFoundException { + doReturn(true) + .when(programRepository) + .existsById(programId); + List storedData = new ArrayList<>(); + doReturn(storedData) + .when(menteeRepository) + .findAllByProgramId(programId); + + List returnedData = programService.getAllMenteesByProgramId(programId); + assertThat(returnedData).isEqualTo(storedData); + } + + @Test + void updateMenteeData_withValidData_thenReturnUpdatedData() + throws ResourceNotFoundException, BadRequestException { + mentor.setState(EnrolmentState.APPROVED); + mentee.setState(EnrolmentState.PENDING); + mentee.setAppliedMentor(mentor); + + Program program = new Program(); + program.setId(programId); + program.setState(ProgramState.MENTEE_APPLICATION); + mentee.setProgram(program); + + doReturn(Optional.of(mentee)) + .when(menteeRepository) + .findByProgramIdAndProfileId(anyLong(), anyLong()); + doReturn(Optional.of(mentor)) + .when(mentorRepository) + .findById(anyLong()); + doReturn(mentee) + .when(menteeRepository) + .save(any(Mentee.class)); + + Mentee savedMentee = programService.updateMenteeData(profileId, programId, mentee); + assertThat(savedMentee).isNotNull(); + } + + @Test + void updateMenteeData_withUnavailableData_thenThrowResourceNotFound() { + doReturn(Optional.empty()) + .when(menteeRepository) + .findByProgramIdAndProfileId(anyLong(), anyLong()); + + Throwable thrown = catchThrowable( + () -> programService.updateMenteeData(profileId, programId, mentee)); + assertThat(thrown) + .isInstanceOf(ResourceNotFoundException.class) + .hasMessage("Error, Mentee by profile id: 1 and program id: 1 cannot be updated. " + + "Mentee doesn't exist."); + } + + @Test + void updateMenteeData_withUnsuitableData_thenThrowBadRequest() { + mentee.setState(EnrolmentState.APPROVED); + mentor.setState(EnrolmentState.APPROVED); + mentee.setAppliedMentor(mentor); + + Program program = new Program(); + program.setId(programId); + program.setState(ProgramState.MENTEE_APPLICATION); + mentee.setProgram(program); + + doReturn(Optional.of(mentee)) + .when(menteeRepository) + .findByProgramIdAndProfileId(anyLong(), anyLong()); + doReturn(Optional.of(mentor)) + .when(mentorRepository) + .findById(anyLong()); + + Throwable thrown = catchThrowable( + () -> programService.updateMenteeData(profileId, programId, mentee)); + assertThat(thrown) + .isInstanceOf(BadRequestException.class) + .hasMessage("Error, Application cannot be updated. " + + "Mentee is not in a valid state."); + } + + @Test + void getLoggedInMentee_withUnavailableData_thenThrowNoContent() { + doReturn(Optional.empty()) + .when(menteeRepository) + .findByProgramIdAndProfileId(anyLong(), anyLong()); + + Throwable thrown = catchThrowable( + () -> programService.getLoggedInMentee(programId, profileId)); + assertThat(thrown) + .isInstanceOf(NoContentException.class) + .hasMessage("Error, User by profile id: 1 " + + "hasn't applied for program with id: 1."); + } }