From 8c80d70f2ee15a3ad2dd85481ea2de52f89675d1 Mon Sep 17 00:00:00 2001
From: Chris Lemaire <c.lemaire@student.tudelft.nl>
Date: Wed, 20 May 2020 10:50:04 +0200
Subject: [PATCH] Add StudentGroup endpoints for getting by person

---
 build.gradle.kts                              |  2 +-
 .../controller/StudentGroupController.java    | 43 +++++++++++
 .../repository/StudentGroupRepository.java    | 53 ++++++++++++-
 ...StudentGroupControllerIntegrationTest.java | 74 ++++++++++++++++++-
 4 files changed, 169 insertions(+), 3 deletions(-)

diff --git a/build.gradle.kts b/build.gradle.kts
index 6a0124b9..ea25b273 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -14,7 +14,7 @@ val lombokVersion = "1.18.12"
 val springDocVersion = "1.2.32"
 val jacksonVersion = "2.10.4"
 val joolVersion = "0.9.12"
-val guavaVersion = "r05"
+val guavaVersion = "29.0-jre"
 val queryDslVersion = "4.2.1"
 
 // The repositories used to lookup dependencies.
diff --git a/src/main/java/nl/tudelft/labracore/controller/StudentGroupController.java b/src/main/java/nl/tudelft/labracore/controller/StudentGroupController.java
index eb345f62..ad0b060e 100644
--- a/src/main/java/nl/tudelft/labracore/controller/StudentGroupController.java
+++ b/src/main/java/nl/tudelft/labracore/controller/StudentGroupController.java
@@ -31,6 +31,7 @@ import nl.tudelft.labracore.dto.view.structured.summary.RoleSummaryDTO;
 import nl.tudelft.labracore.repository.StudentGroupRepository;
 import nl.tudelft.labracore.service.RoleService;
 import nl.tudelft.labracore.service.StudentGroupService;
+import nl.tudelft.librador.dto.view.View;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -250,4 +251,46 @@ public class StudentGroupController {
 		return sgs.getRoleOfMember(personId, id);
 	}
 
+	/**
+	 * Gets all groups for a given person.
+	 *
+	 * @param  personId The id of the person to lookup.
+	 * @return          The list of groups the given person is in.
+	 */
+	@GetMapping("/by-person/{personId}")
+	@PreAuthorize("hasAuthority('STUDENT_GROUP_READ')")
+	public List<StudentGroupSummaryDTO> getGroupsForPerson(@PathVariable Long personId) {
+		return View.convertList(sgr.findAllByPersonIn(personId), StudentGroupSummaryDTO.class);
+	}
+
+	/**
+	 * Gets all groups for a given person within the given course.
+	 *
+	 * @param  personId The id of the person to lookup.
+	 * @param  courseId The id of the course to lookup.
+	 * @return          The list of groups in the given course the given person is in.
+	 */
+	@GetMapping("/by-person-and-course/{personId}/{courseId}")
+	@PreAuthorize("hasAuthority('STUDENT_GROUP_READ')")
+	public List<StudentGroupSummaryDTO> getGroupsForPersonAndCourse(@PathVariable Long personId,
+			@PathVariable Long courseId) {
+		return View.convertList(sgr.findAllByCourseAndPersonIn(personId, courseId),
+				StudentGroupSummaryDTO.class);
+	}
+
+	/**
+	 * Gets all groups for a given person within the given module.
+	 *
+	 * @param  personId The id of the person to lookup.
+	 * @param  moduleId The id of the module to lookup.
+	 * @return          The list of groups in the given module the given person is in.
+	 */
+	@GetMapping("/by-person-and-module/{personId}/{moduleId}")
+	@PreAuthorize("hasAuthority('STUDENT_GROUP_READ')")
+	public List<StudentGroupSummaryDTO> getGroupsForPersonAndModule(@PathVariable Long personId,
+			@PathVariable Long moduleId) {
+		return View.convertList(sgr.findAllByModuleAndPersonIn(personId, moduleId),
+				StudentGroupSummaryDTO.class);
+	}
+
 }
diff --git a/src/main/java/nl/tudelft/labracore/repository/StudentGroupRepository.java b/src/main/java/nl/tudelft/labracore/repository/StudentGroupRepository.java
index 35bcddc5..c9bbe7c2 100644
--- a/src/main/java/nl/tudelft/labracore/repository/StudentGroupRepository.java
+++ b/src/main/java/nl/tudelft/labracore/repository/StudentGroupRepository.java
@@ -17,15 +17,33 @@
  */
 package nl.tudelft.labracore.repository;
 
+import static com.querydsl.jpa.JPAExpressions.select;
+import static nl.tudelft.labracore.model.QRole.role;
+import static nl.tudelft.labracore.model.QStudentGroup.studentGroup;
+
 import java.util.List;
 
 import nl.tudelft.labracore.model.Module;
 import nl.tudelft.labracore.model.StudentGroup;
 
 import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.querydsl.QuerydslPredicateExecutor;
 import org.springframework.data.rest.webmvc.ResourceNotFoundException;
 
-public interface StudentGroupRepository extends JpaRepository<StudentGroup, Long> {
+import com.querydsl.core.types.Predicate;
+import com.querydsl.core.types.dsl.BooleanExpression;
+
+public interface StudentGroupRepository
+		extends JpaRepository<StudentGroup, Long>, QuerydslPredicateExecutor<StudentGroup> {
+
+	/**
+	 * Override findAll definition using a list as the iterable to store results in.
+	 *
+	 * @param  predicate The predicate to execute.
+	 * @return           The resulting iterable of StudentGroups.
+	 */
+	@Override
+	List<StudentGroup> findAll(Predicate predicate);
 
 	/**
 	 * Finds the studentGroup by id or throws a ResourceNotFoundException.
@@ -55,4 +73,37 @@ public interface StudentGroupRepository extends JpaRepository<StudentGroup, Long
 	 */
 	List<StudentGroup> findAllByModule_Id(Long id);
 
+	/**
+	 * @param  personId The id of the person to find groups for.
+	 * @return          The groups that the person is in.
+	 */
+	default List<StudentGroup> findAllByPersonIn(Long personId) {
+		BooleanExpression q = studentGroup.members.any().person.id.eq(personId);
+		return findAll(q);
+	}
+
+	/**
+	 * @param  personId The id of the person to lookup.
+	 * @param  courseId The id of the course to lookup.
+	 * @return          All groups that contain the given person in the given course.
+	 */
+	default List<StudentGroup> findAllByCourseAndPersonIn(Long personId, Long courseId) {
+		BooleanExpression q = studentGroup.members.any().id.in(
+				select(role.id).from(role).where(
+						role.edition.course.id.eq(courseId).and(
+								role.id.personId.eq(personId))));
+		return findAll(q);
+	}
+
+	/**
+	 * @param  personId The id of the person to lookup.
+	 * @param  moduleId The id of the module to lookup.
+	 * @return          All groups that contain the given person in the given module.
+	 */
+	default List<StudentGroup> findAllByModuleAndPersonIn(Long personId, Long moduleId) {
+		BooleanExpression q = studentGroup.module.id.eq(moduleId).and(
+				studentGroup.members.any().id.personId.eq(personId));
+		return findAll(q);
+	}
+
 }
diff --git a/src/test/java/nl/tudelft/labracore/controller/StudentGroupControllerIntegrationTest.java b/src/test/java/nl/tudelft/labracore/controller/StudentGroupControllerIntegrationTest.java
index f137767b..7838ad41 100644
--- a/src/test/java/nl/tudelft/labracore/controller/StudentGroupControllerIntegrationTest.java
+++ b/src/test/java/nl/tudelft/labracore/controller/StudentGroupControllerIntegrationTest.java
@@ -23,6 +23,7 @@ import static org.springframework.security.test.web.servlet.request.SecurityMock
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
+import java.util.ArrayList;
 import java.util.stream.Stream;
 
 import javax.transaction.Transactional;
@@ -31,12 +32,18 @@ import nl.tudelft.labracore.TestLabracoreApplication;
 import nl.tudelft.labracore.dto.create.StudentGroupCreateDTO;
 import nl.tudelft.labracore.dto.helper.GroupGenerateDTO;
 import nl.tudelft.labracore.dto.patch.StudentGroupPatchDTO;
+import nl.tudelft.labracore.dto.view.other.StudentGroupSummaryDTO;
+import nl.tudelft.labracore.model.Course;
+import nl.tudelft.labracore.model.Person;
 import nl.tudelft.labracore.model.StudentGroup;
+import nl.tudelft.labracore.repository.CourseRepository;
 import nl.tudelft.labracore.repository.ModuleRepository;
 import nl.tudelft.labracore.repository.StudentGroupRepository;
 import nl.tudelft.labracore.test.RestControllerTest;
 import nl.tudelft.labracore.test.TestDatabaseLoader;
+import nl.tudelft.librador.dto.view.View;
 
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.MethodSource;
@@ -63,9 +70,25 @@ class StudentGroupControllerIntegrationTest extends RestControllerTest {
 	@Autowired
 	private StudentGroupRepository sgr;
 
+	@Autowired
+	private CourseRepository cr;
+
 	@Autowired
 	private ModuleRepository mr;
 
+	private StudentGroup sg1;
+	private StudentGroup sg2;
+	private Person p;
+	private Course c;
+
+	@BeforeEach
+	void setUp() {
+		sg1 = sgr.getOne(dbLoader.getBattle_g1().getId());
+		sg2 = sgr.getOne(dbLoader.getPrep_g1().getId());
+		p = sg1.getMembers().get(0).getPerson();
+		c = cr.getOne(dbLoader.getBeatingHive().getId());
+	}
+
 	@Test
 	@WithUserDetails("All-access Key")
 	void addGroupValidatesDTO() throws Exception {
@@ -113,6 +136,52 @@ class StudentGroupControllerIntegrationTest extends RestControllerTest {
 								.equals(group.getModule().getId())));
 	}
 
+	private static class StudentGroupSummaryList extends ArrayList<StudentGroupSummaryDTO> {
+	}
+
+	@Test
+	@WithUserDetails("All-access Key")
+	void getGroupsForPersonWorks() throws Exception {
+		mockMvc.perform(get("/api/studentGroup/by-person/{p}", p.getId()))
+				.andExpect(status().isOk())
+				.andExpect(jsonContent(StudentGroupSummaryList.class)
+						.test(l -> assertThat(l).containsExactlyInAnyOrder(
+								View.convert(sg1, StudentGroupSummaryDTO.class),
+								View.convert(sg2, StudentGroupSummaryDTO.class))));
+	}
+
+	@Test
+	@WithUserDetails("All-access Key")
+	void getGroupsForPersonAndCourseWorks() throws Exception {
+		mockMvc.perform(get("/api/studentGroup/by-person-and-course/{p}/{c}", p.getId(),
+				sg1.getModule().getEdition().getCourse().getId()))
+				.andExpect(status().isOk())
+				.andExpect(jsonContent(StudentGroupSummaryList.class)
+						.test(l -> assertThat(l).containsExactlyInAnyOrder(
+								View.convert(sg1, StudentGroupSummaryDTO.class),
+								View.convert(sg2, StudentGroupSummaryDTO.class))));
+	}
+
+	@Test
+	@WithUserDetails("All-access Key")
+	void getGroupsForPersonAndCourseFilters() throws Exception {
+		mockMvc.perform(get("/api/studentGroup/by-person-and-course/{p}/{c}", p.getId(), c.getId()))
+				.andExpect(status().isOk())
+				.andExpect(jsonContent(StudentGroupSummaryList.class)
+						.test(l -> assertThat(l).isEmpty()));
+	}
+
+	@Test
+	@WithUserDetails("All-access Key")
+	void getGroupsForPersonAndModuleWorks() throws Exception {
+		mockMvc.perform(
+				get("/api/studentGroup/by-person-and-module/{p}/{m}", p.getId(), sg1.getModule().getId()))
+				.andExpect(status().isOk())
+				.andExpect(jsonContent(StudentGroupSummaryList.class)
+						.test(l -> assertThat(l).containsExactlyInAnyOrder(
+								View.convert(sg1, StudentGroupSummaryDTO.class))));
+	}
+
 	@WithUserDetails("No-access Key")
 	@MethodSource("protectedEndpoints")
 	@ParameterizedTest
@@ -139,6 +208,9 @@ class StudentGroupControllerIntegrationTest extends RestControllerTest {
 				patch("/api/studentGroup/3/capacity/1"),
 				get("/api/studentGroup/1/locked"),
 				get("/api/studentGroup/1/locked_student/2"),
-				get("/api/studentGroup/1/role/2"));
+				get("/api/studentGroup/1/role/2"),
+				get("/api/studentGroup/by-person/1"),
+				get("/api/studentGroup/by-person-and-course/1/1"),
+				get("/api/studentGroup/by-person-and-module/1/1"));
 	}
 }
-- 
GitLab