diff --git a/src/main/java/fr/univ_lille/gitlab/classrooms/assignments/AssignmentService.java b/src/main/java/fr/univ_lille/gitlab/classrooms/assignments/AssignmentService.java index 60c8455..d13303b 100644 --- a/src/main/java/fr/univ_lille/gitlab/classrooms/assignments/AssignmentService.java +++ b/src/main/java/fr/univ_lille/gitlab/classrooms/assignments/AssignmentService.java @@ -13,6 +13,8 @@ import java.util.UUID; public interface AssignmentService { Optional getAssignment(UUID id); + void archive(Assignment assignment); + @Transactional void acceptAssigment(Assignment assignment, ClassroomUser student) throws GitLabApiException, GitLabException; diff --git a/src/main/java/fr/univ_lille/gitlab/classrooms/assignments/AssignmentServiceImpl.java b/src/main/java/fr/univ_lille/gitlab/classrooms/assignments/AssignmentServiceImpl.java index 39f9426..0537dc0 100644 --- a/src/main/java/fr/univ_lille/gitlab/classrooms/assignments/AssignmentServiceImpl.java +++ b/src/main/java/fr/univ_lille/gitlab/classrooms/assignments/AssignmentServiceImpl.java @@ -45,6 +45,20 @@ class AssignmentServiceImpl implements AssignmentService { return this.assignmentRepository.findById(id); } + @Override + public void archive(Assignment assignment){ + var studentAssignments = this.studentAssignmentRepository.findAllByAssignment(assignment); + studentAssignments.stream() + .map(it -> (StudentExerciseAssignment)it) + .forEach(studentExerciseAssignment -> { + try { + this.gitlab.archiveProject(studentExerciseAssignment); + } catch (GitLabException e) { + System.out.println(e.getMessage()); + } + }); + } + @Override @Transactional public void acceptAssigment(Assignment assignment, ClassroomUser student) throws GitLabApiException, GitLabException { diff --git a/src/main/java/fr/univ_lille/gitlab/classrooms/assignments/ExerciseAssignmentRestController.java b/src/main/java/fr/univ_lille/gitlab/classrooms/assignments/ExerciseAssignmentRestController.java new file mode 100644 index 0000000..bfd8819 --- /dev/null +++ b/src/main/java/fr/univ_lille/gitlab/classrooms/assignments/ExerciseAssignmentRestController.java @@ -0,0 +1,62 @@ +package fr.univ_lille.gitlab.classrooms.assignments; + +import jakarta.annotation.security.RolesAllowed; +import org.gitlab4j.api.GitLabApi; +import org.gitlab4j.api.GitLabApiException; +import org.gitlab4j.api.models.Project; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.server.ResponseStatusException; + +import java.util.UUID; +import java.util.stream.Collectors; + +@Controller +@RolesAllowed("TEACHER") +public class ExerciseAssignmentRestController { + + private AssignmentService assignmentService; + + private GitLabApi gitlab; + + public ExerciseAssignmentRestController(AssignmentService assignmentService, GitLabApi gitlab) { + this.assignmentService = assignmentService; + this.gitlab = gitlab; + } + + @GetMapping(value = "/assignments/{id}/clone-script", produces = "text/plain") + @ResponseBody + String buildGitlabCloneScript(@PathVariable UUID id) { + var assignment = this.assignmentService.getAssignment(id).orElseThrow(); + + var studentAssignments = this.assignmentService.getAssignmentResults(assignment); + + var urls = studentAssignments.stream() + .map(it -> (StudentExerciseAssignment) it) + .map(StudentExerciseAssignment::getGitlabProjectId) + .map(it -> { + try { + return gitlab.getProjectApi().getProject(it); + } catch (GitLabApiException e) { + throw new RuntimeException(e); + } + }) + .map(Project::getSshUrlToRepo) + .map(it -> "git clone " + it); + + return urls.collect(Collectors.joining("\n")); + } + + @GetMapping("/assignments/{assignmentId}/archive") + String archiveAssignment(@PathVariable UUID assignmentId, Model model) { + var assignment = this.assignmentService.getAssignment(assignmentId).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND)); + this.assignmentService.archive(assignment); + + return "redirect:/classrooms/" + assignment.getClassroom().getId(); + } + +} diff --git a/src/main/java/fr/univ_lille/gitlab/classrooms/gitlab/Gitlab.java b/src/main/java/fr/univ_lille/gitlab/classrooms/gitlab/Gitlab.java index 82815d7..0220259 100644 --- a/src/main/java/fr/univ_lille/gitlab/classrooms/gitlab/Gitlab.java +++ b/src/main/java/fr/univ_lille/gitlab/classrooms/gitlab/Gitlab.java @@ -1,6 +1,7 @@ package fr.univ_lille.gitlab.classrooms.gitlab; import fr.univ_lille.gitlab.classrooms.assignments.ExerciseAssignment; +import fr.univ_lille.gitlab.classrooms.assignments.StudentExerciseAssignment; import fr.univ_lille.gitlab.classrooms.classrooms.Classroom; import fr.univ_lille.gitlab.classrooms.users.ClassroomUser; import org.gitlab4j.api.GitLabApiException; @@ -46,4 +47,5 @@ public interface Gitlab { */ Project createStudentProject(ExerciseAssignment exerciseAssignment, ClassroomUser student) throws GitLabApiException, GitLabException; + void archiveProject(StudentExerciseAssignment studentExerciseAssignment) throws GitLabException; } diff --git a/src/main/java/fr/univ_lille/gitlab/classrooms/gitlab/GitlabImpl.java b/src/main/java/fr/univ_lille/gitlab/classrooms/gitlab/GitlabImpl.java index 243be92..c162f61 100644 --- a/src/main/java/fr/univ_lille/gitlab/classrooms/gitlab/GitlabImpl.java +++ b/src/main/java/fr/univ_lille/gitlab/classrooms/gitlab/GitlabImpl.java @@ -1,6 +1,7 @@ package fr.univ_lille.gitlab.classrooms.gitlab; import fr.univ_lille.gitlab.classrooms.assignments.ExerciseAssignment; +import fr.univ_lille.gitlab.classrooms.assignments.StudentExerciseAssignment; import fr.univ_lille.gitlab.classrooms.classrooms.Classroom; import fr.univ_lille.gitlab.classrooms.users.ClassroomUser; import org.gitlab4j.api.GitLabApi; @@ -115,6 +116,17 @@ class GitlabImpl implements Gitlab { return project; } + @Override + public void archiveProject(StudentExerciseAssignment studentExerciseAssignment) throws GitLabException { + var projectId = studentExerciseAssignment.getGitlabProjectId(); + + try { + this.gitLabApi.getProjectApi().archiveProject(projectId); + } catch (GitLabApiException e) { + throw new GitLabException("Unable to archive GitLab project with id '%s'".formatted(projectId), e); + } + } + private Project ensureStudentProjectExists(GitLabApi teacherGitlabApi, ExerciseAssignment exerciseAssignment, ClassroomUser student) throws GitLabException { var groupId = exerciseAssignment.getGitlabGroupId(); var group = teacherGitlabApi.getGroupApi().getOptionalGroup(groupId).orElseThrow(() -> new GitLabException("Group with id %s doest not exists".formatted(groupId))); diff --git a/src/main/java/fr/univ_lille/gitlab/classrooms/security/GitlabIDTokenSecurityConfiguration.java b/src/main/java/fr/univ_lille/gitlab/classrooms/security/GitlabIDTokenSecurityConfiguration.java index 5d735df..20dda24 100644 --- a/src/main/java/fr/univ_lille/gitlab/classrooms/security/GitlabIDTokenSecurityConfiguration.java +++ b/src/main/java/fr/univ_lille/gitlab/classrooms/security/GitlabIDTokenSecurityConfiguration.java @@ -21,4 +21,12 @@ public class GitlabIDTokenSecurityConfiguration { .build(); } + @Bean + SecurityFilterChain apiKeyFilterChain(HttpSecurity http) throws Exception { + return http + .securityMatcher("/api/**") + .authorizeHttpRequests(authorize -> authorize.requestMatchers("/api/**").authenticated()) + .build(); + } + }