Skip to content

Commit

Permalink
Merge pull request #264 from SELab-2/feature/courseadminsubmit
Browse files Browse the repository at this point in the history
Allow admin to submit
  • Loading branch information
usserwoutV2 authored May 18, 2024
2 parents e8e2d3b + 534b14f commit a8c3548
Show file tree
Hide file tree
Showing 13 changed files with 164 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
Expand Down Expand Up @@ -267,6 +268,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.");
}
Expand Down Expand Up @@ -398,4 +400,17 @@ public ResponseEntity<?> getSubmissionsForGroup(@PathVariable("projectid") long
List<SubmissionJson> 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<Void> checkResult = projectUtil.isProjectAdmin(projectid, auth.getUserEntity());
if (!checkResult.getStatus().equals(HttpStatus.OK)) {
return ResponseEntity.status(checkResult.getStatus()).body(checkResult.getMessage());
}

List<SubmissionEntity> submissions = submissionRepository.findAdminSubmissionsByProjectId(projectid);
List<SubmissionJson> res = submissions.stream().map(entityToJsonConverter::getSubmissionJson).toList();
return ResponseEntity.ok(res);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -56,10 +56,14 @@ public SubmissionEntity(long projectId, long groupId, Long fileId, OffsetDateTim
this.dockerAccepted = dockerAccepted;
}

public long getGroupId() {
public Long getGroupId() {
return groupId;
}

public void setGroupId(Long groupId) {
this.groupId = groupId;
}

public long getFileId() {
return fileId;
}
Expand Down Expand Up @@ -155,4 +159,6 @@ public DockerTestType getDockerTestType() {
public void setDockerType(DockerTestType dockerType) {
this.dockerType = dockerType.toString();
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,12 @@ SELECT MAX(s2.submissionTime)
""")
Optional<SubmissionEntity> findLatestsSubmissionIdsByProjectAndGroupId(long projectId, long groupId);

@Query(value = """
SELECT s FROM SubmissionEntity s
WHERE s.projectId = :projectId
AND s.groupId IS NULL
""")
List<SubmissionEntity> findAdminSubmissionsByProjectId(long projectId);

List<SubmissionEntity> findByProjectIdAndGroupId(long projectid, long groupid);
}
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,16 +205,16 @@ public CheckResult<Void> 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<Void> canGetProjectGroupData(long groupId, long projectId, UserEntity user) {
public CheckResult<Void> canGetProjectGroupData(Long groupId, long projectId, UserEntity user) {
CheckResult<ProjectEntity> 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,32 +75,34 @@ public CheckResult<SubmissionEntity> canDeleteSubmission(long submissionId, User
* @return CheckResult with the status of the check and the group id
*/
public CheckResult<Long> checkOnSubmit(long projectId, UserEntity user) {
CheckResult<ProjectEntity> 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<GroupEntity> groupCheck = groupUtil.getGroupIfExists(groupId);
if (groupCheck.getStatus() != HttpStatus.OK) {
return new CheckResult<>(groupCheck.getStatus(), groupCheck.getMessage(), null);
}
GroupEntity group = groupCheck.getData();
CheckResult<Void> 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<GroupEntity> 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<ProjectEntity> 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())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -529,4 +529,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();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ public void setUp() {

submissionEntity = new SubmissionEntity(
22,
45,
45L,
99L,
OffsetDateTime.MIN,
true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ public void setUp() {

submissionEntity = new SubmissionEntity(
22,
45,
45L,
99L,
OffsetDateTime.MIN,
true,
Expand Down Expand Up @@ -456,7 +456,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);
projectEntity.setVisibleAfter(OffsetDateTime.now());
when(projectRepository.findGroupIdsByProjectId(projectEntity.getId())).thenReturn(List.of(groupEntity.getId(), secondGroup.getId()));
Expand Down Expand Up @@ -598,6 +598,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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,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());
}


Expand Down
Loading

0 comments on commit a8c3548

Please sign in to comment.