From abc8b56534aeccfe8e84b065c0d04b0916da41dc Mon Sep 17 00:00:00 2001 From: Aqua-sc <108478185+Aqua-sc@users.noreply.github.com> Date: Fri, 17 May 2024 09:52:48 +0200 Subject: [PATCH 01/11] Allow admin to submit --- .../controllers/SubmissionController.java | 16 ++++++++- .../postgre/models/SubmissionEntity.java | 6 ++-- .../repository/SubmissionRepository.java | 7 ++++ .../pidgeon/util/EntityToJsonConverter.java | 2 +- .../com/ugent/pidgeon/util/Filehandler.java | 8 +++-- .../com/ugent/pidgeon/util/GroupUtil.java | 6 ++-- .../ugent/pidgeon/util/SubmissionUtil.java | 36 ++++++++++--------- 7 files changed, 54 insertions(+), 27 deletions(-) diff --git a/backend/app/src/main/java/com/ugent/pidgeon/controllers/SubmissionController.java b/backend/app/src/main/java/com/ugent/pidgeon/controllers/SubmissionController.java index 39bdca89..9919e6ae 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/controllers/SubmissionController.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/controllers/SubmissionController.java @@ -161,7 +161,7 @@ public ResponseEntity submitFile(@RequestParam("file") MultipartFile file, @P return ResponseEntity.status(checkResult.getStatus()).body(checkResult.getMessage()); } - long groupId = checkResult.getData(); + Long groupId = checkResult.getData(); try { //Save the file entry in the database to get the id @@ -265,6 +265,7 @@ public ResponseEntity submitFile(@RequestParam("file") MultipartFile file, @P return ResponseEntity.ok(entityToJsonConverter.getSubmissionJson(submission)); } catch (Exception e) { + Logger.getLogger("SubmissionController").log(Level.SEVERE, e.getMessage(), e); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body("Failed to save submissions on file server."); } @@ -396,4 +397,17 @@ public ResponseEntity getSubmissionsForGroup(@PathVariable("projectid") long List res = submissions.stream().map(entityToJsonConverter::getSubmissionJson).toList(); return ResponseEntity.ok(res); } + + @GetMapping(ApiRoutes.PROJECT_BASE_PATH + "/{projectid}/adminsubmissions") + @Roles({UserRole.teacher, UserRole.student}) + public ResponseEntity getAdminSubmissions(@PathVariable("projectid") long projectid, Auth auth) { + CheckResult checkResult = projectUtil.isProjectAdmin(projectid, auth.getUserEntity()); + if (!checkResult.getStatus().equals(HttpStatus.OK)) { + return ResponseEntity.status(checkResult.getStatus()).body(checkResult.getMessage()); + } + + List submissions = submissionRepository.findAdminSubmissionsByProjectId(projectid); + List res = submissions.stream().map(entityToJsonConverter::getSubmissionJson).toList(); + return ResponseEntity.ok(res); + } } \ No newline at end of file diff --git a/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/SubmissionEntity.java b/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/SubmissionEntity.java index 2ecdcd8e..1edc07b8 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/SubmissionEntity.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/SubmissionEntity.java @@ -18,7 +18,7 @@ public class SubmissionEntity { private long projectId; @Column(name="group_id", nullable=false) - private long groupId; + private Long groupId; @Column(name="file_id", nullable=false) private long fileId; @@ -47,7 +47,7 @@ public class SubmissionEntity { public SubmissionEntity() { } - public SubmissionEntity(long projectId, long groupId, Long fileId, OffsetDateTime submissionTime, Boolean structureAccepted, Boolean dockerAccepted) { + public SubmissionEntity(long projectId, Long groupId, Long fileId, OffsetDateTime submissionTime, Boolean structureAccepted, Boolean dockerAccepted) { this.projectId = projectId; this.groupId = groupId; this.fileId = fileId; @@ -56,7 +56,7 @@ public SubmissionEntity(long projectId, long groupId, Long fileId, OffsetDateTim this.dockerAccepted = dockerAccepted; } - public long getGroupId() { + public Long getGroupId() { return groupId; } diff --git a/backend/app/src/main/java/com/ugent/pidgeon/postgre/repository/SubmissionRepository.java b/backend/app/src/main/java/com/ugent/pidgeon/postgre/repository/SubmissionRepository.java index a2df7c9a..c000a12a 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/postgre/repository/SubmissionRepository.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/postgre/repository/SubmissionRepository.java @@ -32,5 +32,12 @@ SELECT MAX(s2.submissionTime) """) Optional findLatestsSubmissionIdsByProjectAndGroupId(long projectId, long groupId); + @Query(value = """ + SELECT s FROM SubmissionEntity s + WHERE s.projectId = :projectId + AND s.groupId IS NULL + """) + List findAdminSubmissionsByProjectId(long projectId); + List findByProjectIdAndGroupId(long projectid, long groupid); } diff --git a/backend/app/src/main/java/com/ugent/pidgeon/util/EntityToJsonConverter.java b/backend/app/src/main/java/com/ugent/pidgeon/util/EntityToJsonConverter.java index 716ae1bf..504ddc24 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/util/EntityToJsonConverter.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/util/EntityToJsonConverter.java @@ -245,7 +245,7 @@ else if (submission.getDockerTestType().equals(DockerTestType.SIMPLE)) { return new SubmissionJson( submission.getId(), ApiRoutes.PROJECT_BASE_PATH + "/" + submission.getProjectId(), - ApiRoutes.GROUP_BASE_PATH + "/" + submission.getGroupId(), + submission.getGroupId() == null ? null : ApiRoutes.GROUP_BASE_PATH + "/" + submission.getGroupId(), submission.getProjectId(), submission.getGroupId(), ApiRoutes.SUBMISSION_BASE_PATH + "/" + submission.getId() + "/file", diff --git a/backend/app/src/main/java/com/ugent/pidgeon/util/Filehandler.java b/backend/app/src/main/java/com/ugent/pidgeon/util/Filehandler.java index 071d1d4f..d2f1f3b7 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/util/Filehandler.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/util/Filehandler.java @@ -18,6 +18,7 @@ public class Filehandler { static String BASEPATH = "data"; public static String SUBMISSION_FILENAME = "files.zip"; + public static String ADMIN_SUBMISSION_FOLDER = "adminsubmissions"; /** * Save a submission to the server @@ -109,11 +110,14 @@ private static void deleteEmptyParentDirectories(File directory) throws IOExcept * @param submissionid id of the submission * @return the path of the submission */ - static public Path getSubmissionPath(long projectid, long groupid, long submissionid) { + static public Path getSubmissionPath(long projectid, Long groupid, long submissionid) { + if (groupid == null) { + return Path.of(BASEPATH,"projects", String.valueOf(projectid), ADMIN_SUBMISSION_FOLDER, String.valueOf(submissionid)); + } return Path.of(BASEPATH,"projects", String.valueOf(projectid), String.valueOf(groupid), String.valueOf(submissionid)); } - static public Path getSubmissionArtifactPath(long projectid, long groupid, long submissionid) { + static public Path getSubmissionArtifactPath(long projectid, Long groupid, long submissionid) { return getSubmissionPath(projectid, groupid, submissionid).resolve("artifacts.zip"); } diff --git a/backend/app/src/main/java/com/ugent/pidgeon/util/GroupUtil.java b/backend/app/src/main/java/com/ugent/pidgeon/util/GroupUtil.java index abb96d06..f39ac6ab 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/util/GroupUtil.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/util/GroupUtil.java @@ -189,16 +189,16 @@ public CheckResult canRemoveUserFromGroup(long groupId, long userId, UserE * @param user user that wants to get the submissions * @return CheckResult with the status of the check */ - public CheckResult canGetProjectGroupData(long groupId, long projectId, UserEntity user) { + public CheckResult canGetProjectGroupData(Long groupId, long projectId, UserEntity user) { CheckResult projectCheck = projectUtil.getProjectIfExists(projectId); if (projectCheck.getStatus() != HttpStatus.OK) { return new CheckResult<>(projectCheck.getStatus(), projectCheck.getMessage(), null); } ProjectEntity project = projectCheck.getData(); - if (groupRepository.findByIdAndClusterId(groupId, project.getGroupClusterId()).isEmpty()) { + if (groupId != null && groupRepository.findByIdAndClusterId(groupId, project.getGroupClusterId()).isEmpty()) { return new CheckResult<>(HttpStatus.NOT_FOUND, "Group not part of the project", null); } - boolean inGroup = groupRepository.userInGroup(groupId, user.getId()); + boolean inGroup = groupId != null && groupRepository.userInGroup(groupId, user.getId()); boolean isAdmin = user.getRole().equals(UserRole.admin) || projectUtil.isProjectAdmin(projectId, user).getStatus().equals(HttpStatus.OK); if (inGroup || isAdmin) { return new CheckResult<>(HttpStatus.OK, "", null); diff --git a/backend/app/src/main/java/com/ugent/pidgeon/util/SubmissionUtil.java b/backend/app/src/main/java/com/ugent/pidgeon/util/SubmissionUtil.java index d3135dac..866eed19 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/util/SubmissionUtil.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/util/SubmissionUtil.java @@ -75,32 +75,34 @@ public CheckResult canDeleteSubmission(long submissionId, User * @return CheckResult with the status of the check and the group id */ public CheckResult checkOnSubmit(long projectId, UserEntity user) { + CheckResult projectCheck = projectUtil.getProjectIfExists(projectId); + if (projectCheck.getStatus() != HttpStatus.OK) { + return new CheckResult<> (projectCheck.getStatus(), projectCheck.getMessage(), null); + } + + ProjectEntity project = projectCheck.getData(); + if (!projectUtil.userPartOfProject(projectId, user.getId())) { return new CheckResult<>(HttpStatus.FORBIDDEN, "You aren't part of this project", null); } Long groupId = groupRepository.groupIdByProjectAndUser(projectId, user.getId()); if (groupId == null) { - return new CheckResult<>(HttpStatus.BAD_REQUEST, "User is not part of a group for this project", null); - } - - CheckResult groupCheck = groupUtil.getGroupIfExists(groupId); - if (groupCheck.getStatus() != HttpStatus.OK) { - return new CheckResult<>(groupCheck.getStatus(), groupCheck.getMessage(), null); - } - GroupEntity group = groupCheck.getData(); + CheckResult projectAdminCheck = projectUtil.isProjectAdmin(projectId, user); + if (projectAdminCheck.getStatus() != HttpStatus.OK) { + return new CheckResult<>(HttpStatus.BAD_REQUEST, "User is not part of a group for this project", null); + } + } else { + CheckResult groupCheck = groupUtil.getGroupIfExists(groupId); + if (groupCheck.getStatus() != HttpStatus.OK) { + return new CheckResult<>(groupCheck.getStatus(), groupCheck.getMessage(), null); + } - if (groupClusterRepository.inArchivedCourse(group.getClusterId())) { - return new CheckResult<>(HttpStatus.FORBIDDEN, "Cannot submit for a project in an archived course", null); + if (groupClusterRepository.inArchivedCourse(project.getGroupClusterId())) { + return new CheckResult<>(HttpStatus.FORBIDDEN, "Cannot submit for a project in an archived course", null); + } } - - CheckResult projectCheck = projectUtil.getProjectIfExists(projectId); - if (projectCheck.getStatus() != HttpStatus.OK) { - return new CheckResult<> (projectCheck.getStatus(), projectCheck.getMessage(), null); - } - - ProjectEntity project = projectCheck.getData(); OffsetDateTime time = OffsetDateTime.now(); Logger.getGlobal().info("Time: " + time + " Deadline: " + project.getDeadline()); if (time.isAfter(project.getDeadline())) { From ff585a6fd750928b3d5369b31c4bc89daf12c6c0 Mon Sep 17 00:00:00 2001 From: Aqua-sc <108478185+Aqua-sc@users.noreply.github.com> Date: Fri, 17 May 2024 10:10:56 +0200 Subject: [PATCH 02/11] Update SubmissionController.java --- .../java/com/ugent/pidgeon/controllers/SubmissionController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/app/src/main/java/com/ugent/pidgeon/controllers/SubmissionController.java b/backend/app/src/main/java/com/ugent/pidgeon/controllers/SubmissionController.java index 9919e6ae..e2e2e98b 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/controllers/SubmissionController.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/controllers/SubmissionController.java @@ -179,6 +179,7 @@ public ResponseEntity submitFile(@RequestParam("file") MultipartFile file, @P false ); submissionEntity.setDockerTestState(DockerTestState.finished); + submissionEntity.setDockerType(DockerTestType.NONE); //Save the submission in the database SubmissionEntity submission = submissionRepository.save(submissionEntity); From e960f7e6cf15590e3bf3d269535681a96902c2d2 Mon Sep 17 00:00:00 2001 From: Aqua-sc <108478185+Aqua-sc@users.noreply.github.com> Date: Fri, 17 May 2024 17:06:55 +0200 Subject: [PATCH 03/11] Updated tests --- .../postgre/models/SubmissionEntity.java | 6 +++ .../controllers/SubmissionControllerTest.java | 47 +++++++++++++++++- .../util/CommonDataBaseActionsTest.java | 2 +- .../util/EntityToJsonConverterTest.java | 9 +++- .../ugent/pidgeon/util/FileHandlerTest.java | 16 +++++- .../com/ugent/pidgeon/util/GroupUtilTest.java | 12 +++++ .../pidgeon/util/SubmissionUtilTest.java | 34 +++++++++---- .../DockerSubmissionTestTest/d__test.zip | Bin 162 -> 162 bytes 8 files changed, 109 insertions(+), 17 deletions(-) diff --git a/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/SubmissionEntity.java b/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/SubmissionEntity.java index 1edc07b8..0b14e27e 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/SubmissionEntity.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/SubmissionEntity.java @@ -60,6 +60,10 @@ public Long getGroupId() { return groupId; } + public void setGroupId(Long groupId) { + this.groupId = groupId; + } + public long getFileId() { return fileId; } @@ -155,4 +159,6 @@ public DockerTestType getDockerTestType() { public void setDockerType(DockerTestType dockerType) { this.dockerType = dockerType.toString(); } + + } diff --git a/backend/app/src/test/java/com/ugent/pidgeon/controllers/SubmissionControllerTest.java b/backend/app/src/test/java/com/ugent/pidgeon/controllers/SubmissionControllerTest.java index 21b496ae..cd2b8dc9 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/controllers/SubmissionControllerTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/controllers/SubmissionControllerTest.java @@ -137,7 +137,7 @@ public static File createTestFile() throws IOException { public void setup() { setUpController(submissionController); - submission = new SubmissionEntity(22, 45, 99L, OffsetDateTime.MIN, true, true); + submission = new SubmissionEntity(22L, 45L, 99L, OffsetDateTime.MIN, true, true); submission.setId(56L); groupIds = List.of(45L); submissionJson = new SubmissionJson( @@ -527,4 +527,49 @@ public void testGetSubmissionsForGroup() throws Exception { mockMvc.perform(MockMvcRequestBuilders.get(url)) .andExpect(status().isIAmATeapot()); } + + @Test + public void testGetAdminSubmissions() { + String url = ApiRoutes.PROJECT_BASE_PATH + "/" + submission.getProjectId() + "/adminsubmissions"; + + /* all checks succeed */ + when(projectUtil.isProjectAdmin(submission.getProjectId(), getMockUser())) + .thenReturn(new CheckResult<>(HttpStatus.OK, "", null)); + when(submissionRepository.findAdminSubmissionsByProjectId(submission.getProjectId())) + .thenReturn(List.of(submission)); + when(entityToJsonConverter.getSubmissionJson(submission)).thenReturn(submissionJson); + + try { + mockMvc.perform(MockMvcRequestBuilders.get(url)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(content().json(objectMapper.writeValueAsString(List.of(submissionJson)))); + } catch (Exception e) { + e.printStackTrace(); + } + + /* No submissions */ + when(submissionRepository.findAdminSubmissionsByProjectId(submission.getProjectId())) + .thenReturn(List.of()); + + try { + mockMvc.perform(MockMvcRequestBuilders.get(url)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(content().json("[]")); + } catch (Exception e) { + e.printStackTrace(); + } + + /* User can't get project */ + when(projectUtil.isProjectAdmin(submission.getProjectId(), getMockUser())) + .thenReturn(new CheckResult<>(HttpStatus.I_AM_A_TEAPOT, "", null)); + + try { + mockMvc.perform(MockMvcRequestBuilders.get(url)) + .andExpect(status().isIAmATeapot()); + } catch (Exception e) { + e.printStackTrace(); + } + } } \ No newline at end of file diff --git a/backend/app/src/test/java/com/ugent/pidgeon/util/CommonDataBaseActionsTest.java b/backend/app/src/test/java/com/ugent/pidgeon/util/CommonDataBaseActionsTest.java index 8fedae77..f0cabe86 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/util/CommonDataBaseActionsTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/util/CommonDataBaseActionsTest.java @@ -144,7 +144,7 @@ public void setUp() { submissionEntity = new SubmissionEntity( 22, - 45, + 45L, 99L, OffsetDateTime.MIN, true, diff --git a/backend/app/src/test/java/com/ugent/pidgeon/util/EntityToJsonConverterTest.java b/backend/app/src/test/java/com/ugent/pidgeon/util/EntityToJsonConverterTest.java index fa1a2daa..3143b958 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/util/EntityToJsonConverterTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/util/EntityToJsonConverterTest.java @@ -209,7 +209,7 @@ public void setUp() { submissionEntity = new SubmissionEntity( 22, - 45, + 45L, 99L, OffsetDateTime.MIN, true, @@ -414,7 +414,7 @@ public void testProjectEntityToProjectResponseJsonWithStatus() { @Test public void testProjectEntityToProjectResponseJson() { GroupEntity secondGroup = new GroupEntity("secondGroup", groupClusterEntity.getId()); - SubmissionEntity secondSubmission = new SubmissionEntity(22, 232, 90L, OffsetDateTime.MIN, true, true); + SubmissionEntity secondSubmission = new SubmissionEntity(22, 232L, 90L, OffsetDateTime.MIN, true, true); CourseUserEntity courseUser = new CourseUserEntity(projectEntity.getCourseId(), userEntity.getId(), CourseRelation.creator); when(projectRepository.findGroupIdsByProjectId(projectEntity.getId())).thenReturn(List.of(groupEntity.getId(), secondGroup.getId())); @@ -554,6 +554,11 @@ public void testGetSubmissionJson() { assertEquals(DockerTestType.TEMPLATE, result.getDockerFeedback().type()); assertEquals(submissionEntity.getDockerFeedback(), result.getDockerFeedback().feedback()); assertFalse(result.getDockerFeedback().allowed()); + + /* Group id is null */ + submissionEntity.setGroupId(null); + result = entityToJsonConverter.getSubmissionJson(submissionEntity); + assertNull(result.getGroupUrl()); } @Test diff --git a/backend/app/src/test/java/com/ugent/pidgeon/util/FileHandlerTest.java b/backend/app/src/test/java/com/ugent/pidgeon/util/FileHandlerTest.java index 89efd857..af29bee8 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/util/FileHandlerTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/util/FileHandlerTest.java @@ -245,16 +245,28 @@ public void testDeleteLocation_parentDirIsNull() throws IOException { @Test public void testGetSubmissionPath() { - Path submissionPath = Filehandler.getSubmissionPath(1, 2, 3); + Path submissionPath = Filehandler.getSubmissionPath(1, 2L, 3); assertEquals(Path.of(Filehandler.BASEPATH, "projects", "1", "2", "3"), submissionPath); } + @Test + public void testGetSubmissionPath_groupIdIsNull() { + Path submissionPath = Filehandler.getSubmissionPath(1, null, 3); + assertEquals(Path.of(Filehandler.BASEPATH, "projects", "1", Filehandler.ADMIN_SUBMISSION_FOLDER, "3"), submissionPath); + } + @Test public void testGetSubmissionArtifactPath() { - Path submissionArtifactPath = Filehandler.getSubmissionArtifactPath(1, 2, 3); + Path submissionArtifactPath = Filehandler.getSubmissionArtifactPath(1, 2L, 3); assertEquals(Path.of(Filehandler.BASEPATH, "projects", "1", "2", "3", "artifacts.zip"), submissionArtifactPath); } + @Test + public void testGetSubmissionArtifactPath_groupIdIsNull() { + Path submissionArtifactPath = Filehandler.getSubmissionArtifactPath(1, null, 3); + assertEquals(Path.of(Filehandler.BASEPATH, "projects", "1", Filehandler.ADMIN_SUBMISSION_FOLDER, "3", "artifacts.zip"), submissionArtifactPath); + } + @Test public void testGetFileAsResource_FileExists() { try { diff --git a/backend/app/src/test/java/com/ugent/pidgeon/util/GroupUtilTest.java b/backend/app/src/test/java/com/ugent/pidgeon/util/GroupUtilTest.java index 145b1cc9..0870b292 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/util/GroupUtilTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/util/GroupUtilTest.java @@ -317,6 +317,18 @@ public void testCanGetProjectGroupData() throws Exception { when(projectUtil.getProjectIfExists(project.getId())).thenReturn(new CheckResult<>(HttpStatus.I_AM_A_TEAPOT, "", null)); result = groupUtil.canGetProjectGroupData(group.getId(), project.getId(), mockUser); assertEquals(HttpStatus.I_AM_A_TEAPOT, result.getStatus()); + + /* Check if groupId is null (eg: adminsubmission) */ + /* User is admin of project */ + when(projectUtil.getProjectIfExists(project.getId())).thenReturn(new CheckResult<>(HttpStatus.OK, "", project)); + when(projectUtil.isProjectAdmin(project.getId(), mockUser)).thenReturn(new CheckResult<>(HttpStatus.OK, "", null)); + result = groupUtil.canGetProjectGroupData(null, project.getId(), mockUser); + assertEquals(HttpStatus.OK, result.getStatus()); + + /* User is not admin of project */ + when(projectUtil.isProjectAdmin(project.getId(), mockUser)).thenReturn(new CheckResult<>(HttpStatus.FORBIDDEN, "", null)); + result = groupUtil.canGetProjectGroupData(null, project.getId(), mockUser); + assertEquals(HttpStatus.FORBIDDEN, result.getStatus()); } diff --git a/backend/app/src/test/java/com/ugent/pidgeon/util/SubmissionUtilTest.java b/backend/app/src/test/java/com/ugent/pidgeon/util/SubmissionUtilTest.java index 0875693c..e0040ff8 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/util/SubmissionUtilTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/util/SubmissionUtilTest.java @@ -55,7 +55,7 @@ public class SubmissionUtilTest { public void setUp() { submissionEntity = new SubmissionEntity( 22, - 45, + 45L, 99L, OffsetDateTime.MIN, true, @@ -84,7 +84,7 @@ public void setUp() { groupEntity = new GroupEntity( "groupName", - 52L + projectEntity.getGroupClusterId() ); groupEntity.setId(4L); @@ -149,16 +149,27 @@ public void testCheckOnSubmit() { CheckResult result = submissionUtil.checkOnSubmit(projectEntity.getId(), userEntity); assertEquals(HttpStatus.OK, result.getStatus()); + /* User not part of group but admin */ + when(groupRepository.groupIdByProjectAndUser(projectEntity.getId(), userEntity.getId())).thenReturn(null); + when(projectUtil.isProjectAdmin(projectEntity.getId(), userEntity)) + .thenReturn(new CheckResult<>(HttpStatus.OK, "", null)); + result = submissionUtil.checkOnSubmit(projectEntity.getId(), userEntity); + assertEquals(HttpStatus.OK, result.getStatus()); + assertNull(result.getData()); + + /* User not part of group and not admin */ + when(projectUtil.isProjectAdmin(projectEntity.getId(), userEntity)) + .thenReturn(new CheckResult<>(HttpStatus.I_AM_A_TEAPOT, "User is not part of a group for this project", null)); + result = submissionUtil.checkOnSubmit(projectEntity.getId(), userEntity); + assertEquals(HttpStatus.BAD_REQUEST, result.getStatus()); + + when(groupRepository.groupIdByProjectAndUser(projectEntity.getId(), userEntity.getId())).thenReturn(groupEntity.getId()); + /* Deadline passed */ projectEntity.setDeadline(OffsetDateTime.now().minusDays(1)); result = submissionUtil.checkOnSubmit(projectEntity.getId(), userEntity); assertEquals(HttpStatus.FORBIDDEN, result.getStatus()); - /* Project not found */ - when(projectUtil.getProjectIfExists(projectEntity.getId())).thenReturn(new CheckResult<>(HttpStatus.I_AM_A_TEAPOT, "Project not found", null)); - result = submissionUtil.checkOnSubmit(projectEntity.getId(), userEntity); - assertEquals(HttpStatus.I_AM_A_TEAPOT, result.getStatus()); - /* GroupCluster in archived course */ when(groupClusterRepository.inArchivedCourse(groupEntity.getClusterId())).thenReturn(true); result = submissionUtil.checkOnSubmit(projectEntity.getId(), userEntity); @@ -169,15 +180,16 @@ public void testCheckOnSubmit() { result = submissionUtil.checkOnSubmit(projectEntity.getId(), userEntity); assertEquals(HttpStatus.I_AM_A_TEAPOT, result.getStatus()); - /* User not part of group */ - when(groupRepository.groupIdByProjectAndUser(projectEntity.getId(), userEntity.getId())).thenReturn(null); - result = submissionUtil.checkOnSubmit(projectEntity.getId(), userEntity); - assertEquals(HttpStatus.BAD_REQUEST, result.getStatus()); /* User not part of project */ when(projectUtil.userPartOfProject(projectEntity.getId(), userEntity.getId())).thenReturn(false); result = submissionUtil.checkOnSubmit(projectEntity.getId(), userEntity); assertEquals(HttpStatus.FORBIDDEN, result.getStatus()); + + /* Project not found */ + when(projectUtil.getProjectIfExists(projectEntity.getId())).thenReturn(new CheckResult<>(HttpStatus.I_AM_A_TEAPOT, "Project not found", null)); + result = submissionUtil.checkOnSubmit(projectEntity.getId(), userEntity); + assertEquals(HttpStatus.I_AM_A_TEAPOT, result.getStatus()); } diff --git a/backend/app/src/test/test-cases/DockerSubmissionTestTest/d__test.zip b/backend/app/src/test/test-cases/DockerSubmissionTestTest/d__test.zip index 4e389ca3afc1b890a7685fc0d8db9af2ea9be82b..3da4a2af46dec4215c2d51ba9bb08013feeaed40 100644 GIT binary patch delta 28 hcmZ3)xQLNAz?+#xgn@&DgJDO<#)-WC%pfY>8318W2qypl delta 28 hcmZ3)xQLNAz?+#xgn@&DgTW?w^+aBOW)Kzc3; Date: Fri, 17 May 2024 17:54:24 +0200 Subject: [PATCH 04/11] visible_after field works --- .../controllers/ProjectController.java | 20 +++++++++++++++++++ .../pidgeon/model/ProjectResponseJson.java | 3 ++- .../ugent/pidgeon/model/json/ProjectJson.java | 9 +++++++++ .../pidgeon/postgre/models/ProjectEntity.java | 11 ++++++++++ .../pidgeon/util/EntityToJsonConverter.java | 3 ++- backend/database/start_database.sql | 4 +++- 6 files changed, 47 insertions(+), 3 deletions(-) diff --git a/backend/app/src/main/java/com/ugent/pidgeon/controllers/ProjectController.java b/backend/app/src/main/java/com/ugent/pidgeon/controllers/ProjectController.java index 24bf639d..0cefb37c 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/controllers/ProjectController.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/controllers/ProjectController.java @@ -10,6 +10,7 @@ import com.ugent.pidgeon.postgre.models.types.UserRole; import com.ugent.pidgeon.postgre.repository.*; import com.ugent.pidgeon.util.*; +import java.time.OffsetDateTime; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -74,6 +75,10 @@ public ResponseEntity getProjects(Auth auth) { CourseRelation relation = courseCheck.getData().getSecond(); if (relation.equals(CourseRelation.enrolled)) { + if (project.getVisibleAfter() != null && project.getVisibleAfter().isBefore(OffsetDateTime.now())) { + project.setVisible(true); + projectRepository.save(project); + } if (project.isVisible()) { enrolledProjects.add(entityToJsonConverter.projectEntityToProjectResponseJsonWithStatus(project, course, user)); } @@ -113,6 +118,11 @@ public ResponseEntity getProjectById(@PathVariable Long projectId, Auth auth) } CourseEntity course = courseCheck.getData().getFirst(); CourseRelation relation = courseCheck.getData().getSecond(); + Logger.getGlobal().info("project visible after: " + project.getVisibleAfter().toInstant() + " now: " + OffsetDateTime.now().toInstant()); + if (project.getVisibleAfter() != null && project.getVisibleAfter().isBefore(OffsetDateTime.now())) { + project.setVisible(true); + projectRepository.save(project); + } if (!project.isVisible() && relation.equals(CourseRelation.enrolled)) { return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Project not found"); } @@ -161,6 +171,8 @@ public ResponseEntity createProject( projectJson.getGroupClusterId(), null, projectJson.isVisible(), projectJson.getMaxScore(), projectJson.getDeadline()); + project.setVisibleAfter(projectJson.getVisibleAfter()); + // Save the project entity ProjectEntity savedProject = projectRepository.save(project); CourseEntity courseEntity = checkAcces.getData(); @@ -180,6 +192,10 @@ private ResponseEntity doProjectUpdate(ProjectEntity project, ProjectJson pro project.setDeadline(projectJson.getDeadline()); project.setMaxScore(projectJson.getMaxScore()); project.setVisible(projectJson.isVisible()); + project.setVisibleAfter(projectJson.getVisibleAfter()); + if (project.getVisibleAfter() != null && project.getVisibleAfter().isBefore(OffsetDateTime.now())) { + project.setVisible(true); + } projectRepository.save(project); return ResponseEntity.ok(entityToJsonConverter.projectEntityToProjectResponseJson(project, courseRepository.findById(project.getCourseId()).get(), user)); } @@ -261,6 +277,10 @@ public ResponseEntity patchProjectById(@PathVariable Long projectId, @Request projectJson.setVisible(project.isVisible()); } + if (projectJson.getVisibleAfter() == null) { + projectJson.setVisibleAfter(project.getVisibleAfter()); + } + CheckResult checkProject = projectUtil.checkProjectJson(projectJson, project.getCourseId()); if (checkProject.getStatus() != HttpStatus.OK) { return ResponseEntity.status(checkProject.getStatus()).body(checkProject.getMessage()); diff --git a/backend/app/src/main/java/com/ugent/pidgeon/model/ProjectResponseJson.java b/backend/app/src/main/java/com/ugent/pidgeon/model/ProjectResponseJson.java index 88e5e0fe..1b4b0ca3 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/model/ProjectResponseJson.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/model/ProjectResponseJson.java @@ -21,5 +21,6 @@ public record ProjectResponseJson( boolean visible, ProjectProgressJson progress, Long groupId, - Long clusterId + Long clusterId, + OffsetDateTime visibleAfter ) {} diff --git a/backend/app/src/main/java/com/ugent/pidgeon/model/json/ProjectJson.java b/backend/app/src/main/java/com/ugent/pidgeon/model/json/ProjectJson.java index abbf1b22..11c49711 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/model/json/ProjectJson.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/model/json/ProjectJson.java @@ -15,6 +15,7 @@ public class ProjectJson { private Long groupClusterId; private Boolean visible; private Integer maxScore; + private OffsetDateTime visibleAfter; @JsonSerialize(using = OffsetDateTimeSerializer.class) private OffsetDateTime deadline; @@ -79,4 +80,12 @@ public Integer getMaxScore() { public void setMaxScore(Integer maxScore) { this.maxScore = maxScore; } + + public OffsetDateTime getVisibleAfter() { + return visibleAfter; + } + + public void setVisibleAfter(OffsetDateTime visibleAfter) { + this.visibleAfter = visibleAfter; + } } diff --git a/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/ProjectEntity.java b/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/ProjectEntity.java index 67dc778a..0735d649 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/ProjectEntity.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/ProjectEntity.java @@ -38,6 +38,9 @@ public class ProjectEntity { @Column(name="max_score") private Integer maxScore; + @Column(name = "visible_after") + private OffsetDateTime visibleAfter; + public ProjectEntity(long courseId, String name, String description, long groupClusterId, Long testId, Boolean visible, Integer maxScore, OffsetDateTime deadline) { this.courseId = courseId; this.name = name; @@ -124,4 +127,12 @@ public OffsetDateTime getDeadline() { public void setDeadline(OffsetDateTime deadline) { this.deadline = deadline; } + + public OffsetDateTime getVisibleAfter() { + return visibleAfter; + } + + public void setVisibleAfter(OffsetDateTime visibleAfter) { + this.visibleAfter = visibleAfter; + } } diff --git a/backend/app/src/main/java/com/ugent/pidgeon/util/EntityToJsonConverter.java b/backend/app/src/main/java/com/ugent/pidgeon/util/EntityToJsonConverter.java index 716ae1bf..b3d6d525 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/util/EntityToJsonConverter.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/util/EntityToJsonConverter.java @@ -215,7 +215,8 @@ public ProjectResponseJson projectEntityToProjectResponseJson(ProjectEntity proj project.isVisible(), new ProjectProgressJson(completed, total), groupId, - clusterId + clusterId, + project.getVisibleAfter() ); } diff --git a/backend/database/start_database.sql b/backend/database/start_database.sql index 94cf30e6..4b7f936d 100644 --- a/backend/database/start_database.sql +++ b/backend/database/start_database.sql @@ -9,6 +9,7 @@ CREATE TABLE users ( email VARCHAR(100) UNIQUE NOT NULL, azure_id VARCHAR(255) NOT NULL, role VARCHAR(50) NOT NULL, + studentnumber VARCHAR(50), created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP ); @@ -73,7 +74,8 @@ CREATE TABLE projects ( deadline TIMESTAMP WITH TIME ZONE NOT NULL, test_id INT REFERENCES tests(test_id), visible BOOLEAN DEFAULT false NOT NULL, - max_score INT + max_score INT, + visible_after TIMESTAMP WITH TIME ZONE DEFAULT NULL ); From 4f94fb40d32e6b4de36728ef3f1ec30886b40290 Mon Sep 17 00:00:00 2001 From: Aqua-sc <108478185+Aqua-sc@users.noreply.github.com> Date: Fri, 17 May 2024 18:04:11 +0200 Subject: [PATCH 05/11] Added studentnumber fields --- .../ugent/pidgeon/auth/JwtAuthenticationFilter.java | 7 +++++-- .../java/com/ugent/pidgeon/auth/RolesInterceptor.java | 2 +- .../src/main/java/com/ugent/pidgeon/model/Auth.java | 1 + .../src/main/java/com/ugent/pidgeon/model/User.java | 4 +++- .../com/ugent/pidgeon/postgre/models/UserEntity.java | 11 ++++++++++- 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/backend/app/src/main/java/com/ugent/pidgeon/auth/JwtAuthenticationFilter.java b/backend/app/src/main/java/com/ugent/pidgeon/auth/JwtAuthenticationFilter.java index a4ba6cfc..cf8cd406 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/auth/JwtAuthenticationFilter.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/auth/JwtAuthenticationFilter.java @@ -83,6 +83,7 @@ public void doFilterInternal(HttpServletRequest request, HttpServletResponse res String lastName; String email; String oid; + String studentnumber; String version = jwt.getClaim("ver").asString(); @@ -92,21 +93,23 @@ public void doFilterInternal(HttpServletRequest request, HttpServletResponse res lastName = jwt.getClaim("family_name").asString(); email = jwt.getClaim("unique_name").asString(); oid = jwt.getClaim("oid").asString(); + studentnumber = jwt.getClaim("studentnumber").asString(); } else if (version.startsWith("2.0")) { displayName = jwt.getClaim("name").asString(); lastName = jwt.getClaim("surname").asString(); firstName = displayName.replace(lastName, "").strip(); email = jwt.getClaim("mail").asString(); oid = jwt.getClaim("oid").asString(); + studentnumber = jwt.getClaim("studentnumber").asString(); } else { throw new JwkException("Invalid OAuth version"); } // print full object - // logger.info(jwt.getClaims()); + logger.info(jwt.getClaims()); - User user = new User(displayName, firstName,lastName, email, oid); + User user = new User(displayName, firstName,lastName, email, oid, studentnumber); Auth authUser = new Auth(user, new ArrayList<>()); SecurityContextHolder.getContext().setAuthentication(authUser); diff --git a/backend/app/src/main/java/com/ugent/pidgeon/auth/RolesInterceptor.java b/backend/app/src/main/java/com/ugent/pidgeon/auth/RolesInterceptor.java index 17952d89..b3f5950a 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/auth/RolesInterceptor.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/auth/RolesInterceptor.java @@ -61,7 +61,7 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons if(userEntity == null) { System.out.println("User does not exist, creating new one. user_id: " + auth.getOid()); - userEntity = new UserEntity(auth.getUser().firstName,auth.getUser().lastName, auth.getEmail(), UserRole.student, auth.getOid()); + userEntity = new UserEntity(auth.getUser().firstName,auth.getUser().lastName, auth.getEmail(), UserRole.student, auth.getOid(), auth.getStudentNumber()); OffsetDateTime now = OffsetDateTime.now(); userEntity.setCreatedAt(now); userEntity = userRepository.save(userEntity); diff --git a/backend/app/src/main/java/com/ugent/pidgeon/model/Auth.java b/backend/app/src/main/java/com/ugent/pidgeon/model/Auth.java index 4add2b68..2ebd970e 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/model/Auth.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/model/Auth.java @@ -29,6 +29,7 @@ public String getName(){ public String getEmail(){ return user.email; } + public String getStudentNumber() { return user.studentnumber; } public String getOid(){ return user.oid; diff --git a/backend/app/src/main/java/com/ugent/pidgeon/model/User.java b/backend/app/src/main/java/com/ugent/pidgeon/model/User.java index 330c74e7..0ce04625 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/model/User.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/model/User.java @@ -9,12 +9,14 @@ public class User { public String lastName; public String email; public String oid; + public String studentnumber; - public User (String name, String firstName, String lastName, String email, String oid) { + public User (String name, String firstName, String lastName, String email, String oid, String studentnumber) { this.name = name; this.email = email; this.oid = oid; this.firstName = firstName; this.lastName = lastName; + this.studentnumber = studentnumber; } } \ No newline at end of file diff --git a/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/UserEntity.java b/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/UserEntity.java index d39ac2cc..0addda2d 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/UserEntity.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/UserEntity.java @@ -34,12 +34,17 @@ public class UserEntity { @Column(name = "created_at") private OffsetDateTime createdAt; - public UserEntity(String name, String surname, String email, UserRole role, String azureId) { + @Column(name = "studentnumber") + private String studentNumber; + + public UserEntity(String name, String surname, String email, UserRole role, String azureId, + String studentNumber) { this.name = name; this.surname = surname; this.email = email; this.role = role.toString(); this.azureId = azureId; + this.studentNumber = studentNumber; } public UserEntity() { @@ -110,5 +115,9 @@ public OffsetDateTime getCreatedAt() { public void setCreatedAt(OffsetDateTime createdAt) { this.createdAt = createdAt; } + + public String getStudentNumber() { + return studentNumber; + } } From e106cd885e9d9136c4590fee6993e51351ba9d78 Mon Sep 17 00:00:00 2001 From: Aqua-sc <108478185+Aqua-sc@users.noreply.github.com> Date: Fri, 17 May 2024 18:42:25 +0200 Subject: [PATCH 06/11] Update tests --- .../controllers/ProjectController.java | 2 +- .../pidgeon/controllers/ControllerTest.java | 5 +- .../controllers/CourseControllerTest.java | 9 +- .../GroupMembersControllerTest.java | 4 +- .../controllers/ProjectControllerTest.java | 115 ++++++++++++++++-- .../controllers/UserControllerTest.java | 6 +- .../com/ugent/pidgeon/model/AuthTest.java | 2 +- .../com/ugent/pidgeon/model/UserTest.java | 2 +- .../ugent/pidgeon/util/ClusterUtilTest.java | 2 +- .../ugent/pidgeon/util/CourseUtilTest.java | 2 +- .../util/EntityToJsonConverterTest.java | 13 +- .../pidgeon/util/GroupFeedbackUtilTest.java | 2 +- .../com/ugent/pidgeon/util/GroupUtilTest.java | 4 +- .../ugent/pidgeon/util/ProjectUtilTest.java | 2 +- .../pidgeon/util/SubmissionUtilTest.java | 3 +- .../com/ugent/pidgeon/util/TestUtilTest.java | 3 +- .../com/ugent/pidgeon/util/UserUtilTest.java | 2 +- .../DockerSubmissionTestTest/d__test.zip | Bin 162 -> 162 bytes 18 files changed, 143 insertions(+), 35 deletions(-) diff --git a/backend/app/src/main/java/com/ugent/pidgeon/controllers/ProjectController.java b/backend/app/src/main/java/com/ugent/pidgeon/controllers/ProjectController.java index 0cefb37c..6d3f5742 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/controllers/ProjectController.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/controllers/ProjectController.java @@ -118,7 +118,7 @@ public ResponseEntity getProjectById(@PathVariable Long projectId, Auth auth) } CourseEntity course = courseCheck.getData().getFirst(); CourseRelation relation = courseCheck.getData().getSecond(); - Logger.getGlobal().info("project visible after: " + project.getVisibleAfter().toInstant() + " now: " + OffsetDateTime.now().toInstant()); + if (project.getVisibleAfter() != null && project.getVisibleAfter().isBefore(OffsetDateTime.now())) { project.setVisible(true); projectRepository.save(project); diff --git a/backend/app/src/test/java/com/ugent/pidgeon/controllers/ControllerTest.java b/backend/app/src/test/java/com/ugent/pidgeon/controllers/ControllerTest.java index b506e8b6..c0e6a073 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/controllers/ControllerTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/controllers/ControllerTest.java @@ -47,7 +47,7 @@ public class ControllerTest { public void testSetUp() { MockitoAnnotations.openMocks(this); - User user = new User("displayName", "firstName", "lastName", "email", "test"); + User user = new User("displayName", "firstName", "lastName", "email", "test", "studentnummer"); Auth authUser = new Auth(user, new ArrayList<>()); SecurityContextHolder.getContext().setAuthentication(authUser); @@ -57,7 +57,8 @@ public void testSetUp() { user.lastName, user.email, UserRole.teacher, - user.oid + user.oid, + "studentnummer" ); mockUser.setId(1L); authUser.setUserEntity(mockUser); diff --git a/backend/app/src/test/java/com/ugent/pidgeon/controllers/CourseControllerTest.java b/backend/app/src/test/java/com/ugent/pidgeon/controllers/CourseControllerTest.java index f80af245..6fe060c0 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/controllers/CourseControllerTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/controllers/CourseControllerTest.java @@ -626,7 +626,8 @@ public void testGetProjectsByCourseId() throws Exception { true, new ProjectProgressJson(1, 1), 1L, - 1L + 1L, + OffsetDateTime.now() ); /* If user is in course, return projects */ when(courseUtil.getCourseIfUserInCourse(activeCourse.getId(),getMockUser())) @@ -831,7 +832,7 @@ public void testAddCourseMember() throws Exception { String requestStringAdmin = "{\"userId\": 1, \"relation\": \"course_admin\"}"; String url = ApiRoutes.COURSE_BASE_PATH + "/" + activeCourse.getId() + "/members"; CourseUserEntity courseUser = new CourseUserEntity(activeCourse.getId(), 1, CourseRelation.enrolled); - UserEntity user = new UserEntity("name", "surname", "email", UserRole.teacher, "id"); + UserEntity user = new UserEntity("name", "surname", "email", UserRole.teacher, "id", ""); /* If all checks succeed, return 201 */ when(courseUtil.canUpdateUserInCourse( @@ -907,7 +908,7 @@ public void testUpdateCourseMember() throws Exception { String url = ApiRoutes.COURSE_BASE_PATH + "/" + activeCourse.getId() + "/members/" + userId; String request = "{\"relation\": \"enrolled\"}"; String adminRequest = "{\"relation\": \"course_admin\"}"; - UserEntity user = new UserEntity("name", "surname", "email", UserRole.teacher, "id"); + UserEntity user = new UserEntity("name", "surname", "email", UserRole.teacher, "id", ""); CourseUserEntity enrolledUser = new CourseUserEntity(activeCourse.getId(), userId, CourseRelation.enrolled); CourseUserEntity adminUser = new CourseUserEntity(activeCourse.getId(), userId, CourseRelation.course_admin); /* If all checks succeed, 200 gets returned */ @@ -1004,7 +1005,7 @@ public void testUpdateCourseMember() throws Exception { @Test public void testGetCourseMembers() throws Exception { CourseUserEntity courseUserEntity = new CourseUserEntity(1L, 1L, CourseRelation.enrolled); - UserEntity user = new UserEntity("name", "surname", "email", UserRole.teacher, "id"); + UserEntity user = new UserEntity("name", "surname", "email", UserRole.teacher, "id", ""); UserReferenceWithRelation userJson = new UserReferenceWithRelation( new UserReferenceJson("name", "surname", 1L), ""+CourseRelation.enrolled diff --git a/backend/app/src/test/java/com/ugent/pidgeon/controllers/GroupMembersControllerTest.java b/backend/app/src/test/java/com/ugent/pidgeon/controllers/GroupMembersControllerTest.java index 70fd1ac9..8793a7dd 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/controllers/GroupMembersControllerTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/controllers/GroupMembersControllerTest.java @@ -54,9 +54,9 @@ public class GroupMembersControllerTest extends ControllerTest { @BeforeEach public void setup() { setUpController(groupMemberController); - userEntity = new UserEntity("name", "surname", "email", UserRole.student, "azureid"); + userEntity = new UserEntity("name", "surname", "email", UserRole.student, "azureid", ""); userEntity.setId(5L); - userEntity2 = new UserEntity("name2", "surname2", "email2", UserRole.student, "azureid2"); + userEntity2 = new UserEntity("name2", "surname2", "email2", UserRole.student, "azureid2", ""); userEntity2.setId(6L); userReferenceJson = new UserReferenceJson(userEntity.getName(), userEntity.getEmail(), userEntity.getId()); userReferenceJson2 = new UserReferenceJson(userEntity2.getName(), userEntity2.getEmail(), userEntity2.getId()); diff --git a/backend/app/src/test/java/com/ugent/pidgeon/controllers/ProjectControllerTest.java b/backend/app/src/test/java/com/ugent/pidgeon/controllers/ProjectControllerTest.java index e95b0b5b..5e0545c4 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/controllers/ProjectControllerTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/controllers/ProjectControllerTest.java @@ -35,6 +35,8 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -118,7 +120,8 @@ void setUp() { projectEntity.isVisible(), new ProjectProgressJson(0, 0), 1L, - groupClusterId + groupClusterId, + OffsetDateTime.now() ); projectEntity2 = new ProjectEntity( @@ -144,7 +147,8 @@ void setUp() { projectEntity2.isVisible(), new ProjectProgressJson(0, 0), 1L, - groupClusterId + groupClusterId, + OffsetDateTime.now() ); } @@ -180,17 +184,46 @@ void testGetProjects() throws Exception { .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(content().json(objectMapper.writeValueAsString(userProjectsJson))); - /* If project is visible and role enrolled, don't return it */ + /* If project isn't visible and role enrolled, don't return it */ + projectEntity2.setVisible(false); + userProjectsJson = new UserProjectsJson( + Collections.emptyList(), + List.of(projectResponseJson) + ); + mockMvc.perform(MockMvcRequestBuilders.get(url)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(content().json(objectMapper.writeValueAsString(userProjectsJson))); + + /* If project isn't visible but visibleAfter is passed, update visibility */ + projectEntity2.setVisibleAfter(OffsetDateTime.now().minusDays(1)); + userProjectsJson = new UserProjectsJson( + List.of(projectJsonWithStatus), + List.of(projectResponseJson) + ); + mockMvc.perform(MockMvcRequestBuilders.get(url)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(content().json(objectMapper.writeValueAsString(userProjectsJson))); + + verify(projectRepository, times(1)).save(projectEntity2); + assertTrue(projectEntity2.isVisible()); + + /* If project isn't visible and visibleAfter is in the future, don't return it */ projectEntity2.setVisible(false); + projectEntity2.setVisibleAfter(OffsetDateTime.now().plusDays(1)); userProjectsJson = new UserProjectsJson( Collections.emptyList(), List.of(projectResponseJson) ); + mockMvc.perform(MockMvcRequestBuilders.get(url)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(content().json(objectMapper.writeValueAsString(userProjectsJson))); + assertFalse(projectEntity2.isVisible()); + /* If a coursecheck fails, return corresponding status */ when(courseUtil.getCourseIfUserInCourse(courseEntity.getId(), getMockUser())).thenReturn( new CheckResult<>(HttpStatus.I_AM_A_TEAPOT, "", null) @@ -222,6 +255,22 @@ void testGetProject() throws Exception { mockMvc.perform(MockMvcRequestBuilders.get(url)) .andExpect(status().isNotFound()); + /* if visibleAfter is passed, update visibility */ + projectEntity.setVisibleAfter(OffsetDateTime.now().minusDays(1)); + mockMvc.perform(MockMvcRequestBuilders.get(url)) + .andExpect(status().isOk()); + + verify(projectRepository, times(1)).save(projectEntity); + assertTrue(projectEntity.isVisible()); + + /* If visibleAfter is in the future, return 404 */ + projectEntity.setVisible(false); + projectEntity.setVisibleAfter(OffsetDateTime.now().plusDays(1)); + mockMvc.perform(MockMvcRequestBuilders.get(url)) + .andExpect(status().isNotFound()); + + assertFalse(projectEntity.isVisible()); + /* If user is not enrolled and project not visible, return project */ when(courseUtil.getCourseIfUserInCourse(projectEntity.getCourseId(), getMockUser())).thenReturn( new CheckResult<>(HttpStatus.OK, "", new Pair<>(courseEntity, CourseRelation.course_admin)) @@ -249,13 +298,15 @@ void testGetProject() throws Exception { @Test public void testCreateProject() throws Exception { String url = ApiRoutes.COURSE_BASE_PATH + "/" + courseEntity.getId() + "/projects"; + projectEntity.setVisibleAfter(OffsetDateTime.now().plusDays(1)); String request = "{\n" + " \"name\": \"" + projectEntity.getName() + "\",\n" + " \"description\": \"" + projectEntity.getDescription() + "\",\n" + " \"groupClusterId\": " + projectEntity.getGroupClusterId() + ",\n" + " \"visible\": " + projectEntity.isVisible() + ",\n" + " \"maxScore\": " + projectEntity.getMaxScore() + ",\n" + - " \"deadline\": \"" + projectEntity.getDeadline() + "\"\n" + + " \"deadline\": \"" + projectEntity.getDeadline() + "\",\n" + + " \"visibleAfter\": \"" + projectEntity.getVisibleAfter() + "\"\n" + "}"; /* If all checks succeed, create course */ @@ -287,6 +338,7 @@ public void testCreateProject() throws Exception { && project.isVisible().equals(projectEntity.isVisible()) && project.getMaxScore().equals(projectEntity.getMaxScore()) && project.getDeadline().toInstant().equals(projectEntity.getDeadline().toInstant()) + && project.getVisibleAfter().toInstant().equals(projectEntity.getVisibleAfter().toInstant()) )); /* If groupClusterId is not provided, use invalid groupClusterId */ @@ -387,7 +439,8 @@ void testPutProjectById() throws Exception { false, new ProjectProgressJson(0, 0), 1L, - groupClusterId * 4 + groupClusterId * 4, + OffsetDateTime.now() ); /* If all checks pass, update and return the project */ when(projectUtil.getProjectIfAdmin(projectEntity.getId(), getMockUser())).thenReturn( @@ -426,6 +479,48 @@ void testPutProjectById() throws Exception { projectEntity.setMaxScore(orginalMaxScore); projectEntity.setDeadline(orginalDeadline); + /* If visible after is passed, update visibility */ + projectEntity.setVisibleAfter(OffsetDateTime.now().minusDays(1)); + request = "{\n" + + " \"name\": \"" + "UpdatedName" + "\",\n" + + " \"description\": \"" + "UpdatedDescription" + "\",\n" + + " \"groupClusterId\": " + groupClusterId * 4 + ",\n" + + " \"visible\": " + false + ",\n" + + " \"maxScore\": " + (projectEntity.getMaxScore() + 33) + ",\n" + + " \"deadline\": \"" + newDeadline + "\",\n" + + " \"visibleAfter\": \"" + OffsetDateTime.now().minusDays(1) + "\"\n" + + "}"; + mockMvc.perform(MockMvcRequestBuilders.put(url) + .contentType(MediaType.APPLICATION_JSON) + .content(request)); + + verify(projectRepository, times(2)).save(projectEntity); + assertTrue(projectEntity.isVisible()); + + /* If visible after isn't passed, don't update visibility */ + projectEntity.setVisible(false); + request = "{\n" + + " \"name\": \"" + "UpdatedName" + "\",\n" + + " \"description\": \"" + "UpdatedDescription" + "\",\n" + + " \"groupClusterId\": " + groupClusterId * 4 + ",\n" + + " \"visible\": " + false + ",\n" + + " \"maxScore\": " + (projectEntity.getMaxScore() + 33) + ",\n" + + " \"deadline\": \"" + newDeadline + "\",\n" + + " \"visibleAfter\": \"" + OffsetDateTime.now().plusDays(1) + "\"\n" + + "}"; + mockMvc.perform(MockMvcRequestBuilders.put(url) + .contentType(MediaType.APPLICATION_JSON) + .content(request)); + + assertFalse(projectEntity.isVisible()); + + projectEntity.setName(orginalName); + projectEntity.setDescription(orginalDescription); + projectEntity.setGroupClusterId(orginalGroupClusterId); + projectEntity.setVisible(orginalVisible); + projectEntity.setMaxScore(orginalMaxScore); + projectEntity.setDeadline(orginalDeadline); + /* If groupClusterId is not provided, use invalid groupClusterId */ reset(projectUtil); request = "{\n" + @@ -461,9 +556,11 @@ void testPutProjectById() throws Exception { assertEquals(projectEntity.isVisible(), false); assertEquals(projectEntity.getMaxScore(), orginalMaxScore + 33); assertEquals(projectEntity.getDeadline().toInstant(), newDeadline.toInstant()); - verify(projectRepository, times(2)).save(projectEntity); + verify(projectRepository, times(4)).save(projectEntity); projectEntity.setGroupClusterId(orginalGroupClusterId); + + /* If project json is invalid, return corresponding status */ reset(projectUtil); when(projectUtil.getProjectIfAdmin(projectEntity.getId(), getMockUser())).thenReturn( @@ -504,7 +601,8 @@ void testPatchProjectById() throws Exception { " \"groupClusterId\": " + groupClusterId * 4 + ",\n" + " \"visible\": " + false + ",\n" + " \"maxScore\": " + (projectEntity.getMaxScore() + 33) + ",\n" + - " \"deadline\": \"" + newDeadline + "\"\n" + + " \"deadline\": \"" + newDeadline + "\",\n" + + " \"visibleAfter\": \"" + OffsetDateTime.now().plusDays(1) + "\"\n" + "}"; String orginalName = projectEntity.getName(); String orginalDescription = projectEntity.getDescription(); @@ -524,7 +622,8 @@ void testPatchProjectById() throws Exception { false, new ProjectProgressJson(0, 0), 1L, - groupClusterId * 4 + groupClusterId * 4, + OffsetDateTime.now() ); /* If all checks pass, update and return the project */ when(projectUtil.getProjectIfAdmin(projectEntity.getId(), getMockUser())).thenReturn( diff --git a/backend/app/src/test/java/com/ugent/pidgeon/controllers/UserControllerTest.java b/backend/app/src/test/java/com/ugent/pidgeon/controllers/UserControllerTest.java index a60a6cf2..53d3c904 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/controllers/UserControllerTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/controllers/UserControllerTest.java @@ -49,7 +49,7 @@ public class UserControllerTest extends ControllerTest { @BeforeEach public void setup() { setUpController(userController); - userEntity = new UserEntity("Bob", "Testman", "email", UserRole.student, "azureId"); + userEntity = new UserEntity("Bob", "Testman", "email", UserRole.student, "azureId", ""); userEntity.setId(74L); mockUserJson = new UserJson(getMockUser()); userJson = new UserJson(userEntity); @@ -260,7 +260,7 @@ public void testUpdateUserById() throws Exception { setMockUserRoles(UserRole.admin); String url = ApiRoutes.USERS_BASE_PATH + "/" + userEntity.getId(); String request = "{\"name\":\"John\",\"surname\":\"Doe\",\"email\":\"john@example.com\",\"role\":\"teacher\"}"; - UserEntity updateUserEntity = new UserEntity("John", "Doe", "john@example.com", UserRole.teacher, "azureId"); + UserEntity updateUserEntity = new UserEntity("John", "Doe", "john@example.com", UserRole.teacher, "azureId", ""); updateUserEntity.setId(userEntity.getId()); UserJson updatedUserJson = new UserJson(updateUserEntity); @@ -311,7 +311,7 @@ public void testPatchUserById() throws Exception { setMockUserRoles(UserRole.admin); String url = ApiRoutes.USERS_BASE_PATH + "/" + userEntity.getId(); String request = "{\"name\":\"John\",\"surname\":\"Doe\",\"email\":\"john@example.com\",\"role\":\"teacher\"}"; - UserEntity updateUserEntity = new UserEntity("John", "Doe", "john@example.com", UserRole.teacher, "azureId"); + UserEntity updateUserEntity = new UserEntity("John", "Doe", "john@example.com", UserRole.teacher, "azureId", ""); updateUserEntity.setId(userEntity.getId()); UserJson updatedUserJson = new UserJson(updateUserEntity); String originalName = userEntity.getName(); diff --git a/backend/app/src/test/java/com/ugent/pidgeon/model/AuthTest.java b/backend/app/src/test/java/com/ugent/pidgeon/model/AuthTest.java index 6f415d42..738f922f 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/model/AuthTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/model/AuthTest.java @@ -10,7 +10,7 @@ public class AuthTest { - private final User testUser = new User("John Doe", "John", "Doe", "john.doe@gmail.com", "123456"); + private final User testUser = new User("John Doe", "John", "Doe", "john.doe@gmail.com", "123456", ""); private final List authLijst = List.of(new SimpleGrantedAuthority("READ_AUTHORITY")); private final Auth auth = new Auth(testUser, authLijst); diff --git a/backend/app/src/test/java/com/ugent/pidgeon/model/UserTest.java b/backend/app/src/test/java/com/ugent/pidgeon/model/UserTest.java index 38e15043..e410fca3 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/model/UserTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/model/UserTest.java @@ -5,7 +5,7 @@ public class UserTest { - private final User testUser = new User("John Doe", "John", "Doe", "john.doe@gmail.com", "123456"); + private final User testUser = new User("John Doe", "John", "Doe", "john.doe@gmail.com", "123456", ""); @Test public void isNotNull() { diff --git a/backend/app/src/test/java/com/ugent/pidgeon/util/ClusterUtilTest.java b/backend/app/src/test/java/com/ugent/pidgeon/util/ClusterUtilTest.java index 37588085..b2450230 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/util/ClusterUtilTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/util/ClusterUtilTest.java @@ -54,7 +54,7 @@ public class ClusterUtilTest { public void setUp() { clusterEntity = new GroupClusterEntity(1L, 20, "clustername", 5); clusterEntity.setId(4L); - mockUser = new UserEntity("name", "surname", "email", UserRole.student, "azureid"); + mockUser = new UserEntity("name", "surname", "email", UserRole.student, "azureid", ""); } @Test diff --git a/backend/app/src/test/java/com/ugent/pidgeon/util/CourseUtilTest.java b/backend/app/src/test/java/com/ugent/pidgeon/util/CourseUtilTest.java index 089851cb..f5593dad 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/util/CourseUtilTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/util/CourseUtilTest.java @@ -56,7 +56,7 @@ public class CourseUtilTest { @BeforeEach public void setUp() { - user = new UserEntity("name", "surname", "email", UserRole.student, "azureid"); + user = new UserEntity("name", "surname", "email", UserRole.student, "azureid", ""); user.setId(44L); course = new CourseEntity("name", "description",2024); course.setId(9L); diff --git a/backend/app/src/test/java/com/ugent/pidgeon/util/EntityToJsonConverterTest.java b/backend/app/src/test/java/com/ugent/pidgeon/util/EntityToJsonConverterTest.java index fa1a2daa..de5c788f 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/util/EntityToJsonConverterTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/util/EntityToJsonConverterTest.java @@ -131,7 +131,8 @@ public void setUp() { "surname", "email", UserRole.student, - "azureId" + "azureId", + "" ); userEntity.setId(44L); userReferenceJson = new UserReferenceJson( @@ -145,7 +146,8 @@ public void setUp() { "otherSurname", "otherEmail", UserRole.student, - "otherAzureId" + "otherAzureId", + "" ); otherUserReferenceJson = new UserReferenceJson( otherUser.getName() + " " + otherUser.getSurname(), @@ -190,7 +192,8 @@ public void setUp() { projectEntity.isVisible(), new ProjectProgressJson(44, 60), groupEntity.getId(), - groupClusterEntity.getId() + groupClusterEntity.getId(), + OffsetDateTime.now() ); groupFeedbackEntity = new GroupFeedbackEntity( @@ -416,7 +419,7 @@ public void testProjectEntityToProjectResponseJson() { GroupEntity secondGroup = new GroupEntity("secondGroup", groupClusterEntity.getId()); SubmissionEntity secondSubmission = new SubmissionEntity(22, 232, 90L, OffsetDateTime.MIN, true, true); CourseUserEntity courseUser = new CourseUserEntity(projectEntity.getCourseId(), userEntity.getId(), CourseRelation.creator); - + projectEntity.setVisibleAfter(OffsetDateTime.now()); when(projectRepository.findGroupIdsByProjectId(projectEntity.getId())).thenReturn(List.of(groupEntity.getId(), secondGroup.getId())); when(submissionRepository.findLatestsSubmissionIdsByProjectAndGroupId(projectEntity.getId(), groupEntity.getId())).thenReturn(Optional.of(submissionEntity)); when(submissionRepository.findLatestsSubmissionIdsByProjectAndGroupId(projectEntity.getId(), secondGroup.getId())).thenReturn(Optional.of(secondSubmission)); @@ -443,6 +446,8 @@ public void testProjectEntityToProjectResponseJson() { assertEquals(2, result.progress().total()); assertNull(result.groupId()); // User is a creator/course_admin -> no group assertEquals(groupClusterEntity.getId(), result.clusterId()); + assertEquals(projectEntity.getVisibleAfter(), result.visibleAfter()); + /* TestId is null */ projectEntity.setTestId(null); diff --git a/backend/app/src/test/java/com/ugent/pidgeon/util/GroupFeedbackUtilTest.java b/backend/app/src/test/java/com/ugent/pidgeon/util/GroupFeedbackUtilTest.java index 6eb7581c..506d1607 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/util/GroupFeedbackUtilTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/util/GroupFeedbackUtilTest.java @@ -52,7 +52,7 @@ public void setup() { 10.0f, "Good job!" ); - mockUser = new UserEntity("name", "surname", "email", UserRole.student, "azureid"); + mockUser = new UserEntity("name", "surname", "email", UserRole.student, "azureid", ""); mockUser.setId(2L); projectEntity = new ProjectEntity( 13L, diff --git a/backend/app/src/test/java/com/ugent/pidgeon/util/GroupUtilTest.java b/backend/app/src/test/java/com/ugent/pidgeon/util/GroupUtilTest.java index 145b1cc9..f02bcc17 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/util/GroupUtilTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/util/GroupUtilTest.java @@ -50,7 +50,7 @@ public class GroupUtilTest { public void setup() { group = new GroupEntity("Groupname", 12L); group.setId(54L); - mockUser = new UserEntity("name", "surname", "email", UserRole.student, "azureid"); + mockUser = new UserEntity("name", "surname", "email", UserRole.student, "azureid", ""); mockUser.setId(10L); groupCluster = new GroupClusterEntity(9L, 5, "cluster test", 20); groupCluster.setId(12L); @@ -137,7 +137,7 @@ public void testCanUpdateGroup() { @Test public void TestCanAddUserToGroup() { long otherUserId = 5L; - UserEntity otherUser = new UserEntity("othername", "othersurname", "otheremail", UserRole.student, "otherazureid"); + UserEntity otherUser = new UserEntity("othername", "othersurname", "otheremail", UserRole.student, "otherazureid", ""); /* All checks succeed */ /* Trying to add yourself to the group */ when(groupRepository.findById(group.getId())).thenReturn(Optional.of(group)); diff --git a/backend/app/src/test/java/com/ugent/pidgeon/util/ProjectUtilTest.java b/backend/app/src/test/java/com/ugent/pidgeon/util/ProjectUtilTest.java index 85ad1db1..347b36a3 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/util/ProjectUtilTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/util/ProjectUtilTest.java @@ -52,7 +52,7 @@ public void setUp() { ); projectEntity.setId(64); - mockUser = new UserEntity("name", "surname", "email", UserRole.student, "azureid"); + mockUser = new UserEntity("name", "surname", "email", UserRole.student, "azureid", ""); mockUser.setId(10L); } diff --git a/backend/app/src/test/java/com/ugent/pidgeon/util/SubmissionUtilTest.java b/backend/app/src/test/java/com/ugent/pidgeon/util/SubmissionUtilTest.java index 0875693c..3930c212 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/util/SubmissionUtilTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/util/SubmissionUtilTest.java @@ -78,7 +78,8 @@ public void setUp() { "surname", "email", UserRole.student, - "azureId" + "azureId", + "" ); userEntity.setId(44L); diff --git a/backend/app/src/test/java/com/ugent/pidgeon/util/TestUtilTest.java b/backend/app/src/test/java/com/ugent/pidgeon/util/TestUtilTest.java index 3f132ec0..c3ae300b 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/util/TestUtilTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/util/TestUtilTest.java @@ -64,7 +64,8 @@ public void setUp() { "surname", "email", UserRole.student, - "azureId" + "azureId", + "" ); userEntity.setId(44L); testEntity = new TestEntity( diff --git a/backend/app/src/test/java/com/ugent/pidgeon/util/UserUtilTest.java b/backend/app/src/test/java/com/ugent/pidgeon/util/UserUtilTest.java index bd9a059f..b9706a56 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/util/UserUtilTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/util/UserUtilTest.java @@ -34,7 +34,7 @@ public class UserUtilTest { @BeforeEach public void setUp() { - user = new UserEntity("name", "surname", "email", UserRole.student, "azureid"); + user = new UserEntity("name", "surname", "email", UserRole.student, "azureid", ""); user.setId(87L); } diff --git a/backend/app/src/test/test-cases/DockerSubmissionTestTest/d__test.zip b/backend/app/src/test/test-cases/DockerSubmissionTestTest/d__test.zip index 4e389ca3afc1b890a7685fc0d8db9af2ea9be82b..d50e8b5a1ff565803ba5881494ffcdb3e354bad5 100644 GIT binary patch delta 28 hcmZ3)xQLNAz?+#xgn@&DgCT3m#)-WC%pfY>830^T2crN0 delta 28 hcmZ3)xQLNAz?+#xgn@&DgTW?w^+aBOW)Kzc3; Date: Fri, 17 May 2024 20:14:23 +0200 Subject: [PATCH 07/11] Add studentnumber to user(reference)json Hide if the user requesting it is not an admin of the course --- .../pidgeon/auth/JwtAuthenticationFilter.java | 6 ++--- .../controllers/ClusterController.java | 20 +++++++++----- .../pidgeon/controllers/CourseController.java | 4 ++- .../pidgeon/controllers/GroupController.java | 16 ++++++++++-- .../controllers/GroupMemberController.java | 14 +++++++--- .../controllers/ProjectController.java | 10 ++++--- .../controllers/SubmissionController.java | 2 +- .../ugent/pidgeon/model/json/UserJson.java | 9 +++++++ .../pidgeon/model/json/UserReferenceJson.java | 11 +++++++- .../postgre/repository/GroupRepository.java | 3 ++- .../pidgeon/util/EntityToJsonConverter.java | 26 ++++++++++++------- 11 files changed, 89 insertions(+), 32 deletions(-) diff --git a/backend/app/src/main/java/com/ugent/pidgeon/auth/JwtAuthenticationFilter.java b/backend/app/src/main/java/com/ugent/pidgeon/auth/JwtAuthenticationFilter.java index cf8cd406..1ad279e6 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/auth/JwtAuthenticationFilter.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/auth/JwtAuthenticationFilter.java @@ -93,22 +93,20 @@ public void doFilterInternal(HttpServletRequest request, HttpServletResponse res lastName = jwt.getClaim("family_name").asString(); email = jwt.getClaim("unique_name").asString(); oid = jwt.getClaim("oid").asString(); - studentnumber = jwt.getClaim("studentnumber").asString(); + studentnumber = jwt.getClaim("ugentStudentID").asString(); } else if (version.startsWith("2.0")) { displayName = jwt.getClaim("name").asString(); lastName = jwt.getClaim("surname").asString(); firstName = displayName.replace(lastName, "").strip(); email = jwt.getClaim("mail").asString(); oid = jwt.getClaim("oid").asString(); - studentnumber = jwt.getClaim("studentnumber").asString(); + studentnumber = jwt.getClaim("ugentStudentID").asString(); } else { throw new JwkException("Invalid OAuth version"); } // print full object logger.info(jwt.getClaims()); - - User user = new User(displayName, firstName,lastName, email, oid, studentnumber); Auth authUser = new Auth(user, new ArrayList<>()); diff --git a/backend/app/src/main/java/com/ugent/pidgeon/controllers/ClusterController.java b/backend/app/src/main/java/com/ugent/pidgeon/controllers/ClusterController.java index 6508be3c..55f01119 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/controllers/ClusterController.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/controllers/ClusterController.java @@ -65,10 +65,15 @@ public ResponseEntity getClustersForCourse(@PathVariable("courseid") Long cou if (checkResult.getStatus() != HttpStatus.OK) { return ResponseEntity.status(checkResult.getStatus()).body(checkResult.getMessage()); } + + CourseRelation courseRelation = checkResult.getData().getSecond(); + boolean hideStudentNumber = courseRelation.equals(CourseRelation.enrolled); + // Get the clusters for the course List clusters = groupClusterRepository.findClustersWithoutInvidualByCourseId(courseid); List clusterJsons = clusters.stream().map( - entityToJsonConverter::clusterEntityToClusterJson).toList(); + g -> entityToJsonConverter.clusterEntityToClusterJson(g, hideStudentNumber) + ).toList(); // Return the clusters return ResponseEntity.ok(clusterJsons); } @@ -113,7 +118,7 @@ public ResponseEntity createClusterForCourse(@PathVariable("courseid") Long c groupRepository.save(new GroupEntity("Group " + (i + 1), cluster.getId())); } - GroupClusterJson clusterJsonResponse = entityToJsonConverter.clusterEntityToClusterJson(clusterEntity); + GroupClusterJson clusterJsonResponse = entityToJsonConverter.clusterEntityToClusterJson(clusterEntity, false); // Return the cluster return ResponseEntity.status(HttpStatus.CREATED).body(clusterJsonResponse); @@ -138,8 +143,11 @@ public ResponseEntity getCluster(@PathVariable("clusterid") Long clusterid, A return ResponseEntity.status(checkResult.getStatus()).body(checkResult.getMessage()); } GroupClusterEntity cluster = checkResult.getData(); + + CheckResult courseAdmin = courseUtil.getCourseIfAdmin(cluster.getCourseId(), auth.getUserEntity()); + boolean hideStudentNumber = !courseAdmin.getStatus().equals(HttpStatus.OK); // Return the cluster - return ResponseEntity.ok(entityToJsonConverter.clusterEntityToClusterJson(cluster)); + return ResponseEntity.ok(entityToJsonConverter.clusterEntityToClusterJson(cluster, hideStudentNumber)); } @@ -175,7 +183,7 @@ public ResponseEntity doGroupClusterUpdate(GroupClusterEntity clusterEntity, clusterEntity.setMaxSize(clusterJson.getCapacity()); clusterEntity.setName(clusterJson.getName()); clusterEntity = groupClusterRepository.save(clusterEntity); - return ResponseEntity.ok(entityToJsonConverter.clusterEntityToClusterJson(clusterEntity)); + return ResponseEntity.ok(entityToJsonConverter.clusterEntityToClusterJson(clusterEntity, false)); } /** @@ -226,7 +234,7 @@ public ResponseEntity fillCluster(@PathVariable("clusterid") Long clusterid, groupCluster.setGroupAmount(clusterFillJson.getClusterGroupMembers().size()); groupClusterRepository.save(groupCluster); - return ResponseEntity.status(HttpStatus.OK).body(entityToJsonConverter.clusterEntityToClusterJson(groupCluster)); + return ResponseEntity.status(HttpStatus.OK).body(entityToJsonConverter.clusterEntityToClusterJson(groupCluster, false)); } catch (Exception e) { Logger.getGlobal().severe(e.getMessage()); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Something went wrong"); @@ -317,6 +325,6 @@ public ResponseEntity createGroupForCluster(@PathVariable("clusterid") Long c cluster.setGroupAmount(cluster.getGroupAmount() + 1); groupClusterRepository.save(cluster); - return ResponseEntity.status(HttpStatus.CREATED).body(entityToJsonConverter.groupEntityToJson(group)); + return ResponseEntity.status(HttpStatus.CREATED).body(entityToJsonConverter.groupEntityToJson(group, false)); } } diff --git a/backend/app/src/main/java/com/ugent/pidgeon/controllers/CourseController.java b/backend/app/src/main/java/com/ugent/pidgeon/controllers/CourseController.java index fa912b5f..8dfc5072 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/controllers/CourseController.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/controllers/CourseController.java @@ -591,6 +591,8 @@ public ResponseEntity getCourseMembers(Auth auth, @PathVariable Long courseId return ResponseEntity.status(checkResult.getStatus()).body(checkResult.getMessage()); } + boolean hideStudentNumber = checkResult.getData().getSecond().equals(CourseRelation.enrolled); + List members = courseUserRepository.findAllMembers(courseId); List memberJson = members.stream(). map(cue -> { @@ -598,7 +600,7 @@ public ResponseEntity getCourseMembers(Auth auth, @PathVariable Long courseId if (user == null) { return null; } - return entityToJsonConverter.userEntityToUserReferenceWithRelation(user, cue.getRelation()); + return entityToJsonConverter.userEntityToUserReferenceWithRelation(user, cue.getRelation(), hideStudentNumber); }). filter(Objects::nonNull).toList(); diff --git a/backend/app/src/main/java/com/ugent/pidgeon/controllers/GroupController.java b/backend/app/src/main/java/com/ugent/pidgeon/controllers/GroupController.java index bdae9bec..bd579216 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/controllers/GroupController.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/controllers/GroupController.java @@ -9,7 +9,9 @@ import com.ugent.pidgeon.postgre.models.types.UserRole; import com.ugent.pidgeon.postgre.repository.GroupRepository; import com.ugent.pidgeon.util.CheckResult; +import com.ugent.pidgeon.util.ClusterUtil; import com.ugent.pidgeon.util.CommonDatabaseActions; +import com.ugent.pidgeon.util.CourseUtil; import com.ugent.pidgeon.util.EntityToJsonConverter; import com.ugent.pidgeon.util.GroupUtil; import org.springframework.beans.factory.annotation.Autowired; @@ -28,6 +30,10 @@ public class GroupController { private EntityToJsonConverter entityToJsonConverter; @Autowired private CommonDatabaseActions commonDatabaseActions; + @Autowired + private ClusterUtil clusterUtil; + @Autowired + private CourseUtil courseUtil; /** @@ -50,8 +56,14 @@ public ResponseEntity getGroupById(@PathVariable("groupid") Long groupid, Aut return ResponseEntity.status(checkResult1.getStatus()).body(checkResult1.getMessage()); } + boolean hideStudentNumber = true; + CheckResult adminCheck = groupUtil.isAdminOfGroup(groupid, auth.getUserEntity()); + if (adminCheck.getStatus().equals(HttpStatus.OK)) { + hideStudentNumber = false; + } + // Return the group - GroupJson groupJson = entityToJsonConverter.groupEntityToJson(group); + GroupJson groupJson = entityToJsonConverter.groupEntityToJson(group, hideStudentNumber); return ResponseEntity.ok(groupJson); } @@ -113,7 +125,7 @@ private ResponseEntity doGroupNameUpdate(Long groupid, NameRequest nameReques groupRepository.save(group); // Return the updated group - GroupJson groupJson = entityToJsonConverter.groupEntityToJson(group); + GroupJson groupJson = entityToJsonConverter.groupEntityToJson(group, false); return ResponseEntity.ok(groupJson); } diff --git a/backend/app/src/main/java/com/ugent/pidgeon/controllers/GroupMemberController.java b/backend/app/src/main/java/com/ugent/pidgeon/controllers/GroupMemberController.java index a3b0161b..e7e9397c 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/controllers/GroupMemberController.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/controllers/GroupMemberController.java @@ -111,7 +111,9 @@ public ResponseEntity addMemberToGroup(@PathVariable("groupid") long gro try { groupMemberRepository.addMemberToGroup(groupId, memberid); List members = groupMemberRepository.findAllMembersByGroupId(groupId); - List response = members.stream().map(entityToJsonConverter::userEntityToUserReference).toList(); + List response = members.stream().map( + u -> entityToJsonConverter.userEntityToUserReference(u, false) + ).toList(); return ResponseEntity.ok(response); } catch (Exception e) { Logger.getGlobal().severe(e.getMessage()); @@ -143,7 +145,9 @@ public ResponseEntity addMemberToGroupInferred(@PathVariable("groupid") try { groupMemberRepository.addMemberToGroup(groupId,user.getId()); List members = groupMemberRepository.findAllMembersByGroupId(groupId); - List response = members.stream().map(entityToJsonConverter::userEntityToUserReference).toList(); + List response = members.stream().map( + u -> entityToJsonConverter.userEntityToUserReference(u, true) + ).toList(); return ResponseEntity.ok(response); } catch (Exception e) { Logger.getGlobal().severe(e.getMessage()); @@ -171,8 +175,12 @@ public ResponseEntity findAllMembersByGroupId(@PathVariable("groupid") l return ResponseEntity.status(checkResult.getStatus()).body(checkResult.getMessage()); } + boolean hideStudentnumber = !groupUtil.isAdminOfGroup(groupId, user).getStatus().equals(HttpStatus.OK); + List members = groupMemberRepository.findAllMembersByGroupId(groupId); - List response = members.stream().map((UserEntity e) -> entityToJsonConverter.userEntityToUserReference(e)).toList(); + List response = members.stream().map( + (UserEntity e) -> entityToJsonConverter.userEntityToUserReference(e, hideStudentnumber)) + .toList(); return ResponseEntity.ok(response); } } diff --git a/backend/app/src/main/java/com/ugent/pidgeon/controllers/ProjectController.java b/backend/app/src/main/java/com/ugent/pidgeon/controllers/ProjectController.java index 6d3f5742..3e68a627 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/controllers/ProjectController.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/controllers/ProjectController.java @@ -312,11 +312,15 @@ public ResponseEntity getGroupsOfProject(@PathVariable Long projectId, Auth a "No groups for this project: use " + memberUrl + " to get the members of the course"); } + boolean hideStudentNumber; + CheckResult adminCheck = projectUtil.isProjectAdmin(projectId, auth.getUserEntity()); + hideStudentNumber = !adminCheck.getStatus().equals(HttpStatus.OK); + List groups = projectRepository.findGroupIdsByProjectId(projectId); List groupjsons = groups.stream() - .map((Long id) -> { - return groupRepository.findById(id).orElse(null); - }).filter(Objects::nonNull).map(entityToJsonConverter::groupEntityToJson).toList(); + .map((Long id) -> groupRepository.findById(id).orElse(null)).filter(Objects::nonNull).map( + g -> entityToJsonConverter.groupEntityToJson(g, hideStudentNumber)) + .toList(); return ResponseEntity.ok(groupjsons); } diff --git a/backend/app/src/main/java/com/ugent/pidgeon/controllers/SubmissionController.java b/backend/app/src/main/java/com/ugent/pidgeon/controllers/SubmissionController.java index 39bdca89..4edec9f9 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/controllers/SubmissionController.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/controllers/SubmissionController.java @@ -115,7 +115,7 @@ public ResponseEntity getSubmissions(@PathVariable("projectid") long projecti if (group == null) { throw new RuntimeException("Group not found"); } - GroupJson groupjson = entityToJsonConverter.groupEntityToJson(group); + GroupJson groupjson = entityToJsonConverter.groupEntityToJson(group, false); GroupFeedbackEntity groupFeedbackEntity = groupFeedbackRepository.getGroupFeedback(groupId, projectid); GroupFeedbackJson groupFeedbackJson; if (groupFeedbackEntity == null) { diff --git a/backend/app/src/main/java/com/ugent/pidgeon/model/json/UserJson.java b/backend/app/src/main/java/com/ugent/pidgeon/model/json/UserJson.java index bcba3900..3f8940e3 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/model/json/UserJson.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/model/json/UserJson.java @@ -14,6 +14,7 @@ public class UserJson { private String surname; private String email; private UserRole role; + private String studentNumber; private OffsetDateTime createdAt; @@ -29,6 +30,7 @@ public UserJson(UserEntity entity) { this.email = entity.getEmail(); this.role = entity.getRole(); this.createdAt = entity.getCreatedAt(); + this.studentNumber = entity.getStudentNumber(); // this.courses = new ArrayList<>(); } @@ -96,4 +98,11 @@ public String getProjectUrl() { } public void setProjectUrl(String s){} + public String getStudentNumber() { + return studentNumber; + } + + public void setStudentNumber(String studentNumber) { + this.studentNumber = studentNumber; + } } diff --git a/backend/app/src/main/java/com/ugent/pidgeon/model/json/UserReferenceJson.java b/backend/app/src/main/java/com/ugent/pidgeon/model/json/UserReferenceJson.java index b14d4068..1d486fae 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/model/json/UserReferenceJson.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/model/json/UserReferenceJson.java @@ -4,11 +4,13 @@ public class UserReferenceJson { private String name; private String email; private Long userId; + private String studentNumber; - public UserReferenceJson(String name, String email, Long userId) { + public UserReferenceJson(String name, String email, Long userId, String studentNumber) { this.name = name; this.email = email; this.userId = userId; + this.studentNumber = studentNumber; } public String getEmail() { @@ -39,4 +41,11 @@ public void setName(String name) { } + public String getStudentNumber() { + return studentNumber; + } + + public void setStudentNumber(String studentNumber) { + this.studentNumber = studentNumber; + } } diff --git a/backend/app/src/main/java/com/ugent/pidgeon/postgre/repository/GroupRepository.java b/backend/app/src/main/java/com/ugent/pidgeon/postgre/repository/GroupRepository.java index 1a3e1d07..65af7bc0 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/postgre/repository/GroupRepository.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/postgre/repository/GroupRepository.java @@ -36,9 +36,10 @@ public interface UserReference { Long getUserId(); String getName(); String getEmail(); + String getStudentNumber(); } @Query(value= """ - SELECT gu.userId as userId, u.name, CONCAT(u.name, ' ', u.surname) as name, u.email as email + SELECT gu.userId as userId, u.name, CONCAT(u.name, ' ', u.surname) as name, u.email as email, u.studentNumber as studentNumber FROM GroupUserEntity gu JOIN UserEntity u ON u.id = gu.userId WHERE gu.groupId = ?1""") List findGroupUsersReferencesByGroupId(long id); diff --git a/backend/app/src/main/java/com/ugent/pidgeon/util/EntityToJsonConverter.java b/backend/app/src/main/java/com/ugent/pidgeon/util/EntityToJsonConverter.java index b3d6d525..152b2594 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/util/EntityToJsonConverter.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/util/EntityToJsonConverter.java @@ -41,7 +41,7 @@ public class EntityToJsonConverter { private TestRepository testRepository; - public GroupJson groupEntityToJson(GroupEntity groupEntity) { + public GroupJson groupEntityToJson(GroupEntity groupEntity, boolean hideStudentNumber) { GroupClusterEntity cluster = groupClusterRepository.findById(groupEntity.getClusterId()).orElse(null); if (cluster == null) { throw new RuntimeException("Cluster not found"); @@ -54,7 +54,7 @@ public GroupJson groupEntityToJson(GroupEntity groupEntity) { } // Get the members of the group List members = groupRepository.findGroupUsersReferencesByGroupId(groupEntity.getId()).stream().map(user -> - new UserReferenceJson(user.getName(), user.getEmail(), user.getUserId()) + new UserReferenceJson(user.getName(), user.getEmail(), user.getUserId(), hideStudentNumber ? null : user.getStudentNumber()) ).toList(); // Return the group with its members @@ -63,9 +63,9 @@ public GroupJson groupEntityToJson(GroupEntity groupEntity) { } - public GroupClusterJson clusterEntityToClusterJson(GroupClusterEntity cluster) { + public GroupClusterJson clusterEntityToClusterJson(GroupClusterEntity cluster, boolean hideStudentNumber) { List groups = groupRepository.findAllByClusterId(cluster.getId()).stream().map( - this::groupEntityToJson + g -> groupEntityToJson(g, hideStudentNumber) ).toList(); return new GroupClusterJson( cluster.getId(), @@ -78,20 +78,26 @@ public GroupClusterJson clusterEntityToClusterJson(GroupClusterEntity cluster) { ); } - public UserReferenceJson userEntityToUserReference(UserEntity user) { - return new UserReferenceJson(user.getName() + " " + user.getSurname(), user.getEmail(), user.getId()); + public UserReferenceJson userEntityToUserReference(UserEntity user, boolean hideStudentNumber) { + return new UserReferenceJson( + user.getName() + " " + user.getSurname(), + user.getEmail(), user.getId(), + hideStudentNumber ? null : user.getStudentNumber() + ); } - public UserReferenceWithRelation userEntityToUserReferenceWithRelation(UserEntity user, CourseRelation relation) { - return new UserReferenceWithRelation(userEntityToUserReference(user), relation.toString()); + public UserReferenceWithRelation userEntityToUserReferenceWithRelation(UserEntity user, CourseRelation relation, boolean hideStudentNumber) { + return new UserReferenceWithRelation(userEntityToUserReference(user, hideStudentNumber), relation.toString()); } public CourseWithInfoJson courseEntityToCourseWithInfo(CourseEntity course, String joinLink, boolean hideKey) { UserEntity teacher = courseRepository.findTeacherByCourseId(course.getId()); - UserReferenceJson teacherJson = userEntityToUserReference(teacher); + UserReferenceJson teacherJson = userEntityToUserReference(teacher, true); List assistants = courseRepository.findAssistantsByCourseId(course.getId()); - List assistantsJson = assistants.stream().map(this::userEntityToUserReference).toList(); + List assistantsJson = assistants.stream().map( + u -> userEntityToUserReference(u, true) + ).toList(); return new CourseWithInfoJson( course.getId(), From 93f5e827ee891819ed242dea21585a4ff81a9c78 Mon Sep 17 00:00:00 2001 From: Aqua-sc <108478185+Aqua-sc@users.noreply.github.com> Date: Fri, 17 May 2024 21:16:43 +0200 Subject: [PATCH 08/11] updated tests --- .../pidgeon/postgre/models/UserEntity.java | 4 ++ .../controllers/ClusterControllerTest.java | 42 +++++++++-- .../controllers/CourseControllerTest.java | 26 +++++-- .../controllers/GroupControllerTest.java | 19 ++++- .../GroupMembersControllerTest.java | 35 +++++++--- .../controllers/ProjectControllerTest.java | 18 ++++- .../controllers/SubmissionControllerTest.java | 4 +- .../pidgeon/global/RolesInterceptorTest.java | 1 + .../util/EntityToJsonConverterTest.java | 65 ++++++++++++++---- .../DockerSubmissionTestTest/d__test.zip | Bin 162 -> 162 bytes 10 files changed, 173 insertions(+), 41 deletions(-) diff --git a/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/UserEntity.java b/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/UserEntity.java index 0addda2d..0f3a04ca 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/UserEntity.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/UserEntity.java @@ -119,5 +119,9 @@ public void setCreatedAt(OffsetDateTime createdAt) { public String getStudentNumber() { return studentNumber; } + + public void setStudentNumber(String studentNumber) { + this.studentNumber = studentNumber; + } } diff --git a/backend/app/src/test/java/com/ugent/pidgeon/controllers/ClusterControllerTest.java b/backend/app/src/test/java/com/ugent/pidgeon/controllers/ClusterControllerTest.java index 2bd77265..bc3392e3 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/controllers/ClusterControllerTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/controllers/ClusterControllerTest.java @@ -105,12 +105,26 @@ public void testGetClustersForCourse() throws Exception { when(courseUtil.getCourseIfUserInCourse(courseId, getMockUser())) .thenReturn(new CheckResult<>(HttpStatus.OK, "", new Pair<>(courseEntity, CourseRelation.enrolled))); when(groupClusterRepository.findClustersWithoutInvidualByCourseId(courseId)).thenReturn(List.of(groupClusterEntity)); - when(entityToJsonConverter.clusterEntityToClusterJson(groupClusterEntity)).thenReturn(groupClusterJson); + when(entityToJsonConverter.clusterEntityToClusterJson(groupClusterEntity, true)).thenReturn(groupClusterJson); mockMvc.perform(MockMvcRequestBuilders.get(url)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(content().json(objectMapper.writeValueAsString(List.of(groupClusterJson)))); + verify(entityToJsonConverter, times(1)).clusterEntityToClusterJson(groupClusterEntity, true); + + + /* If user is course_admin, studentnumber isn't hidden */ + when(courseUtil.getCourseIfUserInCourse(courseId, getMockUser())) + .thenReturn(new CheckResult<>(HttpStatus.OK, "", new Pair<>(courseEntity, CourseRelation.course_admin))); + when(entityToJsonConverter.clusterEntityToClusterJson(groupClusterEntity, false)).thenReturn(groupClusterJson); + mockMvc.perform(MockMvcRequestBuilders.get(url)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(content().json(objectMapper.writeValueAsString(List.of(groupClusterJson)))); + + verify(entityToJsonConverter, times(1)).clusterEntityToClusterJson(groupClusterEntity, false); + /* If a certain check fails, the corresponding status code is returned */ when(courseUtil.getCourseIfUserInCourse(anyLong(), any())) .thenReturn(new CheckResult<>(HttpStatus.BAD_REQUEST, "", null)); @@ -129,7 +143,7 @@ public void testCreateClusterForCourse() throws Exception { json -> json.name().equals("test") && json.capacity().equals(20) && json.groupCount().equals(5) ))).thenReturn(new CheckResult<>(HttpStatus.OK, "", null)); when(groupClusterRepository.save(any())).thenReturn(groupClusterEntity); - when(entityToJsonConverter.clusterEntityToClusterJson(groupClusterEntity)).thenReturn(groupClusterJson); + when(entityToJsonConverter.clusterEntityToClusterJson(groupClusterEntity, false)).thenReturn(groupClusterJson); mockMvc.perform(MockMvcRequestBuilders.post(url) .contentType(MediaType.APPLICATION_JSON) .content(request)) @@ -158,13 +172,27 @@ public void testGetCluster() throws Exception { String url = ApiRoutes.CLUSTER_BASE_PATH + "/" + groupClusterEntity.getId(); /* If the user has acces to the cluster and it isn't an individual cluster, the cluster is returned */ - when(entityToJsonConverter.clusterEntityToClusterJson(groupClusterEntity)).thenReturn(groupClusterJson); + /* User is not an admin, studentNumber should be hidden */ + when(courseUtil.getCourseIfAdmin(courseEntity.getId(), getMockUser())).thenReturn(new CheckResult<>(HttpStatus.FORBIDDEN, "", courseEntity)); + when(entityToJsonConverter.clusterEntityToClusterJson(groupClusterEntity, true)).thenReturn(groupClusterJson); when(clusterUtil.getGroupClusterEntityIfNotIndividual(groupClusterEntity.getId(), getMockUser())).thenReturn(new CheckResult<>(HttpStatus.OK, "", groupClusterEntity)); mockMvc.perform(MockMvcRequestBuilders.get(url)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(content().json(objectMapper.writeValueAsString(groupClusterJson))); + verify(entityToJsonConverter, times(1)).clusterEntityToClusterJson(groupClusterEntity, true); + + /* User is an admin, studentNumber should be visible */ + when(courseUtil.getCourseIfAdmin(courseEntity.getId(), getMockUser())).thenReturn(new CheckResult<>(HttpStatus.OK, "", courseEntity)); + when(entityToJsonConverter.clusterEntityToClusterJson(groupClusterEntity, false)).thenReturn(groupClusterJson); + mockMvc.perform(MockMvcRequestBuilders.get(url)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(content().json(objectMapper.writeValueAsString(groupClusterJson))); + + verify(entityToJsonConverter, times(1)).clusterEntityToClusterJson(groupClusterEntity, false); + /* If any check fails, the corresponding status code is returned */ when(clusterUtil.getGroupClusterEntityIfNotIndividual(anyLong(), any())).thenReturn(new CheckResult<>(HttpStatus.I_AM_A_TEAPOT, "", null)); mockMvc.perform(MockMvcRequestBuilders.get(url)) @@ -188,7 +216,7 @@ public void testUpdateCluster() throws Exception { copy.setName("newclustername"); GroupClusterJson updated = new GroupClusterJson(1L, "newclustername", 20, 5, OffsetDateTime.now(), Collections.emptyList(), ""); when(groupClusterRepository.save(groupClusterEntity)).thenReturn(copy); - when(entityToJsonConverter.clusterEntityToClusterJson(copy)).thenReturn(updated); + when(entityToJsonConverter.clusterEntityToClusterJson(copy, false)).thenReturn(updated); mockMvc.perform(MockMvcRequestBuilders.put(url) .contentType(MediaType.APPLICATION_JSON) .content(request)) @@ -318,7 +346,7 @@ public void testPatchCluster() throws Exception { argThat(json -> json.getName() == groupClusterEntity.getName() && json.getCapacity() == groupClusterEntity.getMaxSize()) )).thenReturn(new CheckResult<>(HttpStatus.OK, "", null)); when(groupClusterRepository.save(groupClusterEntity)).thenReturn(groupClusterEntity); - when(entityToJsonConverter.clusterEntityToClusterJson(groupClusterEntity)).thenReturn(groupClusterJson); + when(entityToJsonConverter.clusterEntityToClusterJson(groupClusterEntity, false)).thenReturn(groupClusterJson); mockMvc.perform(MockMvcRequestBuilders.patch(url) .contentType(MediaType.APPLICATION_JSON) .content(request)) @@ -339,7 +367,7 @@ public void testPatchCluster() throws Exception { )).thenReturn(new CheckResult<>(HttpStatus.OK, "", null)); GroupClusterJson updated = new GroupClusterJson(1L, "newclustername", 22, 5, OffsetDateTime.now(), Collections.emptyList(), ""); when(groupClusterRepository.save(groupClusterEntity)).thenReturn(copy); - when(entityToJsonConverter.clusterEntityToClusterJson(copy)).thenReturn(updated); + when(entityToJsonConverter.clusterEntityToClusterJson(copy, false)).thenReturn(updated); mockMvc.perform(MockMvcRequestBuilders.patch(url) .contentType(MediaType.APPLICATION_JSON) .content(request)) @@ -397,7 +425,7 @@ public void testCreateGroupForCluster() throws Exception { when(groupRepository.save(argThat( group -> group.getName().equals("test") && group.getClusterId() == groupClusterEntity.getId() ))).thenReturn(groupEntity); - when(entityToJsonConverter.groupEntityToJson(groupEntity)).thenReturn(groupJson); + when(entityToJsonConverter.groupEntityToJson(groupEntity, false)).thenReturn(groupJson); mockMvc.perform(MockMvcRequestBuilders.post(url) .contentType(MediaType.APPLICATION_JSON) .content(request)) diff --git a/backend/app/src/test/java/com/ugent/pidgeon/controllers/CourseControllerTest.java b/backend/app/src/test/java/com/ugent/pidgeon/controllers/CourseControllerTest.java index 6fe060c0..a712c982 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/controllers/CourseControllerTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/controllers/CourseControllerTest.java @@ -112,7 +112,7 @@ public void setup() { activeCourse.getId(), activeCourse.getName(), activeCourse.getDescription(), - new UserReferenceJson("", "", 0L), + new UserReferenceJson("", "", 0L, ""), new ArrayList<>(), "", "", @@ -308,7 +308,7 @@ public void testUpdateCourse() throws Exception { activeCourse.getId(), "test", "description", - new UserReferenceJson("", "", 0L), + new UserReferenceJson("", "", 0L, ""), new ArrayList<>(), "", "", @@ -403,7 +403,7 @@ public void testPatchCourse() throws Exception { activeCourse.getId(), "test", "description2", - new UserReferenceJson("", "", 0L), + new UserReferenceJson("", "", 0L, ""), new ArrayList<>(), "", "", @@ -1007,21 +1007,33 @@ public void testGetCourseMembers() throws Exception { CourseUserEntity courseUserEntity = new CourseUserEntity(1L, 1L, CourseRelation.enrolled); UserEntity user = new UserEntity("name", "surname", "email", UserRole.teacher, "id", ""); UserReferenceWithRelation userJson = new UserReferenceWithRelation( - new UserReferenceJson("name", "surname", 1L), + new UserReferenceJson("name", "surname", 1L, ""), ""+CourseRelation.enrolled ); List userList = List.of(courseUserEntity); String url = ApiRoutes.COURSE_BASE_PATH + "/" + activeCourse.getId() + "/members"; /* If user is in course, return members */ when(courseUtil.getCourseIfUserInCourse(activeCourseJson.courseId(), getMockUser())) - .thenReturn(new CheckResult<>(HttpStatus.OK, "", new Pair<>(activeCourse, CourseRelation.course_admin))); + .thenReturn(new CheckResult<>(HttpStatus.OK, "", new Pair<>(activeCourse, CourseRelation.enrolled))); when(courseUserRepository.findAllMembers(activeCourseJson.courseId())).thenReturn(userList); when(userUtil.getUserIfExists(courseUserEntity.getUserId())).thenReturn(user); - when(entityToJsonConverter.userEntityToUserReferenceWithRelation(user, CourseRelation.enrolled)).thenReturn(userJson); + /* User is enrolled so studentNumber should be hidden */ + when(entityToJsonConverter.userEntityToUserReferenceWithRelation(user, CourseRelation.enrolled, true)).thenReturn(userJson); + mockMvc.perform(MockMvcRequestBuilders.get(url)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(content().json(objectMapper.writeValueAsString(List.of(userJson)))); + verify(entityToJsonConverter, times(1)).userEntityToUserReferenceWithRelation(user, CourseRelation.enrolled, true); + + /* If user is admin studentNumber should be visible */ + when(courseUtil.getCourseIfUserInCourse(activeCourseJson.courseId(), getMockUser())) + .thenReturn(new CheckResult<>(HttpStatus.OK, "", new Pair<>(activeCourse, CourseRelation.course_admin))); + when(entityToJsonConverter.userEntityToUserReferenceWithRelation(user, CourseRelation.enrolled, false)).thenReturn(userJson); mockMvc.perform(MockMvcRequestBuilders.get(url)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(content().json(objectMapper.writeValueAsString(List.of(userJson)))); + verify(entityToJsonConverter, times(1)).userEntityToUserReferenceWithRelation(user, CourseRelation.enrolled, false); /* If user doesn't get found it gets filtered out */ when(userUtil.getUserIfExists(anyLong())).thenReturn(null); @@ -1107,7 +1119,7 @@ public void testCopyCourse() throws Exception { 2L, "name", "description", - new UserReferenceJson("", "", 0L), + new UserReferenceJson("", "", 0L, ""), new ArrayList<>(), "", "", diff --git a/backend/app/src/test/java/com/ugent/pidgeon/controllers/GroupControllerTest.java b/backend/app/src/test/java/com/ugent/pidgeon/controllers/GroupControllerTest.java index 798e0d89..76ef9110 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/controllers/GroupControllerTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/controllers/GroupControllerTest.java @@ -29,6 +29,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -74,11 +76,26 @@ public void testGetGroupById() throws Exception { .thenReturn(new CheckResult<>(HttpStatus.OK, "", groupEntity)); when(groupUtil.canGetGroup(groupEntity.getId(), getMockUser())) .thenReturn(new CheckResult<>(HttpStatus.OK, "", null)); - when(entityToJsonConverter.groupEntityToJson(groupEntity)).thenReturn(groupJson); + /* User is admin, student number should not be hidden */ + when(groupUtil.isAdminOfGroup(groupEntity.getId(), getMockUser())) + .thenReturn(new CheckResult<>(HttpStatus.OK, "", null)); + when(entityToJsonConverter.groupEntityToJson(groupEntity, false)).thenReturn(groupJson); + mockMvc.perform(MockMvcRequestBuilders.get(url)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(content().string(objectMapper.writeValueAsString(groupJson))); + verify(entityToJsonConverter, times(1)).groupEntityToJson(groupEntity, false); + + /* User is not admin, student number should be hidden */ + when(groupUtil.isAdminOfGroup(groupEntity.getId(), getMockUser())) + .thenReturn(new CheckResult<>(HttpStatus.I_AM_A_TEAPOT, "", null)); + when(entityToJsonConverter.groupEntityToJson(groupEntity, true)).thenReturn(groupJson); mockMvc.perform(MockMvcRequestBuilders.get(url)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(content().string(objectMapper.writeValueAsString(groupJson))); + verify(entityToJsonConverter, times(1)).groupEntityToJson(groupEntity, true); + /* If the user doesn't have acces to group, return forbidden */ when(groupUtil.canGetGroup(anyLong(), any())) diff --git a/backend/app/src/test/java/com/ugent/pidgeon/controllers/GroupMembersControllerTest.java b/backend/app/src/test/java/com/ugent/pidgeon/controllers/GroupMembersControllerTest.java index 8793a7dd..b3074b26 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/controllers/GroupMembersControllerTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/controllers/GroupMembersControllerTest.java @@ -58,8 +58,8 @@ public void setup() { userEntity.setId(5L); userEntity2 = new UserEntity("name2", "surname2", "email2", UserRole.student, "azureid2", ""); userEntity2.setId(6L); - userReferenceJson = new UserReferenceJson(userEntity.getName(), userEntity.getEmail(), userEntity.getId()); - userReferenceJson2 = new UserReferenceJson(userEntity2.getName(), userEntity2.getEmail(), userEntity2.getId()); + userReferenceJson = new UserReferenceJson(userEntity.getName(), userEntity.getEmail(), userEntity.getId(), ""); + userReferenceJson2 = new UserReferenceJson(userEntity2.getName(), userEntity2.getEmail(), userEntity2.getId(), ""); } @Test @@ -117,8 +117,8 @@ public void testAddMemberToGroup() throws Exception { .thenReturn(new CheckResult<>(HttpStatus.OK, "", null)); when(groupMemberRepository.findAllMembersByGroupId(groupId)) .thenReturn(List.of(userEntity, userEntity2)); - when(entityToJsonConverter.userEntityToUserReference(userEntity)).thenReturn(userReferenceJson); - when(entityToJsonConverter.userEntityToUserReference(userEntity2)).thenReturn(userReferenceJson2); + when(entityToJsonConverter.userEntityToUserReference(userEntity, false)).thenReturn(userReferenceJson); + when(entityToJsonConverter.userEntityToUserReference(userEntity2, false)).thenReturn(userReferenceJson2); mockMvc.perform(MockMvcRequestBuilders.post(url)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) @@ -141,15 +141,15 @@ public void testAddMemberToGroup() throws Exception { @Test public void testAddMemberToGroupInferred() throws Exception { String url = ApiRoutes.GROUP_MEMBER_BASE_PATH.replace("{groupid}", ""+groupId); - UserReferenceJson mockUserJson = new UserReferenceJson(getMockUser().getName(), getMockUser().getEmail(), getMockUser().getId()); + UserReferenceJson mockUserJson = new UserReferenceJson(getMockUser().getName(), getMockUser().getEmail(), getMockUser().getId(), getMockUser().getStudentNumber()); /* If all checks succeed, the user is added to the group */ when(groupUtil.canAddUserToGroup(groupId, getMockUser().getId(), getMockUser())) .thenReturn(new CheckResult<>(HttpStatus.OK, "", null)); when(groupMemberRepository.findAllMembersByGroupId(groupId)) .thenReturn(List.of(getMockUser(), userEntity2)); - when(entityToJsonConverter.userEntityToUserReference(getMockUser())).thenReturn(mockUserJson); - when(entityToJsonConverter.userEntityToUserReference(userEntity2)).thenReturn(userReferenceJson2); + when(entityToJsonConverter.userEntityToUserReference(getMockUser(), true)).thenReturn(mockUserJson); + when(entityToJsonConverter.userEntityToUserReference(userEntity2, true)).thenReturn(userReferenceJson2); mockMvc.perform(MockMvcRequestBuilders.post(url)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) @@ -174,8 +174,10 @@ public void testFindAllMembersByGroupId() throws Exception { List members = List.of(userEntity, userEntity2); List userReferenceJsons = List.of(userReferenceJson, userReferenceJson2); when(groupMemberRepository.findAllMembersByGroupId(groupId)).thenReturn(members); - when(entityToJsonConverter.userEntityToUserReference(userEntity)).thenReturn(userReferenceJson); - when(entityToJsonConverter.userEntityToUserReference(userEntity2)).thenReturn(userReferenceJson2); + /* User is admin of group so don't hide studentNumbers */ + when(groupUtil.isAdminOfGroup(groupId, getMockUser())).thenReturn(new CheckResult<>(HttpStatus.OK, "", null)); + when(entityToJsonConverter.userEntityToUserReference(userEntity, false)).thenReturn(userReferenceJson); + when(entityToJsonConverter.userEntityToUserReference(userEntity2, false)).thenReturn(userReferenceJson2); /* If user can get group return list of members */ when(groupUtil.canGetGroup(groupId, getMockUser())) @@ -185,6 +187,21 @@ public void testFindAllMembersByGroupId() throws Exception { .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(content().json(objectMapper.writeValueAsString(userReferenceJsons))); + verify(entityToJsonConverter, times(1)).userEntityToUserReference(userEntity, false); + verify(entityToJsonConverter, times(1)).userEntityToUserReference(userEntity2, false); + + /* If user isn't admin, studentNumbers should be hidden */ + when(groupUtil.isAdminOfGroup(groupId, getMockUser())).thenReturn(new CheckResult<>(HttpStatus.I_AM_A_TEAPOT, "", null)); + when(entityToJsonConverter.userEntityToUserReference(userEntity, true)).thenReturn(userReferenceJson); + when(entityToJsonConverter.userEntityToUserReference(userEntity2, true)).thenReturn(userReferenceJson2); + mockMvc.perform(MockMvcRequestBuilders.get(url)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(content().json(objectMapper.writeValueAsString(userReferenceJsons))); + + verify(entityToJsonConverter, times(1)).userEntityToUserReference(userEntity, true); + verify(entityToJsonConverter, times(1)).userEntityToUserReference(userEntity2, true); + /* If use can't get group return corresponding status */ when(groupUtil.canGetGroup(groupId, getMockUser())) .thenReturn(new CheckResult<>(HttpStatus.I_AM_A_TEAPOT, "", null)); diff --git a/backend/app/src/test/java/com/ugent/pidgeon/controllers/ProjectControllerTest.java b/backend/app/src/test/java/com/ugent/pidgeon/controllers/ProjectControllerTest.java index 5e0545c4..e17ae6ae 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/controllers/ProjectControllerTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/controllers/ProjectControllerTest.java @@ -746,7 +746,7 @@ void testPatchProjectById() throws Exception { } @Test - void getGroupsOfProject() throws Exception { + void testGetGroupsOfProject() throws Exception { String url = ApiRoutes.PROJECT_BASE_PATH + "/" + projectEntity.getId() + "/groups"; GroupEntity groupEntity = new GroupEntity("groupName", 1L); long groupId = 83L; @@ -760,12 +760,26 @@ void getGroupsOfProject() throws Exception { when(clusterUtil.isIndividualCluster(projectEntity.getGroupClusterId())).thenReturn(false); when(projectRepository.findGroupIdsByProjectId(projectEntity.getId())).thenReturn(List.of(groupId)); when(grouprRepository.findById(groupId)).thenReturn(Optional.of(groupEntity)); - when(entityToJsonConverter.groupEntityToJson(groupEntity)).thenReturn(groupJson); + /* User is admin so studentNumber shouldn't be hidden */ + when(projectUtil.isProjectAdmin(projectEntity.getId(), getMockUser())).thenReturn(new CheckResult<>(HttpStatus.OK, "", null)); + when(entityToJsonConverter.groupEntityToJson(groupEntity, false)).thenReturn(groupJson); mockMvc.perform(MockMvcRequestBuilders.get(url)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(content().json(objectMapper.writeValueAsString(List.of(groupJson)))); + verify(entityToJsonConverter, times(1)).groupEntityToJson(groupEntity, false); + + /* If user is not admin, studentNumber should be hidden */ + when(projectUtil.isProjectAdmin(projectEntity.getId(), getMockUser())).thenReturn(new CheckResult<>(HttpStatus.I_AM_A_TEAPOT, "", null)); + when(entityToJsonConverter.groupEntityToJson(groupEntity, true)).thenReturn(groupJson); + mockMvc.perform(MockMvcRequestBuilders.get(url)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(content().json(objectMapper.writeValueAsString(List.of(groupJson)))); + + verify(entityToJsonConverter, times(1)).groupEntityToJson(groupEntity, true); + /* If inidividual cluster return no content */ when(clusterUtil.isIndividualCluster(projectEntity.getGroupClusterId())).thenReturn(true); mockMvc.perform(MockMvcRequestBuilders.get(url)) diff --git a/backend/app/src/test/java/com/ugent/pidgeon/controllers/SubmissionControllerTest.java b/backend/app/src/test/java/com/ugent/pidgeon/controllers/SubmissionControllerTest.java index 21b496ae..aada0734 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/controllers/SubmissionControllerTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/controllers/SubmissionControllerTest.java @@ -209,7 +209,7 @@ public void testGetSubmissions() throws Exception { when(projectUtil.isProjectAdmin(submission.getProjectId(), getMockUser())).thenReturn(new CheckResult<>(HttpStatus.OK, "", null)); when(projectRepository.findGroupIdsByProjectId(submission.getProjectId())).thenReturn(groupIds); when(groupRepository.findById(groupIds.get(0))).thenReturn(Optional.of(groupEntity)); - when(entityToJsonConverter.groupEntityToJson(groupEntity)).thenReturn(groupJson); + when(entityToJsonConverter.groupEntityToJson(groupEntity, false)).thenReturn(groupJson); when(groupFeedbackRepository.getGroupFeedback(groupEntity.getId(), submission.getProjectId())).thenReturn(groupFeedbackEntity); when(entityToJsonConverter.groupFeedbackEntityToJson(groupFeedbackEntity)).thenReturn(groupFeedbackJson); when(submissionRepository.findLatestsSubmissionIdsByProjectAndGroupId(submission.getProjectId(), groupEntity.getId())).thenReturn(Optional.of(submission)); @@ -219,6 +219,8 @@ public void testGetSubmissions() throws Exception { .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(content().json(objectMapper.writeValueAsString(List.of(lastGroupSubmissionJson)))); + verify(entityToJsonConverter, times(1)).groupEntityToJson(groupEntity, false); + /* no submission */ when(submissionRepository.findLatestsSubmissionIdsByProjectAndGroupId(submission.getProjectId(), groupEntity.getId())).thenReturn(Optional.empty()); lastGroupSubmissionJson.setSubmission(null); diff --git a/backend/app/src/test/java/com/ugent/pidgeon/global/RolesInterceptorTest.java b/backend/app/src/test/java/com/ugent/pidgeon/global/RolesInterceptorTest.java index bff3e4e1..76b25d2e 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/global/RolesInterceptorTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/global/RolesInterceptorTest.java @@ -76,6 +76,7 @@ void testUserDoesntExistYet() throws Exception { user.getName().equals(getMockUser().getName()) && user.getSurname().equals(getMockUser().getSurname()) && user.getEmail().equals(getMockUser().getEmail()) && + user.getStudentNumber().equals(getMockUser().getStudentNumber()) && duration.getSeconds() < 5; } ))).thenReturn(getMockUser()); diff --git a/backend/app/src/test/java/com/ugent/pidgeon/util/EntityToJsonConverterTest.java b/backend/app/src/test/java/com/ugent/pidgeon/util/EntityToJsonConverterTest.java index de5c788f..f4806083 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/util/EntityToJsonConverterTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/util/EntityToJsonConverterTest.java @@ -138,7 +138,8 @@ public void setUp() { userReferenceJson = new UserReferenceJson( userEntity.getName() + " " + userEntity.getSurname(), userEntity.getEmail(), - userEntity.getId() + userEntity.getId(), + "" ); otherUser = new UserEntity( @@ -152,7 +153,8 @@ public void setUp() { otherUserReferenceJson = new UserReferenceJson( otherUser.getName() + " " + otherUser.getSurname(), otherUser.getEmail(), - otherUser.getId() + otherUser.getId(), + "" ); @@ -222,6 +224,7 @@ public void setUp() { @Test public void testGroupEntityToJson() { + userEntity.setStudentNumber("studentNumber"); when(groupClusterRepository.findById(groupEntity.getClusterId())).thenReturn(Optional.of(groupClusterEntity)); when(groupRepository.findGroupUsersReferencesByGroupId(anyLong())).thenReturn( List.of(new UserReference[]{ @@ -240,11 +243,16 @@ public String getName() { public String getEmail() { return userEntity.getEmail(); } + + @Override + public String getStudentNumber() { + return userEntity.getStudentNumber(); + } } }) ); - GroupJson result = entityToJsonConverter.groupEntityToJson(groupEntity); + GroupJson result = entityToJsonConverter.groupEntityToJson(groupEntity, false); assertEquals(groupClusterEntity.getMaxSize(), result.getCapacity()); assertEquals(groupEntity.getId(), result.getGroupId()); assertEquals(groupEntity.getName(), result.getName()); @@ -254,25 +262,32 @@ public String getEmail() { assertEquals(userEntity.getId(), userReferenceJson.getUserId()); assertEquals(userEntity.getName() + " " + userEntity.getSurname(), userReferenceJson.getName()); assertEquals(userEntity.getEmail(), userReferenceJson.getEmail()); + assertEquals(userEntity.getStudentNumber(), userReferenceJson.getStudentNumber()); /* Cluster is individual */ groupClusterEntity.setMaxSize(1); - result = entityToJsonConverter.groupEntityToJson(groupEntity); + result = entityToJsonConverter.groupEntityToJson(groupEntity, false); assertEquals(1, result.getCapacity()); assertNull(result.getGroupClusterUrl()); + /* StudentNumber gets hidden correctly */ + result = entityToJsonConverter.groupEntityToJson(groupEntity, true); + assertNull(result.getMembers().get(0).getStudentNumber()); + /* Issue when groupClusterEntity is null */ when(groupClusterRepository.findById(groupEntity.getClusterId())).thenReturn(Optional.empty()); - assertThrows(RuntimeException.class, () -> entityToJsonConverter.groupEntityToJson(groupEntity)); + assertThrows(RuntimeException.class, () -> entityToJsonConverter.groupEntityToJson(groupEntity, false)); } @Test public void testClusterEntityToClusterJson() { when(groupRepository.findAllByClusterId(groupClusterEntity.getId())).thenReturn(List.of(groupEntity)); - doReturn(groupJson).when(entityToJsonConverter).groupEntityToJson(groupEntity); + doReturn(groupJson).when(entityToJsonConverter).groupEntityToJson(groupEntity, false); + + GroupClusterJson result = entityToJsonConverter.clusterEntityToClusterJson(groupClusterEntity, false); - GroupClusterJson result = entityToJsonConverter.clusterEntityToClusterJson(groupClusterEntity); + verify(entityToJsonConverter, times(1)).groupEntityToJson(groupEntity, false); assertEquals(groupClusterEntity.getId(), result.clusterId()); assertEquals(groupClusterEntity.getName(), result.name()); @@ -282,27 +297,49 @@ public void testClusterEntityToClusterJson() { assertEquals(1, result.groups().size()); assertEquals(groupJson, result.groups().get(0)); assertEquals(ApiRoutes.COURSE_BASE_PATH + "/" + courseEntity.getId(), result.courseUrl()); + + /* Hide studentNumber */ + doReturn(groupJson).when(entityToJsonConverter).groupEntityToJson(groupEntity, true); + + result = entityToJsonConverter.clusterEntityToClusterJson(groupClusterEntity, true); + + verify(entityToJsonConverter, times(1)).groupEntityToJson(groupEntity, true); } @Test public void testUserEntityToUserReference() { - UserReferenceJson result = entityToJsonConverter.userEntityToUserReference(userEntity); + userEntity.setStudentNumber("studentNumber"); + UserReferenceJson result = entityToJsonConverter.userEntityToUserReference(userEntity, false); assertEquals(userEntity.getId(), result.getUserId()); assertEquals(userEntity.getName() + " " + userEntity.getSurname(), result.getName()); assertEquals(userEntity.getEmail(), result.getEmail()); + assertEquals(userEntity.getStudentNumber(), result.getStudentNumber()); + + /* Hide studentnumber */ + result = entityToJsonConverter.userEntityToUserReference(userEntity, true); + assertNull(result.getStudentNumber()); } @Test public void testUserEntityToUserReferenceWithRelation() { - doReturn(userReferenceJson).when(entityToJsonConverter).userEntityToUserReference(userEntity); - UserReferenceWithRelation result = entityToJsonConverter.userEntityToUserReferenceWithRelation(userEntity, CourseRelation.creator); + + doReturn(userReferenceJson).when(entityToJsonConverter).userEntityToUserReference(userEntity, false); + UserReferenceWithRelation result = entityToJsonConverter.userEntityToUserReferenceWithRelation(userEntity, CourseRelation.creator, false); assertEquals(userReferenceJson, result.getUser()); assertEquals(CourseRelation.creator.toString(), result.getRelation()); - result = entityToJsonConverter.userEntityToUserReferenceWithRelation(userEntity, CourseRelation.course_admin); + verify(entityToJsonConverter, times(1)).userEntityToUserReference(userEntity, false); + + /* Hide studentnumber */ + doReturn(userReferenceJson).when(entityToJsonConverter).userEntityToUserReference(userEntity, true); + result = entityToJsonConverter.userEntityToUserReferenceWithRelation(userEntity, CourseRelation.creator, true); + verify(entityToJsonConverter, times(1)).userEntityToUserReference(userEntity, true); + + /* Different relations */ + result = entityToJsonConverter.userEntityToUserReferenceWithRelation(userEntity, CourseRelation.course_admin, false); assertEquals(CourseRelation.course_admin.toString(), result.getRelation()); - result = entityToJsonConverter.userEntityToUserReferenceWithRelation(userEntity, CourseRelation.enrolled); + result = entityToJsonConverter.userEntityToUserReferenceWithRelation(userEntity, CourseRelation.enrolled, false); assertEquals(CourseRelation.enrolled.toString(), result.getRelation()); } @@ -315,8 +352,8 @@ public void testCourseEntityToCourseWithInfo() { when(courseRepository.findTeacherByCourseId(courseEntity.getId())).thenReturn(userEntity); when(courseRepository.findAssistantsByCourseId(courseEntity.getId())).thenReturn(List.of(otherUser)); - doReturn(userReferenceJson).when(entityToJsonConverter).userEntityToUserReference(userEntity); - doReturn(otherUserReferenceJson).when(entityToJsonConverter).userEntityToUserReference(otherUser); + doReturn(userReferenceJson).when(entityToJsonConverter).userEntityToUserReference(userEntity, true); + doReturn(otherUserReferenceJson).when(entityToJsonConverter).userEntityToUserReference(otherUser, true); CourseWithInfoJson result = entityToJsonConverter.courseEntityToCourseWithInfo(courseEntity, joinLink, false); assertEquals(courseEntity.getId(), result.courseId()); diff --git a/backend/app/src/test/test-cases/DockerSubmissionTestTest/d__test.zip b/backend/app/src/test/test-cases/DockerSubmissionTestTest/d__test.zip index d50e8b5a1ff565803ba5881494ffcdb3e354bad5..9ad7ca11633f3de8c62a501ead1805e577a40c7e 100644 GIT binary patch delta 26 gcmZ3)xQLM_z?+#xgn@&DgW>SXi97*JKr+q+08m{A8vp Date: Sat, 18 May 2024 06:40:05 +0200 Subject: [PATCH 09/11] Added lockGroupsAfter --- .../pidgeon/controllers/ClusterController.java | 6 ++++++ .../model/json/GroupClusterCreateJson.java | 5 ++++- .../pidgeon/model/json/GroupClusterJson.java | 1 + .../model/json/GroupClusterUpdateJson.java | 11 +++++++++++ .../postgre/models/GroupClusterEntity.java | 11 +++++++++++ .../pidgeon/postgre/models/ProjectEntity.java | 1 + .../pidgeon/util/EntityToJsonConverter.java | 1 + .../java/com/ugent/pidgeon/util/GroupUtil.java | 18 +++++++++++++++++- backend/database/start_database.sql | 1 + 9 files changed, 53 insertions(+), 2 deletions(-) diff --git a/backend/app/src/main/java/com/ugent/pidgeon/controllers/ClusterController.java b/backend/app/src/main/java/com/ugent/pidgeon/controllers/ClusterController.java index 55f01119..ebc911bd 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/controllers/ClusterController.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/controllers/ClusterController.java @@ -112,6 +112,7 @@ public ResponseEntity createClusterForCourse(@PathVariable("courseid") Long c clusterJson.groupCount() ); cluster.setCreatedAt(OffsetDateTime.now()); + cluster.setLockGroupsAfter(clusterJson.lockGroupsAfter()); GroupClusterEntity clusterEntity = groupClusterRepository.save(cluster); for (int i = 0; i < clusterJson.groupCount(); i++) { @@ -182,6 +183,7 @@ public ResponseEntity doGroupClusterUpdate(GroupClusterEntity clusterEntity, } clusterEntity.setMaxSize(clusterJson.getCapacity()); clusterEntity.setName(clusterJson.getName()); + clusterEntity.setLockGroupsAfter(clusterJson.getLockGroupsAfter()); clusterEntity = groupClusterRepository.save(clusterEntity); return ResponseEntity.ok(entityToJsonConverter.clusterEntityToClusterJson(clusterEntity, false)); } @@ -261,6 +263,10 @@ public ResponseEntity patchCluster(@PathVariable("clusterid") Long clusterid, clusterJson.setName(cluster.getName()); } + if (clusterJson.getLockGroupsAfter() == null) { + clusterJson.setLockGroupsAfter(cluster.getLockGroupsAfter()); + } + return doGroupClusterUpdate(cluster, clusterJson); } diff --git a/backend/app/src/main/java/com/ugent/pidgeon/model/json/GroupClusterCreateJson.java b/backend/app/src/main/java/com/ugent/pidgeon/model/json/GroupClusterCreateJson.java index 8e461631..e7e7161a 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/model/json/GroupClusterCreateJson.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/model/json/GroupClusterCreateJson.java @@ -1,9 +1,12 @@ package com.ugent.pidgeon.model.json; +import java.time.OffsetDateTime; + public record GroupClusterCreateJson( String name, Integer capacity, - Integer groupCount + Integer groupCount, + OffsetDateTime lockGroupsAfter ) { public GroupClusterCreateJson { } diff --git a/backend/app/src/main/java/com/ugent/pidgeon/model/json/GroupClusterJson.java b/backend/app/src/main/java/com/ugent/pidgeon/model/json/GroupClusterJson.java index 30714044..6d29accd 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/model/json/GroupClusterJson.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/model/json/GroupClusterJson.java @@ -10,6 +10,7 @@ public record GroupClusterJson( int groupCount, OffsetDateTime createdAt, List groups, + OffsetDateTime lockGroupsAfter, String courseUrl ) { diff --git a/backend/app/src/main/java/com/ugent/pidgeon/model/json/GroupClusterUpdateJson.java b/backend/app/src/main/java/com/ugent/pidgeon/model/json/GroupClusterUpdateJson.java index 3d8b3a2a..72ea9ec0 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/model/json/GroupClusterUpdateJson.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/model/json/GroupClusterUpdateJson.java @@ -1,8 +1,11 @@ package com.ugent.pidgeon.model.json; +import java.time.OffsetDateTime; + public class GroupClusterUpdateJson { private String name; private Integer capacity; + private OffsetDateTime lockGroupsAfter; public GroupClusterUpdateJson() { } @@ -16,6 +19,10 @@ public Integer getCapacity() { return capacity; } + public OffsetDateTime getLockGroupsAfter() { + return lockGroupsAfter; + } + // Setters public void setName(String name) { this.name = name; @@ -24,4 +31,8 @@ public void setName(String name) { public void setCapacity(Integer capacity) { this.capacity = capacity; } + + public void setLockGroupsAfter(OffsetDateTime lockGroupsAfter) { + this.lockGroupsAfter = lockGroupsAfter; + } } \ No newline at end of file diff --git a/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/GroupClusterEntity.java b/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/GroupClusterEntity.java index ea2818bb..cc9678ae 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/GroupClusterEntity.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/GroupClusterEntity.java @@ -26,6 +26,9 @@ public class GroupClusterEntity { @Column(name="group_amount", nullable=false) private int groupAmount; + @Column(name = "lock_groups_after") + private OffsetDateTime lockGroupsAfter; + @Column(name = "created_at") private OffsetDateTime createdAt; @@ -87,4 +90,12 @@ public OffsetDateTime getCreatedAt() { public void setCreatedAt(OffsetDateTime createdAt) { this.createdAt = createdAt; } + + public OffsetDateTime getLockGroupsAfter() { + return lockGroupsAfter; + } + + public void setLockGroupsAfter(OffsetDateTime lockGroupsAfter) { + this.lockGroupsAfter = lockGroupsAfter; + } } diff --git a/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/ProjectEntity.java b/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/ProjectEntity.java index 0735d649..b3cc7bac 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/ProjectEntity.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/postgre/models/ProjectEntity.java @@ -41,6 +41,7 @@ public class ProjectEntity { @Column(name = "visible_after") private OffsetDateTime visibleAfter; + public ProjectEntity(long courseId, String name, String description, long groupClusterId, Long testId, Boolean visible, Integer maxScore, OffsetDateTime deadline) { this.courseId = courseId; this.name = name; diff --git a/backend/app/src/main/java/com/ugent/pidgeon/util/EntityToJsonConverter.java b/backend/app/src/main/java/com/ugent/pidgeon/util/EntityToJsonConverter.java index 152b2594..4a5bedd4 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/util/EntityToJsonConverter.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/util/EntityToJsonConverter.java @@ -74,6 +74,7 @@ public GroupClusterJson clusterEntityToClusterJson(GroupClusterEntity cluster, b cluster.getGroupAmount(), cluster.getCreatedAt(), groups, + cluster.getLockGroupsAfter(), ApiRoutes.COURSE_BASE_PATH + "/" + cluster.getCourseId() ); } diff --git a/backend/app/src/main/java/com/ugent/pidgeon/util/GroupUtil.java b/backend/app/src/main/java/com/ugent/pidgeon/util/GroupUtil.java index abb96d06..a3cce43f 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/util/GroupUtil.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/util/GroupUtil.java @@ -7,6 +7,8 @@ import com.ugent.pidgeon.postgre.models.types.UserRole; import com.ugent.pidgeon.postgre.repository.GroupClusterRepository; import com.ugent.pidgeon.postgre.repository.GroupRepository; +import java.time.OffsetDateTime; +import javax.swing.GroupLayout.Group; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; @@ -142,7 +144,12 @@ public CheckResult canAddUserToGroup(long groupId, long userId, UserEntity return new CheckResult<>(HttpStatus.FORBIDDEN, "Cannot add user to individual group", null); } - if (isAdminOfGroup(groupId, userToAdd).getStatus() == HttpStatus.OK) { + OffsetDateTime lockGroupTime = cluster.getData().getLockGroupsAfter(); + if (lockGroupTime != null && lockGroupTime.isBefore(OffsetDateTime.now()) && !isAdmin) { + return new CheckResult<>(HttpStatus.FORBIDDEN, "Groups are locked", null); + } + + if (isAdminOfGroup(groupId, userToAdd).getStatus().equals(HttpStatus.OK)) { return new CheckResult<>(HttpStatus.FORBIDDEN, "Cannot add a course admin to a group", null); } @@ -166,10 +173,19 @@ public CheckResult canRemoveUserFromGroup(long groupId, long userId, UserE if (admin.getStatus() != HttpStatus.OK) { return admin; } + } else { if (groupClusterRepository.inArchivedCourse(group.getClusterId())) { return new CheckResult<>(HttpStatus.FORBIDDEN, "Cannot leave a group in an archived course", null); } + CheckResult cluster = clusterUtil.getClusterIfExists(group.getClusterId()); + if (cluster.getStatus() != HttpStatus.OK) { + return new CheckResult<>(HttpStatus.INTERNAL_SERVER_ERROR, "Error while checking cluster", null); + } + OffsetDateTime lockGroupTime = cluster.getData().getLockGroupsAfter(); + if (lockGroupTime != null && lockGroupTime.isBefore(OffsetDateTime.now())) { + return new CheckResult<>(HttpStatus.FORBIDDEN, "Groups are locked", null); + } } if (!groupRepository.userInGroup(groupId, userId)) { return new CheckResult<>(HttpStatus.NOT_FOUND, "User is not in the group", null); diff --git a/backend/database/start_database.sql b/backend/database/start_database.sql index 4b7f936d..311762e1 100644 --- a/backend/database/start_database.sql +++ b/backend/database/start_database.sql @@ -38,6 +38,7 @@ CREATE TABLE group_clusters ( max_size INT NOT NULL, cluster_name VARCHAR(100) NOT NULL, group_amount INT NOT NULL, + lock_groups_after TIMESTAMP WITH TIME ZONE DEFAULT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP ); From 7b91b247472d17e1ee7f6e86909cbfbe3bd4a339 Mon Sep 17 00:00:00 2001 From: Aqua-sc <108478185+Aqua-sc@users.noreply.github.com> Date: Sat, 18 May 2024 06:58:57 +0200 Subject: [PATCH 10/11] Updated tests --- .../controllers/ClusterControllerTest.java | 33 ++++++++++++++----- .../ugent/pidgeon/util/ClusterUtilTest.java | 14 ++++---- .../util/EntityToJsonConverterTest.java | 2 ++ .../com/ugent/pidgeon/util/GroupUtilTest.java | 32 ++++++++++++++++++ 4 files changed, 66 insertions(+), 15 deletions(-) diff --git a/backend/app/src/test/java/com/ugent/pidgeon/controllers/ClusterControllerTest.java b/backend/app/src/test/java/com/ugent/pidgeon/controllers/ClusterControllerTest.java index bc3392e3..440d329e 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/controllers/ClusterControllerTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/controllers/ClusterControllerTest.java @@ -14,6 +14,7 @@ import com.ugent.pidgeon.util.*; import java.time.OffsetDateTime; import java.util.Collections; +import java.util.Objects; import java.util.logging.Logger; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -31,6 +32,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.argThat; @@ -91,6 +93,7 @@ public void setup() { groupClusterEntity.getGroupAmount(), OffsetDateTime.now(), Collections.emptyList(), + null, ""); groupEntity = new GroupEntity("groupName", 1L); groupEntity.setId(78L); @@ -137,10 +140,10 @@ public void testCreateClusterForCourse() throws Exception { String url = ApiRoutes.COURSE_BASE_PATH + "/" + courseId +"/clusters"; /* If the user is an admin of the course and the json is valid, the cluster is created */ - String request = "{\"name\": \"test\", \"capacity\": 20, \"groupCount\": 5}"; + String request = "{\"name\": \"test\", \"capacity\": 20, \"groupCount\": 5, \"lockGroupsAfter\": null}"; when(courseUtil.getCourseIfAdmin(courseId, getMockUser())).thenReturn(new CheckResult<>(HttpStatus.OK, "", courseEntity)); when(clusterUtil.checkGroupClusterCreateJson(argThat( - json -> json.name().equals("test") && json.capacity().equals(20) && json.groupCount().equals(5) + json -> json.name().equals("test") && json.capacity().equals(20) && json.groupCount().equals(5) && json.lockGroupsAfter() == null ))).thenReturn(new CheckResult<>(HttpStatus.OK, "", null)); when(groupClusterRepository.save(any())).thenReturn(groupClusterEntity); when(entityToJsonConverter.clusterEntityToClusterJson(groupClusterEntity, false)).thenReturn(groupClusterJson); @@ -151,6 +154,18 @@ public void testCreateClusterForCourse() throws Exception { .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(content().json(objectMapper.writeValueAsString(groupClusterJson))); + /* lockGroupsAfter not null */ + request = "{\"name\": \"test\", \"capacity\": 20, \"groupCount\": 5, \"lockGroupsAfter\": \"2024-01-01T00:00:00Z\"}"; + reset(clusterUtil); + when(clusterUtil.checkGroupClusterCreateJson(argThat( + json -> json.name().equals("test") && json.capacity().equals(20) && json.groupCount().equals(5) && json.lockGroupsAfter().equals(OffsetDateTime.parse("2024-01-01T00:00:00Z")) + ))).thenReturn(new CheckResult<>(HttpStatus.OK, "", null)); + mockMvc.perform(MockMvcRequestBuilders.post(url) + .contentType(MediaType.APPLICATION_JSON) + .content(request)) + .andExpect(status().isCreated()); + + /* If the json is invalid, the corresponding status code is returned */ reset(clusterUtil); when(clusterUtil.checkGroupClusterCreateJson(any())).thenReturn(new CheckResult<>(HttpStatus.I_AM_A_TEAPOT, "", null)); @@ -203,7 +218,7 @@ public void testGetCluster() throws Exception { @Test public void testUpdateCluster() throws Exception { String url = ApiRoutes.CLUSTER_BASE_PATH + "/" + groupClusterEntity.getId(); - String request = "{\"name\": \"newclustername\", \"capacity\": 22}"; + String request = "{\"name\": \"newclustername\", \"capacity\": 22, \"lockGroupsAfter\": \"2024-01-01T00:00:00Z\"}"; String originalname = groupClusterEntity.getName(); Integer originalcapacity = groupClusterEntity.getMaxSize(); /* If the user is an admin of the cluster, the cluster isn't individual and the json is valid, the cluster is updated */ @@ -211,10 +226,10 @@ public void testUpdateCluster() throws Exception { when(clusterUtil.getGroupClusterEntityIfAdminAndNotIndividual(groupClusterEntity.getId(), getMockUser())) .thenReturn(new CheckResult<>(HttpStatus.OK, "", groupClusterEntity)); when(clusterUtil.checkGroupClusterUpdateJson( - argThat(json -> json.getName().equals("newclustername") && json.getCapacity().equals(22)) + argThat(json -> json.getName().equals("newclustername") && json.getCapacity().equals(22) && json.getLockGroupsAfter().equals(OffsetDateTime.parse("2024-01-01T00:00:00Z"))) )).thenReturn(new CheckResult<>(HttpStatus.OK, "", null)); copy.setName("newclustername"); - GroupClusterJson updated = new GroupClusterJson(1L, "newclustername", 20, 5, OffsetDateTime.now(), Collections.emptyList(), ""); + GroupClusterJson updated = new GroupClusterJson(1L, "newclustername", 20, 5, OffsetDateTime.now(), Collections.emptyList(), null, ""); when(groupClusterRepository.save(groupClusterEntity)).thenReturn(copy); when(entityToJsonConverter.clusterEntityToClusterJson(copy, false)).thenReturn(updated); mockMvc.perform(MockMvcRequestBuilders.put(url) @@ -343,7 +358,8 @@ public void testPatchCluster() throws Exception { when(clusterUtil.getGroupClusterEntityIfAdminAndNotIndividual(groupClusterEntity.getId(), getMockUser())) .thenReturn(new CheckResult<>(HttpStatus.OK, "", groupClusterEntity)); when(clusterUtil.checkGroupClusterUpdateJson( - argThat(json -> json.getName() == groupClusterEntity.getName() && json.getCapacity() == groupClusterEntity.getMaxSize()) + argThat(json -> Objects.equals(json.getName(), groupClusterEntity.getName()) + && json.getCapacity() == groupClusterEntity.getMaxSize()) )).thenReturn(new CheckResult<>(HttpStatus.OK, "", null)); when(groupClusterRepository.save(groupClusterEntity)).thenReturn(groupClusterEntity); when(entityToJsonConverter.clusterEntityToClusterJson(groupClusterEntity, false)).thenReturn(groupClusterJson); @@ -357,7 +373,7 @@ public void testPatchCluster() throws Exception { assertEquals(originalcapacity, groupClusterEntity.getMaxSize()); /* If fields are not null they are updated */ - request = "{\"name\": \"newclustername\", \"capacity\": 22}"; + request = "{\"name\": \"newclustername\", \"capacity\": 22, \"lockGroupsAfter\": \"2024-01-01T00:00:00Z\"}"; reset(clusterUtil); when(clusterUtil.getGroupClusterEntityIfAdminAndNotIndividual(groupClusterEntity.getId(), getMockUser())) .thenReturn(new CheckResult<>(HttpStatus.OK, "", groupClusterEntity)); @@ -365,7 +381,7 @@ public void testPatchCluster() throws Exception { when(clusterUtil.checkGroupClusterUpdateJson( argThat(json -> json.getName().equals("newclustername") && json.getCapacity().equals(22)) )).thenReturn(new CheckResult<>(HttpStatus.OK, "", null)); - GroupClusterJson updated = new GroupClusterJson(1L, "newclustername", 22, 5, OffsetDateTime.now(), Collections.emptyList(), ""); + GroupClusterJson updated = new GroupClusterJson(1L, "newclustername", 22, 5, OffsetDateTime.now(), Collections.emptyList(), null, ""); when(groupClusterRepository.save(groupClusterEntity)).thenReturn(copy); when(entityToJsonConverter.clusterEntityToClusterJson(copy, false)).thenReturn(updated); mockMvc.perform(MockMvcRequestBuilders.patch(url) @@ -376,6 +392,7 @@ public void testPatchCluster() throws Exception { .andExpect(content().json(objectMapper.writeValueAsString(updated))); assertNotEquals(originalname, groupClusterEntity.getName()); assertNotEquals(originalcapacity, groupClusterEntity.getMaxSize()); + assertNotNull(groupClusterEntity.getLockGroupsAfter()); /* If the json is invalid, the corresponding status code is returned */ reset(clusterUtil); diff --git a/backend/app/src/test/java/com/ugent/pidgeon/util/ClusterUtilTest.java b/backend/app/src/test/java/com/ugent/pidgeon/util/ClusterUtilTest.java index b2450230..9a1e2609 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/util/ClusterUtilTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/util/ClusterUtilTest.java @@ -226,38 +226,38 @@ void testCheckGroupClusterUpdateJson() { @Test void testCheckGroupClusterCreateJson() { - GroupClusterCreateJson json = new GroupClusterCreateJson("clustername", 5, 5); + GroupClusterCreateJson json = new GroupClusterCreateJson("clustername", 5, 5, null); /* All checks succeed */ CheckResult result = clusterUtil.checkGroupClusterCreateJson(json); assertEquals(HttpStatus.OK, result.getStatus()); /* GroupCount is negative */ - json = new GroupClusterCreateJson("clustername", 5, -5); + json = new GroupClusterCreateJson("clustername", 5, -5, null); result = clusterUtil.checkGroupClusterCreateJson(json); assertEquals(HttpStatus.BAD_REQUEST, result.getStatus()); /* Capacity is smaller than 1 */ - json = new GroupClusterCreateJson("clustername", 0, 5); + json = new GroupClusterCreateJson("clustername", 0, 5, null); result = clusterUtil.checkGroupClusterCreateJson(json); assertEquals(HttpStatus.BAD_REQUEST, result.getStatus()); /* Name is empty */ - json = new GroupClusterCreateJson("", 5, 5); + json = new GroupClusterCreateJson("", 5, 5, null); result = clusterUtil.checkGroupClusterCreateJson(json); assertEquals(HttpStatus.BAD_REQUEST, result.getStatus()); /* Capacity is null */ - json = new GroupClusterCreateJson("clustername", null, 5); + json = new GroupClusterCreateJson("clustername", null, 5, null); result = clusterUtil.checkGroupClusterCreateJson(json); assertEquals(HttpStatus.BAD_REQUEST, result.getStatus()); /* Name is null */ - json = new GroupClusterCreateJson(null, 5, 5); + json = new GroupClusterCreateJson(null, 5, 5, null); result = clusterUtil.checkGroupClusterCreateJson(json); assertEquals(HttpStatus.BAD_REQUEST, result.getStatus()); /* GroupCount is null */ - json = new GroupClusterCreateJson("clustername", 5, null); + json = new GroupClusterCreateJson("clustername", 5, null, null); result = clusterUtil.checkGroupClusterCreateJson(json); assertEquals(HttpStatus.BAD_REQUEST, result.getStatus()); } diff --git a/backend/app/src/test/java/com/ugent/pidgeon/util/EntityToJsonConverterTest.java b/backend/app/src/test/java/com/ugent/pidgeon/util/EntityToJsonConverterTest.java index f4806083..903ac6eb 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/util/EntityToJsonConverterTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/util/EntityToJsonConverterTest.java @@ -282,6 +282,7 @@ public String getStudentNumber() { @Test public void testClusterEntityToClusterJson() { + groupClusterEntity.setLockGroupsAfter(OffsetDateTime.now()); when(groupRepository.findAllByClusterId(groupClusterEntity.getId())).thenReturn(List.of(groupEntity)); doReturn(groupJson).when(entityToJsonConverter).groupEntityToJson(groupEntity, false); @@ -296,6 +297,7 @@ public void testClusterEntityToClusterJson() { assertEquals(groupClusterEntity.getCreatedAt(), result.createdAt()); assertEquals(1, result.groups().size()); assertEquals(groupJson, result.groups().get(0)); + assertEquals(groupClusterEntity.getLockGroupsAfter(), result.lockGroupsAfter()); assertEquals(ApiRoutes.COURSE_BASE_PATH + "/" + courseEntity.getId(), result.courseUrl()); /* Hide studentNumber */ diff --git a/backend/app/src/test/java/com/ugent/pidgeon/util/GroupUtilTest.java b/backend/app/src/test/java/com/ugent/pidgeon/util/GroupUtilTest.java index f02bcc17..ac039900 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/util/GroupUtilTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/util/GroupUtilTest.java @@ -155,6 +155,16 @@ public void TestCanAddUserToGroup() { CheckResult result = groupUtil.canAddUserToGroup(group.getId(), mockUser.getId(), mockUser); assertEquals(HttpStatus.OK, result.getStatus()); + /* Trying to join a group when the groups are locked */ + groupCluster.setLockGroupsAfter(OffsetDateTime.now().minusDays(1)); + result = groupUtil.canAddUserToGroup(group.getId(), mockUser.getId(), mockUser); + assertEquals(HttpStatus.FORBIDDEN, result.getStatus()); + + /* Trying to join a group when a locktime is configured but it hasn't passed yet */ + groupCluster.setLockGroupsAfter(OffsetDateTime.now().plusDays(1)); + result = groupUtil.canAddUserToGroup(group.getId(), mockUser.getId(), mockUser); + assertEquals(HttpStatus.OK, result.getStatus()); + /* Trying to add someone else as admin */ doReturn(new CheckResult<>(HttpStatus.OK, "", null)). when(groupUtil).isAdminOfGroup(group.getId(), mockUser); @@ -166,6 +176,12 @@ public void TestCanAddUserToGroup() { result = groupUtil.canAddUserToGroup(group.getId(), otherUserId, mockUser); assertEquals(HttpStatus.OK, result.getStatus()); + /* Adding someone to a group as admin after the locktime has passed */ + groupCluster.setLockGroupsAfter(OffsetDateTime.now().minusDays(1)); + result = groupUtil.canAddUserToGroup(group.getId(), otherUserId, mockUser); + assertEquals(HttpStatus.OK, result.getStatus()); + + /* Group is already full but it's an admin adding someone else */ when(groupRepository.countUsersInGroup(group.getId())).thenReturn(groupCluster.getMaxSize()); result = groupUtil.canAddUserToGroup(group.getId(), otherUserId, mockUser); @@ -238,10 +254,26 @@ public void testCanRemoveUserFromGroup() throws Exception { when(groupClusterRepository.inArchivedCourse(group.getClusterId())).thenReturn(false); when(groupRepository.userInGroup(group.getId(), mockUser.getId())).thenReturn(true); when(clusterUtil.isIndividualCluster(group.getClusterId())).thenReturn(false); + when(clusterUtil.getClusterIfExists(group.getClusterId())).thenReturn(new CheckResult<>(HttpStatus.OK, "", groupCluster)); CheckResult result = groupUtil.canRemoveUserFromGroup(group.getId(), mockUser.getId(), mockUser); assertEquals(HttpStatus.OK, result.getStatus()); + /* Trying to leave group when groups are locked */ + groupCluster.setLockGroupsAfter(OffsetDateTime.now().minusDays(1)); + result = groupUtil.canRemoveUserFromGroup(group.getId(), mockUser.getId(), mockUser); + assertEquals(HttpStatus.FORBIDDEN, result.getStatus()); + + /* Trying to leave group when a locktime is configured but it hasn't passed yet */ + groupCluster.setLockGroupsAfter(OffsetDateTime.now().plusDays(1)); + result = groupUtil.canRemoveUserFromGroup(group.getId(), mockUser.getId(), mockUser); + assertEquals(HttpStatus.OK, result.getStatus()); + + /* Getting cluster fails */ + when(clusterUtil.getClusterIfExists(group.getClusterId())).thenReturn(new CheckResult<>(HttpStatus.I_AM_A_TEAPOT, "", null)); + result = groupUtil.canRemoveUserFromGroup(group.getId(), mockUser.getId(), mockUser); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, result.getStatus()); + /* Trying to remove someone else */ long otherUserId = 5L; doReturn(new CheckResult<>(HttpStatus.OK, "", null)). From 746a3197fda64ed2fa5792d40ce3dc89646b719c Mon Sep 17 00:00:00 2001 From: Aqua-sc <108478185+Aqua-sc@users.noreply.github.com> Date: Sat, 18 May 2024 07:18:33 +0200 Subject: [PATCH 11/11] small fix to accepted fields if no test --- .../com/ugent/pidgeon/controllers/SubmissionController.java | 2 ++ .../com/ugent/pidgeon/controllers/SubmissionControllerTest.java | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/app/src/main/java/com/ugent/pidgeon/controllers/SubmissionController.java b/backend/app/src/main/java/com/ugent/pidgeon/controllers/SubmissionController.java index 4edec9f9..4327219c 100644 --- a/backend/app/src/main/java/com/ugent/pidgeon/controllers/SubmissionController.java +++ b/backend/app/src/main/java/com/ugent/pidgeon/controllers/SubmissionController.java @@ -201,6 +201,8 @@ public ResponseEntity submitFile(@RequestParam("file") MultipartFile file, @P Logger.getLogger("SubmissionController").info("no tests"); submission.setStructureFeedback("No specific structure requested for this project."); submission.setStructureAccepted(true); + submission.setDockerAccepted(true); + submissionRepository.save(submission); } else { // Check file structure diff --git a/backend/app/src/test/java/com/ugent/pidgeon/controllers/SubmissionControllerTest.java b/backend/app/src/test/java/com/ugent/pidgeon/controllers/SubmissionControllerTest.java index aada0734..78b368d9 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/controllers/SubmissionControllerTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/controllers/SubmissionControllerTest.java @@ -297,7 +297,7 @@ public void testSubmitFile() throws Exception { /* assertEquals(DockerTestState.running, submission.getDockerTestState()); */ // This executes too quickly so we can't test this - Thread.sleep(1000); + Thread.sleep(2000); // File repository needs to save again after setting path verify(fileRepository, times(1)).save(argThat(