Skip to content

Commit

Permalink
Merge pull request #263 from SELab-2/feature/extra_files_in_test
Browse files Browse the repository at this point in the history
Uploaden extra files voor testen
  • Loading branch information
usserwoutV2 authored May 18, 2024
2 parents a8c3548 + b274bdc commit 4516f6b
Show file tree
Hide file tree
Showing 17 changed files with 563 additions and 146 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ public ResponseEntity<?> submitFile(@RequestParam("file") MultipartFile file, @P
//Save the file on the server
String filename = file.getOriginalFilename();
Path path = Filehandler.getSubmissionPath(projectid, groupId, submission.getId());
File savedFile = Filehandler.saveSubmission(path, file);
File savedFile = Filehandler.saveFile(path, file, Filehandler.SUBMISSION_FILENAME);
String pathname = path.resolve(Filehandler.SUBMISSION_FILENAME).toString();

//Update name and path for the file entry
Expand Down Expand Up @@ -240,7 +240,7 @@ public ResponseEntity<?> submitFile(@RequestParam("file") MultipartFile file, @P
try {
// Check if docker tests succeed
DockerSubmissionTestModel dockerModel = new DockerSubmissionTestModel(testEntity.getDockerImage());
DockerOutput dockerOutput = testRunner.runDockerTest(new ZipFile(finalSavedFile), testEntity, artifactPath, dockerModel);
DockerOutput dockerOutput = testRunner.runDockerTest(new ZipFile(finalSavedFile), testEntity, artifactPath, dockerModel, projectid);
if (dockerOutput == null) {
throw new RuntimeException("Error while running docker tests.");
}
Expand Down Expand Up @@ -301,23 +301,7 @@ public ResponseEntity<?> getSubmissionFile(@PathVariable("submissionid") long su
}

// Get the file from the server
try {
Resource zipFile = Filehandler.getFileAsResource(Path.of(file.getPath()));
if (zipFile == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("File not found.");
}

// Set headers for the response
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + file.getName());
headers.add(HttpHeaders.CONTENT_TYPE, "application/zip");

return ResponseEntity.ok()
.headers(headers)
.body(zipFile);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
}
return Filehandler.getZipFileAsResponse(Path.of(file.getPath()), file.getName());
}

@GetMapping(ApiRoutes.SUBMISSION_BASE_PATH + "/{submissionid}/artifacts") //Route to get a submission
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,15 @@
import com.ugent.pidgeon.postgre.models.types.UserRole;
import com.ugent.pidgeon.postgre.repository.*;
import com.ugent.pidgeon.util.*;
import java.io.File;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.nio.file.Path;

import java.util.Optional;
import java.util.function.Function;

@RestController
public class TestController {

Expand Down Expand Up @@ -238,5 +234,97 @@ public ResponseEntity<?> deleteTestById(@PathVariable("projectid") long projectI
}
return ResponseEntity.ok().build();
}

@PutMapping(ApiRoutes.PROJECT_BASE_PATH + "/{projectid}/tests/extrafiles")
@Roles({UserRole.teacher, UserRole.student})
public ResponseEntity<?> uploadExtraTestFiles(
@PathVariable("projectid") long projectId,
@RequestParam("file") MultipartFile file,
Auth auth
) {
CheckResult<TestEntity> checkResult = testUtil.getTestIfAdmin(projectId, auth.getUserEntity());
if (!checkResult.getStatus().equals(HttpStatus.OK)) {
return ResponseEntity.status(checkResult.getStatus()).body(checkResult.getMessage());
}

TestEntity testEntity = checkResult.getData();

try {
Path path = Filehandler.getTestExtraFilesPath(projectId);
Filehandler.saveFile(path, file, Filehandler.EXTRA_TESTFILES_FILENAME);

FileEntity fileEntity = new FileEntity();
fileEntity.setName(file.getOriginalFilename());
fileEntity.setPath(path.resolve(Filehandler.EXTRA_TESTFILES_FILENAME).toString());
fileEntity.setUploadedBy(auth.getUserEntity().getId());
fileEntity = fileRepository.save(fileEntity);

testEntity.setExtraFilesId(fileEntity.getId());
testEntity = testRepository.save(testEntity);

return ResponseEntity.ok(entityToJsonConverter.testEntityToTestJson(testEntity, projectId));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error while saving files");
}
}

@DeleteMapping(ApiRoutes.PROJECT_BASE_PATH + "/{projectid}/tests/extrafiles")
@Roles({UserRole.teacher, UserRole.student})
public ResponseEntity<?> deleteExtraTestFiles(
@PathVariable("projectid") long projectId,
Auth auth
) {
CheckResult<TestEntity> checkResult = testUtil.getTestIfAdmin(projectId, auth.getUserEntity());
if (!checkResult.getStatus().equals(HttpStatus.OK)) {
return ResponseEntity.status(checkResult.getStatus()).body(checkResult.getMessage());
}

TestEntity testEntity = checkResult.getData();

try {

FileEntity fileEntity = testEntity.getExtraFilesId() == null ?
null : fileRepository.findById(testEntity.getExtraFilesId()).orElse(null);
if (fileEntity == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("No extra files found");
}

testEntity.setExtraFilesId(null);
testEntity = testRepository.save(testEntity);

CheckResult<Void> delResult = fileUtil.deleteFileById(fileEntity.getId());
if (!delResult.getStatus().equals(HttpStatus.OK)) {
return ResponseEntity.status(delResult.getStatus()).body(delResult.getMessage());
}

return ResponseEntity.ok(entityToJsonConverter.testEntityToTestJson(testEntity, projectId));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error while deleting files");
}
}

@GetMapping(ApiRoutes.PROJECT_BASE_PATH + "/{projectid}/tests/extrafiles")
@Roles({UserRole.teacher, UserRole.student})
public ResponseEntity<?> getExtraTestFiles(
@PathVariable("projectid") long projectId,
Auth auth
) {
CheckResult<TestEntity> checkResult = testUtil.getTestIfAdmin(projectId, auth.getUserEntity());
if (!checkResult.getStatus().equals(HttpStatus.OK)) {
return ResponseEntity.status(checkResult.getStatus()).body(checkResult.getMessage());
}

TestEntity testEntity = checkResult.getData();
if (testEntity.getExtraFilesId() == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("No extra files found");
}

FileEntity fileEntity = fileRepository.findById(testEntity.getExtraFilesId()).orElse(null);
if (fileEntity == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("No extra files found");
}

return Filehandler.getZipFileAsResponse(Path.of(fileEntity.getPath()), fileEntity.getName());
}
}

Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
package com.ugent.pidgeon.model.json;

public class TestJson {

private String projectUrl;
private String dockerImage;
private String dockerScript;
private String dockerTemplate;
private String structureTest;
private String extraFilesUrl;
private String extraFilesName;


public TestJson() {
}

public TestJson(String projectUrl, String dockerImage, String dockerScript,
String dockerTemplate, String structureTest) {
String dockerTemplate, String structureTest, String extraFilesUrl, String extraFilesName) {
this.projectUrl = projectUrl;
this.dockerImage = dockerImage;
this.dockerScript = dockerScript;
this.dockerTemplate = dockerTemplate;
this.structureTest = structureTest;
this.dockerTemplate = dockerTemplate;
this.structureTest = structureTest;
this.extraFilesUrl = extraFilesUrl;
this.extraFilesName = extraFilesName;
}

public String getProjectUrl() {
Expand Down Expand Up @@ -58,4 +64,20 @@ public String getDockerTemplate() {
public void setDockerTemplate(String dockerTemplate) {
this.dockerTemplate = dockerTemplate;
}

public String getExtraFilesUrl() {
return extraFilesUrl;
}

public void setExtraFilesUrl(String extraFilesUrl) {
this.extraFilesUrl = extraFilesUrl;
}

public String getExtraFilesName() {
return extraFilesName;
}

public void setExtraFilesName(String extraFilesName) {
this.extraFilesName = extraFilesName;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
Expand Down Expand Up @@ -56,6 +57,7 @@ public DockerSubmissionTestModel(String dockerImage) {
new File(localMountFolder + "input/").mkdirs();
new File(localMountFolder + "output/").mkdirs();
new File(localMountFolder + "artifacts/").mkdirs();
new File(localMountFolder + "extra/").mkdirs();
}


Expand Down Expand Up @@ -86,6 +88,33 @@ public void addInputFiles(File[] files) {
}
}

public void addUtilFiles(Path pathToZip){
// first unzip files to the utils folder
try {
ZipFile zipFile = new ZipFile(pathToZip.toFile());
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
File entryDestination = new File(localMountFolder + "extra/", entry.getName());
if (entry.isDirectory()) {
entryDestination.mkdirs();
} else {
File parent = entryDestination.getParentFile();
if (parent != null) {
parent.mkdirs();
}
try {
FileUtils.copyInputStreamToFile(zipFile.getInputStream(entry), entryDestination);
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}

public void addZipInputFiles(ZipFile zipFile) {
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ public class TestEntity {
@Column(name = "structure_template")
private String structureTemplate;

@Column(name = "extra_files")
private Long extraFilesId;

public TestEntity(String dockerImage, String docker_test_script,
String dockerTestTemplate,
String structureTemplate) {
Expand Down Expand Up @@ -76,4 +79,12 @@ public String getStructureTemplate() {
public void setStructureTemplate(String structureTemplate) {
this.structureTemplate = structureTemplate;
}

public Long getExtraFilesId() {
return extraFilesId;
}

public void setExtraFilesId(Long extraFilesId) {
this.extraFilesId = extraFilesId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public class EntityToJsonConverter {
private TestUtil testUtil;
@Autowired
private TestRepository testRepository;
@Autowired
private FileRepository fileRepository;


public GroupJson groupEntityToJson(GroupEntity groupEntity, boolean hideStudentNumber) {
Expand Down Expand Up @@ -267,12 +269,15 @@ else if (submission.getDockerTestType().equals(DockerTestType.SIMPLE)) {
}

public TestJson testEntityToTestJson(TestEntity testEntity, long projectId) {
FileEntity extrafiles = testEntity.getExtraFilesId() == null ? null : fileRepository.findById(testEntity.getExtraFilesId()).orElse(null);
return new TestJson(
ApiRoutes.PROJECT_BASE_PATH + "/" + projectId,
testEntity.getDockerImage(),
testEntity.getDockerTestScript(),
testEntity.getDockerTestTemplate(),
testEntity.getStructureTemplate()
testEntity.getStructureTemplate(),
testEntity.getExtraFilesId() == null ? null : ApiRoutes.PROJECT_BASE_PATH + "/" + projectId + "/tests/extrafiles",
extrafiles == null ? null : extrafiles.getName()
);
}
}
29 changes: 27 additions & 2 deletions backend/app/src/main/java/com/ugent/pidgeon/util/Filehandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import java.util.zip.ZipOutputStream;
import org.apache.tika.Tika;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.core.io.Resource;

Expand All @@ -18,6 +21,7 @@ public class Filehandler {

static String BASEPATH = "data";
public static String SUBMISSION_FILENAME = "files.zip";
public static String EXTRA_TESTFILES_FILENAME = "testfiles.zip";
public static String ADMIN_SUBMISSION_FOLDER = "adminsubmissions";

/**
Expand All @@ -27,7 +31,7 @@ public class Filehandler {
* @return the saved file
* @throws IOException if an error occurs while saving the file
*/
public static File saveSubmission(Path directory, MultipartFile file) throws IOException {
public static File saveFile(Path directory, MultipartFile file, String filename) throws IOException {
// Check if the file is empty
if (file == null || file.isEmpty()) {
throw new IOException("File is empty");
Expand All @@ -51,7 +55,7 @@ public static File saveSubmission(Path directory, MultipartFile file) throws IOE
}

// Save the file to the server
Path filePath = directory.resolve(SUBMISSION_FILENAME);
Path filePath = directory.resolve(filename);

try(InputStream stream = new FileInputStream(tempFile)) {
Files.copy(stream, filePath, StandardCopyOption.REPLACE_EXISTING);
Expand Down Expand Up @@ -121,6 +125,10 @@ static public Path getSubmissionArtifactPath(long projectid, Long groupid, long
return getSubmissionPath(projectid, groupid, submissionid).resolve("artifacts.zip");
}

static public Path getTestExtraFilesPath(long projectid) {
return Path.of(BASEPATH,"projects", String.valueOf(projectid));
}

/**
* Get a file as a resource
* @param path path of the file
Expand Down Expand Up @@ -188,4 +196,21 @@ public static void copyFilesAsZip(List<File> files, Path path) throws IOExceptio
}
}
}

public static ResponseEntity<?> getZipFileAsResponse(Path path, String filename) {
// Get the file from the server
Resource zipFile = Filehandler.getFileAsResource(path);
if (zipFile == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("File not found.");
}

// Set headers for the response
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename);
headers.add(HttpHeaders.CONTENT_TYPE, "application/zip");

return ResponseEntity.ok()
.headers(headers)
.body(zipFile);
}
}
Loading

0 comments on commit 4516f6b

Please sign in to comment.