Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow admin to submit #264

Merged
merged 4 commits into from
May 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading