Skip to content
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
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<dependency>
<groupId>edu.kit.kastel.sdq</groupId>
<artifactId>artemis4j</artifactId>
<version>7.10.1</version>
<version>8.5.0</version>
</dependency>
<dependency>
<groupId>info.picocli</groupId>
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/edu/kit/kastel/artemiscli/ArtemisUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public static ProgrammingExercise findExercise(Course course, String name) throw
List<String> availableExercises = new ArrayList<>();

for (var exercise : allProgrammingExercises(course).toList()) {
if (List.of(exercise.getShortName(), exercise.getTitle()).contains(name)) {
if (List.of(exercise.getShortName(), exercise.getTitle(), "" + exercise.getId()).contains(name.toLowerCase())) {
return exercise;
}
availableExercises.add(exercise.getShortName());
Expand Down
26 changes: 19 additions & 7 deletions src/main/java/edu/kit/kastel/artemiscli/CloneCommand.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package edu.kit.kastel.artemiscli;

import edu.kit.kastel.sdq.artemis4j.ArtemisClientException;
import edu.kit.kastel.sdq.artemis4j.grading.ClonedProgrammingSubmission;
import edu.kit.kastel.sdq.artemis4j.grading.ProgrammingExercise;
import edu.kit.kastel.sdq.artemis4j.grading.ProgrammingSubmission;
import edu.kit.kastel.sdq.artemis4j.grading.ProgrammingSubmissionWithResults;
import org.eclipse.jgit.dircache.InvalidPathException;
import picocli.CommandLine;

import java.nio.file.Path;
Expand Down Expand Up @@ -65,19 +66,30 @@ public void execute() throws Exception {
}

private static void cloneSubmissions(ProgrammingExercise exercise, Path outputFolder, Predicate<? super ProgrammingSubmission> shouldClone) throws ArtemisClientException {
List<ProgrammingSubmission> submissions = exercise.fetchSubmissions(0, false);
List<ProgrammingSubmissionWithResults> submissions = exercise.fetchAllSubmissions();
System.out.println("Found " + submissions.size() + " submissions");

for (ProgrammingSubmission submission : submissions) {
if (!shouldClone.test(submission)) {
for (ProgrammingSubmissionWithResults submission : submissions) {
var actualSubmission = submission.getSubmission();
if (!shouldClone.test(actualSubmission)) {
continue;
}

System.out.println("Submission " + submission.getId() + " is from " + submission.getRepositoryUrl());
Path output = Path.of(outputFolder.toString(), extractFolderName(submission.getRepositoryUrl()));
System.out.println("Submission " + actualSubmission.getId() + " is from " + actualSubmission.getRepositoryUrl());
Path output = Path.of(outputFolder.toString(), extractFolderName(actualSubmission.getRepositoryUrl()));

if (output.toFile().exists()) {
System.out.println("Warning: The folder " + output + " already exists, skipping submission " + actualSubmission.getId());
continue;
}

// ignore the submission/do not close it, otherwise the folder will be deleted
ClonedProgrammingSubmission _cloned = submission.cloneViaVCSTokenInto(output, null);
try {
actualSubmission.cloneViaVCSTokenInto(output, null);
} catch (InvalidPathException e) {
// This happens when an invalid filename like `CON` on Windows is used
System.out.println("Error: Could not clone submission " + actualSubmission.getId() + " into " + output + ": " + e.getMessage());
}
}
}

Expand Down
41 changes: 20 additions & 21 deletions src/main/java/edu/kit/kastel/artemiscli/ListLocksCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@
import edu.kit.kastel.sdq.artemis4j.client.GenericSubmissionDTO;
import edu.kit.kastel.sdq.artemis4j.grading.Course;
import edu.kit.kastel.sdq.artemis4j.grading.ProgrammingExercise;
import edu.kit.kastel.sdq.artemis4j.grading.ProgrammingSubmission;
import edu.kit.kastel.sdq.artemis4j.grading.ProgrammingSubmissionWithResults;
import picocli.CommandLine;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
Expand All @@ -34,49 +33,49 @@ public void execute() throws Exception {

for (ProgrammingExercise exercise : exercises) {
for (var submission : listLockedSubmissions(this.parent.course(), exercise)) {
if (submission.getFirstRoundAssessment() == null) {
throw new IllegalStateException(
"Submission %s is locked, but has no first round assessment.".formatted(submission.getSubmission().getId())
);
}

System.out.printf(
"The submission by %s with the id %s is currently locked by %s.%n",
submission.getStudent().map(Object::toString).orElse("???"),
submission.getId(),
submission.getAssessor().map(Object::toString).orElse("???")
submission.getSubmission().getStudent().map(Object::toString).orElse("???"),
submission.getSubmission().getId(),
submission.getFirstRoundAssessment().getAssessor()
);
}
}
}

static List<ProgrammingSubmission> listLockedSubmissions(Course course, ProgrammingExercise exercise) throws ArtemisNetworkException {
static List<ProgrammingSubmissionWithResults> listLockedSubmissions(Course course, ProgrammingExercise exercise) throws ArtemisNetworkException {
Set<Long> allLockedSubmissions = CourseDTO.fetchLockedSubmissions(course.getConnection().getClient(), course.getId())
.stream()
.map(GenericSubmissionDTO::id)
.collect(Collectors.toSet());
.stream()
.map(GenericSubmissionDTO::id)
.collect(Collectors.toSet());

if (allLockedSubmissions.isEmpty()) {
return List.of();
}

if (exercise != null) {
List<ProgrammingSubmission> allSubmissions = exercise.fetchSubmissions(0, false);
if (exercise.hasSecondCorrectionRound()) {
allSubmissions.addAll(exercise.fetchSubmissions(1, false));
}
List<ProgrammingSubmissionWithResults> allSubmissions = exercise.fetchAllSubmissions();


return allSubmissions.stream()
.filter(submission -> allLockedSubmissions.contains(submission.getId()))
.toList();
.filter(submission -> allLockedSubmissions.contains(submission.getSubmission().getId()))
.toList();
}

List<ProgrammingSubmission> result = new ArrayList<>();
List<ProgrammingSubmissionWithResults> result = new ArrayList<>();
Deque<ProgrammingExercise> exercises = new LinkedList<>(course.getProgrammingExercises());
while (!allLockedSubmissions.isEmpty() && !exercises.isEmpty()) {
ProgrammingExercise currentExercise = exercises.removeLast();
Collection<ProgrammingSubmission> submissions = new ArrayList<>(currentExercise.fetchSubmissions(0, false));
if (currentExercise.hasSecondCorrectionRound()) {
submissions.addAll(currentExercise.fetchSubmissions(1, false));
}
List<ProgrammingSubmissionWithResults> submissions = currentExercise.fetchAllSubmissions();

for (var submission : submissions) {
if (allLockedSubmissions.remove(submission.getId())) {
if (allLockedSubmissions.remove(submission.getSubmission().getId())) {
result.add(submission);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/edu/kit/kastel/artemiscli/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public final class Main implements Runnable{
CommandLine.Model.CommandSpec specification;

@CommandLine.Option(names = {"--url"}, description = "The URL of the Artemis instance. Note that the https:// prefix is required.")
private String artemisUrl = "https://artemis.praktomat.cs.kit.edu/";
private String artemisUrl = "https://artemis.cs.kit.edu/";
//private String artemisUrl = "https://artemis-test.sdq.kastel.kit.edu/";

@CommandLine.Option(names = {"--username"}, description = "The username to use for authentication.", required = true)
Expand Down
18 changes: 10 additions & 8 deletions src/main/java/edu/kit/kastel/artemiscli/ShowRepositoryCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
import java.util.List;

@CommandLine.Command(name = "show", mixinStandardHelpOptions = true,
description = "Shows the repository urls of the given submissions.")
description = "Shows the repository urls of the given submissions.")
public class ShowRepositoryCommand implements Command {
private static final String REPOSITORY_URL = "https://artemis.praktomat.cs.kit.edu/courses/%d/exercises/%d/repository/%d";
private static final String REPOSITORY_URL = "https://artemis.cs.kit.edu/courses/%d/exercises/%d/repository/%d";

@CommandLine.Spec
private CommandLine.Model.CommandSpec specification;
Expand All @@ -31,16 +31,18 @@ public void execute() throws Exception {
}

Collection<String> remainingIds = new LinkedHashSet<>(List.of(this.submissionIds));
outer: for (var exercise : ArtemisUtil.listAllApplyingExercises(this.parent.course(), this.exerciseName)) {
for (var submission : exercise.fetchSubmissions(0, false)) {
outer:
for (var exercise : ArtemisUtil.listAllApplyingExercises(this.parent.course(), this.exerciseName)) {
for (var submission : exercise.fetchAllSubmissions()) {
var actualSubmission = submission.getSubmission();
if (remainingIds.isEmpty()) {
break outer;
}

if (remainingIds.remove("" + submission.getId()) || submission.getStudent().isPresent() && remainingIds.contains(submission.getStudent().get().toString())) {
String prefix = "[%s][%s][%s]:".formatted(exercise.getTitle(), submission.getId(), submission.getStudent().get().toString());
System.out.printf("%s git url to clone: %s%n".formatted(prefix, submission.getRepositoryUrl()));
System.out.printf("%s artemis url: %s%n".formatted(" ".repeat(prefix.length()), REPOSITORY_URL.formatted(this.parent.course().getId(), exercise.getId(), submission.getParticipationId())));
if (remainingIds.remove("" + actualSubmission.getId()) || actualSubmission.getStudent().isPresent() && remainingIds.contains(actualSubmission.getStudent().get().toString())) {
String prefix = "[%s][%s][%s]:".formatted(exercise.getTitle(), actualSubmission.getId(), actualSubmission.getStudent().get().toString());
System.out.printf("%s git url to clone: %s%n".formatted(prefix, actualSubmission.getRepositoryUrl()));
System.out.printf("%s artemis url: %s%n".formatted(" ".repeat(prefix.length()), REPOSITORY_URL.formatted(this.parent.course().getId(), exercise.getId(), actualSubmission.getParticipationId())));
}
}
}
Expand Down
19 changes: 10 additions & 9 deletions src/main/java/edu/kit/kastel/artemiscli/UnlockCommand.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package edu.kit.kastel.artemiscli;

import edu.kit.kastel.sdq.artemis4j.ArtemisNetworkException;
import edu.kit.kastel.sdq.artemis4j.client.ArtemisClient;
import edu.kit.kastel.sdq.artemis4j.client.ProgrammingSubmissionDTO;
import edu.kit.kastel.sdq.artemis4j.grading.ProgrammingSubmission;
import edu.kit.kastel.sdq.artemis4j.grading.ProgrammingSubmissionWithResults;
import picocli.CommandLine;

import java.util.ArrayList;
Expand Down Expand Up @@ -41,12 +42,12 @@ public void execute() throws Exception {
var exercises = ArtemisUtil.listAllApplyingExercises(this.parent.course(), this.exerciseName);

for (var exercise : exercises) {
List<ProgrammingSubmission> availableSubmissions = ListLocksCommand.listLockedSubmissions(this.parent.course(), exercise);
List<ProgrammingSubmissionWithResults> availableSubmissions = ListLocksCommand.listLockedSubmissions(this.parent.course(), exercise);

Collection<ProgrammingSubmission> submissions = new ArrayList<>();
Collection<ProgrammingSubmissionWithResults> submissions = new ArrayList<>();
outer: for (long submissionId : this.submissionIds) {
for (var submission : availableSubmissions) {
if (submission.getId() == submissionId) {
if (submission.getSubmission().getId() == submissionId) {
submissions.add(submission);
continue outer;
}
Expand All @@ -60,17 +61,17 @@ public void execute() throws Exception {
}

for (var submission : submissions) {
unlock(submission);
System.out.println("Unlocked submission " + submission.getId());
unlock(this.parent.course().getConnection().getClient(), submission);
System.out.println("Unlocked submission " + submission.getSubmission().getId());
}
}
}

private static void unlock(ProgrammingSubmission submission) throws ArtemisNetworkException {
if (submission.isSubmitted()) {
private static void unlock(ArtemisClient client, ProgrammingSubmissionWithResults submission) throws ArtemisNetworkException {
if (submission.getFirstRoundAssessment().isSubmitted()) {
throw new IllegalStateException("Submission has already been submitted");
}

ProgrammingSubmissionDTO.cancelAssessment(submission.getConnection().getClient(), submission.getId());
ProgrammingSubmissionDTO.cancelAssessment(client, submission.getSubmission().getId());
}
}