-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #50 from SELab-2/feature/project_routes
Feature/project routes
- Loading branch information
Showing
38 changed files
with
734 additions
and
105 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,3 +35,4 @@ out/ | |
|
||
### VS Code ### | ||
.vscode/ | ||
backend/app/data/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 14 additions & 0 deletions
14
backend/app/src/main/java/com/ugent/pidgeon/auth/Roles.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package com.ugent.pidgeon.auth; | ||
|
||
import com.ugent.pidgeon.postgre.models.types.UserRole; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
@Target(ElementType.METHOD) | ||
@Retention(RetentionPolicy.RUNTIME) | ||
public @interface Roles { | ||
UserRole[] value(); | ||
} |
58 changes: 58 additions & 0 deletions
58
backend/app/src/main/java/com/ugent/pidgeon/auth/RolesInterceptor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package com.ugent.pidgeon.auth; | ||
|
||
|
||
import com.ugent.pidgeon.model.Auth; | ||
import com.ugent.pidgeon.postgre.models.UserEntity; | ||
import com.ugent.pidgeon.postgre.models.types.UserRole; | ||
import com.ugent.pidgeon.postgre.repository.UserRepository; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.security.core.context.SecurityContextHolder; | ||
import org.springframework.stereotype.Component; | ||
import org.springframework.web.method.HandlerMethod; | ||
import org.springframework.web.servlet.HandlerInterceptor; | ||
|
||
import java.sql.Timestamp; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
@Component | ||
public class RolesInterceptor implements HandlerInterceptor { | ||
|
||
|
||
private final UserRepository userRepository; | ||
|
||
@Autowired | ||
public RolesInterceptor(UserRepository userRepository) { | ||
this.userRepository = userRepository; | ||
} | ||
|
||
|
||
@Override | ||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { | ||
if (handler instanceof HandlerMethod handlerMethod) { | ||
Roles rolesAnnotation = handlerMethod.getMethodAnnotation(Roles.class); | ||
if (rolesAnnotation != null) { | ||
List<UserRole> requiredRoles = Arrays.asList(rolesAnnotation.value()); | ||
Auth auth = (Auth) SecurityContextHolder.getContext().getAuthentication(); | ||
UserEntity userEntity = userRepository.findUserByAzureId(auth.getOid()); | ||
|
||
if(userEntity == null) { | ||
System.out.println("User does not exist, creating new one"); | ||
userEntity = new UserEntity(auth.getUser().firstName,auth.getUser().lastName, auth.getEmail(), UserRole.student, auth.getOid()); | ||
Timestamp now = new Timestamp(System.currentTimeMillis()); | ||
userEntity.setCreatedAt(now); | ||
userRepository.save(userEntity); | ||
} | ||
auth.setUserEntity(userEntity); | ||
|
||
if (!requiredRoles.contains(userEntity.getRole()) || userEntity.getRole() == UserRole.admin) { | ||
response.sendError(HttpServletResponse.SC_FORBIDDEN, "User does not have required role"); | ||
return false; | ||
} | ||
} | ||
} | ||
return true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 17 additions & 1 deletion
18
backend/app/src/main/java/com/ugent/pidgeon/config/WebConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,34 @@ | ||
package com.ugent.pidgeon.config; | ||
|
||
import com.ugent.pidgeon.auth.RolesInterceptor; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.web.servlet.config.annotation.CorsRegistry; | ||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; | ||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; | ||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | ||
|
||
@Configuration | ||
public class WebConfig implements WebMvcConfigurer { | ||
|
||
|
||
private final RolesInterceptor rolesInterceptor; | ||
|
||
@Autowired | ||
public WebConfig(RolesInterceptor rolesInterceptor) { | ||
this.rolesInterceptor = rolesInterceptor; | ||
} | ||
|
||
@Override | ||
public void addCorsMappings(CorsRegistry registry) { | ||
registry.addMapping("/**") | ||
.allowedMethods("*") | ||
.allowedOrigins("*") | ||
.allowedHeaders("*"); | ||
} | ||
|
||
|
||
@Override | ||
public void addInterceptors(InterceptorRegistry registry) { | ||
registry.addInterceptor(rolesInterceptor); | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
backend/app/src/main/java/com/ugent/pidgeon/controllers/ApiRoutes.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.ugent.pidgeon.controllers; | ||
|
||
public final class ApiRoutes { | ||
public static final String USER_BASE_PATH = "/api/users"; | ||
public static final String COURSE_BASE_PATH = "/api/courses"; | ||
|
||
public static final String PROJECT_BASE_PATH = "/api/projects"; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
52 changes: 52 additions & 0 deletions
52
backend/app/src/main/java/com/ugent/pidgeon/controllers/CourseController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package com.ugent.pidgeon.controllers; | ||
|
||
import com.ugent.pidgeon.auth.Roles; | ||
import com.ugent.pidgeon.postgre.models.CourseEntity; | ||
import com.ugent.pidgeon.postgre.models.ProjectEntity; | ||
import com.ugent.pidgeon.postgre.models.types.UserRole; | ||
import com.ugent.pidgeon.postgre.repository.CourseRepository; | ||
import com.ugent.pidgeon.postgre.repository.ProjectRepository; | ||
import com.ugent.pidgeon.postgre.repository.TestRepository; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.PathVariable; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
@RestController | ||
public class CourseController { | ||
|
||
@Autowired | ||
private CourseRepository courseRepository; | ||
|
||
@Autowired | ||
private ProjectRepository projectRepository; | ||
|
||
@Autowired | ||
private TestRepository testRepository; | ||
|
||
@GetMapping(ApiRoutes.COURSE_BASE_PATH + "/{courseId}") | ||
@Roles({UserRole.teacher, UserRole.student}) | ||
public ResponseEntity<CourseEntity> getCourseByCourseId(@PathVariable Long courseId) { | ||
Optional<CourseEntity> courseopt = courseRepository.findById(courseId); | ||
if (courseopt.isEmpty()) { | ||
return ResponseEntity.notFound().build(); // Or return an empty list, based on your preference | ||
} | ||
CourseEntity course = courseopt.get(); | ||
return ResponseEntity.ok(course); | ||
} | ||
|
||
@GetMapping(ApiRoutes.COURSE_BASE_PATH + "/{courseId}/projects") | ||
@Roles({UserRole.teacher, UserRole.student}) | ||
public ResponseEntity<List<ProjectEntity>> getProjectByCourseId(@PathVariable Long courseId) { | ||
List<ProjectEntity> projects = projectRepository.findByCourseId(courseId); | ||
if (projects.isEmpty()) { | ||
return ResponseEntity.notFound().build(); | ||
} | ||
return ResponseEntity.ok(projects); | ||
} | ||
|
||
} |
109 changes: 109 additions & 0 deletions
109
backend/app/src/main/java/com/ugent/pidgeon/controllers/FilesubmissiontestController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package com.ugent.pidgeon.controllers; | ||
|
||
import com.ugent.pidgeon.auth.Roles; | ||
import com.ugent.pidgeon.model.Auth; | ||
import com.ugent.pidgeon.postgre.models.FileEntity; | ||
import com.ugent.pidgeon.postgre.models.SubmissionEntity; | ||
import com.ugent.pidgeon.postgre.models.types.UserRole; | ||
import com.ugent.pidgeon.postgre.repository.FileRepository; | ||
import com.ugent.pidgeon.postgre.repository.GroupRepository; | ||
import com.ugent.pidgeon.postgre.repository.ProjectRepository; | ||
import com.ugent.pidgeon.postgre.repository.SubmissionRepository; | ||
import com.ugent.pidgeon.util.Filehandler; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.core.io.Resource; | ||
import org.springframework.http.HttpHeaders; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.*; | ||
import org.springframework.web.multipart.MultipartFile; | ||
|
||
import java.nio.file.Path; | ||
import java.sql.Timestamp; | ||
|
||
@RestController | ||
public class FilesubmissiontestController { | ||
|
||
@Autowired | ||
private GroupRepository groupRepository; | ||
@Autowired | ||
private FileRepository fileRepository; | ||
@Autowired | ||
private SubmissionRepository submissionRepository; | ||
@Autowired | ||
private ProjectRepository projectRepository; | ||
|
||
@PostMapping("/project/{projectid}/submit") //Route to submit a file, it accepts a multiform with the file and submissionTime | ||
@Roles({UserRole.teacher, UserRole.student}) | ||
public ResponseEntity<String> submitFile(@RequestParam("file") MultipartFile file, @RequestParam("submissionTime") Timestamp time, @PathVariable("projectid") long projectid,Auth auth) { | ||
long userId = auth.getUserEntity().getId(); | ||
Long groupId = groupRepository.groupIdByProjectAndUser(projectid, userId); | ||
|
||
if (!projectRepository.userPartOfProject(projectid, userId)) { | ||
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("You aren't part of this project"); | ||
} | ||
//TODO: executes the tests onces these are implemented | ||
try { | ||
//Save the file entry in the database to get the id | ||
FileEntity fileEntity = new FileEntity("", "", userId); | ||
long fileid = fileRepository.save(fileEntity).getId(); | ||
|
||
//Save the submission in the database TODO: update the accepted parameter | ||
SubmissionEntity submissionEntity = new SubmissionEntity(projectid, groupId, fileid, time, false); | ||
SubmissionEntity submission = submissionRepository.save(submissionEntity); | ||
|
||
//Save the file on the server | ||
Path path = Filehandler.getSubmissionPath(projectid, groupId, submission.getId()); | ||
String filename = Filehandler.saveSubmission(path, file); | ||
|
||
//Update name and path for the file entry | ||
fileEntity.setName(filename); | ||
fileEntity.setPath(path.toString()); | ||
fileRepository.save(fileEntity); | ||
|
||
return ResponseEntity.ok("File saved"); | ||
} catch (Exception e) { | ||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error while saving file: " + e.getMessage()); | ||
} | ||
|
||
} | ||
|
||
@GetMapping("submissions/{submissionid}") | ||
@Roles({UserRole.teacher, UserRole.student}) | ||
public ResponseEntity<Resource> getSubmission(@PathVariable("submissionid") long submissionid, Auth auth) { | ||
long userId = auth.getUserEntity().getId(); | ||
// Get the submission entry from the database | ||
SubmissionEntity submission = submissionRepository.findById(submissionid).orElse(null); | ||
if (submission == null) { | ||
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null); | ||
} | ||
|
||
if (!groupRepository.userInGroup(submission.getGroupId(), userId)) { | ||
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(null); | ||
} | ||
// Get the file entry from the database | ||
FileEntity file = fileRepository.findById(submission.getFileId()).orElse(null); | ||
if (file == null) { | ||
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null); | ||
} | ||
|
||
|
||
// Get the file from the server | ||
try { | ||
Resource zipFile = Filehandler.getSubmissionAsResource(Path.of(file.getPath(), file.getName())); | ||
|
||
// 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) | ||
.contentType(MediaType.APPLICATION_OCTET_STREAM) | ||
.body(zipFile); | ||
} catch (Exception e) { | ||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.