Skip to content

Commit

Permalink
Update to new Artemis4J version
Browse files Browse the repository at this point in the history
  • Loading branch information
Luro02 committed Aug 13, 2024
1 parent 7300677 commit e0b3ee5
Show file tree
Hide file tree
Showing 40 changed files with 486 additions and 750 deletions.
16 changes: 13 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@
<spotless.version>2.43.0</spotless.version>
<junit.version>5.10.3</junit.version>
</properties>

<dependencies>
<dependency>
<groupId>edu.kit.kastel.sdq</groupId>
<groupId>com.github.Luro02</groupId>
<artifactId>artemis4j</artifactId>
<version>6.7.5</version>
<version>36c5157cd5</version>
</dependency>
<!--<dependency>
<groupId>edu.kit.kastel.sdq</groupId>
<artifactId>artemis4j</artifactId>
<version>7.4.0-SNAPSHOT</version>
</dependency>-->
<dependency>
<groupId>org.jcommander</groupId>
<artifactId>jcommander</artifactId>
Expand All @@ -45,6 +49,12 @@
<version>2.0.14</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>

<build>
<plugins>
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/edu/kit/kastel/sdq/scorestats/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import edu.kit.kastel.sdq.scorestats.cli.CLI;

public final class Application {
private Application() {
}

public static void main(String[] args) {
CLI cli = new CLI();
cli.run(args);
Expand Down
109 changes: 69 additions & 40 deletions src/main/java/edu/kit/kastel/sdq/scorestats/cli/CLI.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
Expand All @@ -14,21 +17,24 @@

import com.beust.jcommander.JCommander;
import com.beust.jcommander.ParameterException;
import edu.kit.kastel.sdq.artemis4j.api.ArtemisClientException;
import edu.kit.kastel.sdq.artemis4j.api.artemis.Course;
import edu.kit.kastel.sdq.artemis4j.api.artemis.Exercise;
import edu.kit.kastel.sdq.artemis4j.grading.config.ExerciseConfig;
import edu.kit.kastel.sdq.artemis4j.ArtemisClientException;
import edu.kit.kastel.sdq.artemis4j.ArtemisNetworkException;
import edu.kit.kastel.sdq.artemis4j.client.ArtemisInstance;
import edu.kit.kastel.sdq.artemis4j.grading.ArtemisConnection;
import edu.kit.kastel.sdq.artemis4j.grading.Assessment;
import edu.kit.kastel.sdq.artemis4j.grading.Course;
import edu.kit.kastel.sdq.artemis4j.grading.Exercise;
import edu.kit.kastel.sdq.artemis4j.grading.ProgrammingExercise;
import edu.kit.kastel.sdq.artemis4j.grading.ProgrammingSubmission;
import edu.kit.kastel.sdq.artemis4j.grading.metajson.AnnotationMappingException;
import edu.kit.kastel.sdq.artemis4j.grading.penalty.GradingConfig;
import edu.kit.kastel.sdq.artemis4j.grading.penalty.InvalidGradingConfigException;
import edu.kit.kastel.sdq.scorestats.cli.arguments.Arguments;
import edu.kit.kastel.sdq.scorestats.cli.dialogue.OptionDialogue;
import edu.kit.kastel.sdq.scorestats.cli.dialogue.OptionsDialogue;
import edu.kit.kastel.sdq.scorestats.config.AutomaticFeedbackType;
import edu.kit.kastel.sdq.scorestats.config.AutomaticFeedbackTypeAssessmentFactory;
import edu.kit.kastel.sdq.scorestats.config.ReportBuilder;
import edu.kit.kastel.sdq.scorestats.core.assessment.Assessments;
import edu.kit.kastel.sdq.scorestats.core.client.Artemis4JArtemisClient;
import edu.kit.kastel.sdq.scorestats.core.client.ArtemisClient;
import edu.kit.kastel.sdq.scorestats.input.ConfigFileMapper;
import edu.kit.kastel.sdq.scorestats.input.ConfigFileParser.ConfigFileParserException;
import edu.kit.kastel.sdq.scorestats.input.GroupFileParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -37,7 +43,6 @@ public class CLI {
private static final Logger logger = LoggerFactory.getLogger(CLI.class);

public void run(String[] args) {

Arguments arguments = new Arguments();
try {
JCommander.newBuilder().addObject(arguments).build().parse(args);
Expand All @@ -46,47 +51,49 @@ public void run(String[] args) {
return;
}

ArtemisClient<AutomaticFeedbackType> client = new Artemis4JArtemisClient<>(arguments.host, new AutomaticFeedbackTypeAssessmentFactory());
var artemis = new ArtemisInstance(arguments.host);

ArtemisConnection connection;
try {
client.login(arguments.username, arguments.password);
} catch (ArtemisClientException e) {
connection = ArtemisConnection.connectWithUsernamePassword(artemis, arguments.username, arguments.password);
} catch (ArtemisNetworkException e) {
logger.error("Failed to login!");
logger.error(e.getMessage(), e);
return;
}

List<Course> courses;
try {
courses = client.loadCourses();
courses = new ArrayList<>(connection.getCourses());
} catch (ArtemisClientException e) {
logger.error("Failed to load courses!");
logger.error(e.getMessage(), e);
return;
}
courses.sort(Comparator.comparing(Course::getCourseId));
courses.sort(Comparator.comparing(Course::getId));

try (Scanner scanner = new Scanner(System.in)) {
Course course = courses.get(0);
Course course = courses.getFirst();
// only prompt if there is more than one course to select from
if (courses.size() > 1) {
OptionDialogue<Course> courseDialogue = new OptionDialogue<>(scanner, "Please select the course:",
courses.stream().collect(Collectors.toMap(Course::getShortName, item -> item, (i1, i2) -> null, LinkedHashMap::new)));
course = courseDialogue.prompt();
}

List<Exercise> exercises;
List<ProgrammingExercise> exercises;
try {
exercises = course.getExercises();
exercises = new ArrayList<>(course.getProgrammingExercises());
} catch (ArtemisClientException e) {
logger.error("Error loading exercises.");
logger.error(e.getMessage());
return;
}
exercises.sort(Comparator.comparing(Exercise::getExerciseId));
OptionsDialogue<Exercise> exerciseDialogue = new OptionsDialogue<>(scanner, "Please select one or more exercises (separated by comma).",
exercises.sort(Comparator.comparing(ProgrammingExercise::getId));
OptionsDialogue<ProgrammingExercise> exerciseDialogue = new OptionsDialogue<>(scanner, "Please select one or more exercises (separated by comma).",
exercises.stream().collect(Collectors.toMap(Exercise::getShortName, item -> item, (i1, i2) -> null, LinkedHashMap::new)));

List<Exercise> selectedExercises = exerciseDialogue.prompt();
List<ProgrammingExercise> selectedExercises = exerciseDialogue.prompt();

try {
arguments.outDir.mkdirs();
Expand All @@ -95,20 +102,15 @@ public void run(String[] args) {
return;
}

Map<Exercise, ExerciseConfig> configs;
Map<ProgrammingExercise, GradingConfig> configs = new HashMap<>();
try {
configs = new ConfigFileMapper().mapConfigFiles(selectedExercises, arguments.configsDir);
} catch (ConfigFileParserException e) {
switch (e.getError()) {
case PARSING_FAILED:
logger.error("Failed to parse config file '%s':".formatted(e.getFile().getName()));
return;
case NOT_ALLOWED:
logger.error("The config file '%s' is not allowed for the exercise '%s':".formatted(e.getFile().getName(), e.getExercise().getShortName()));
return;
default:
return;
}
} catch (InvalidGradingConfigException e) {
logger.error("Failed to parse config file: %s".formatted(e.getMessage()));
} catch (IOException e) {
logger.error("Error while reading config files.");
logger.error(e.getMessage());
return;
}

GroupFileParser parser = new GroupFileParser();
Expand All @@ -125,18 +127,17 @@ public void run(String[] args) {
groups.put(file.getName().replaceFirst("[.][^.]+$", ""), students);
}

for (Map.Entry<Exercise, ExerciseConfig> entry : configs.entrySet()) {

Exercise exercise = entry.getKey();
ExerciseConfig config = entry.getValue();
for (var entry : configs.entrySet()) {
ProgrammingExercise exercise = entry.getKey();
GradingConfig config = entry.getValue();

logger.info(" -------------------- %s --------------------".formatted(exercise.getShortName()));

logger.info("Loading data...");
Assessments<AutomaticFeedbackType> assessments;
Assessments assessments;
try {
assessments = client.loadAssessments(exercise, config);
} catch (ArtemisClientException e) {
assessments = this.loadAssessments(config, exercise);
} catch (ArtemisNetworkException | AnnotationMappingException e) {
logger.error("Error while loading data.");
logger.error(e.getMessage());
return;
Expand All @@ -158,4 +159,32 @@ public void run(String[] args) {
logger.info("Finished!");
}
}

private Assessments loadAssessments(GradingConfig config, ProgrammingExercise exercise) throws ArtemisNetworkException, AnnotationMappingException {
Collection<ProgrammingSubmission> submissions = new ArrayList<>(exercise.fetchSubmissions(0, false));

if (exercise.hasSecondCorrectionRound()) {
submissions.addAll(exercise.fetchSubmissions(1, false));
}

Map<String, Assessment> assessments = HashMap.newHashMap(submissions.size());
List<String> skippedStudents = new ArrayList<>();

for (ProgrammingSubmission submission : submissions) {
String studentId = submission.getParticipantIdentifier();
Assessment assessment = submission.openAssessment(config).orElse(null);
if (assessment == null) {
skippedStudents.add(studentId);
continue;
}

if (assessments.containsKey(studentId)) {
logger.error("Something went wrong: The student id %s occurred multiple times.".formatted(studentId));
}

assessments.put(studentId, assessment);
}

return new Assessments(skippedStudents, assessments);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,29 @@

import java.io.File;
import java.io.IOException;
import java.util.EnumMap;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;

import edu.kit.kastel.sdq.artemis4j.api.artemis.Course;
import edu.kit.kastel.sdq.artemis4j.api.artemis.Exercise;
import edu.kit.kastel.sdq.artemis4j.grading.config.ExerciseConfig;
import edu.kit.kastel.sdq.artemis4j.grading.Assessment;
import edu.kit.kastel.sdq.artemis4j.grading.Course;
import edu.kit.kastel.sdq.artemis4j.grading.ProgrammingExercise;
import edu.kit.kastel.sdq.artemis4j.grading.penalty.GradingConfig;
import edu.kit.kastel.sdq.scorestats.cli.arguments.Arguments;
import edu.kit.kastel.sdq.scorestats.core.assessment.Assessments;
import edu.kit.kastel.sdq.scorestats.core.assessment.TestResultGroup;
import edu.kit.kastel.sdq.scorestats.core.report.Report;
import edu.kit.kastel.sdq.scorestats.core.report.visitors.CustomPenaltyAnnotationList;
import edu.kit.kastel.sdq.scorestats.core.report.visitors.FeedbackGroupFailedFrequency;
import edu.kit.kastel.sdq.scorestats.core.report.visitors.FeedbackGroupPassedAverage;
import edu.kit.kastel.sdq.scorestats.core.report.visitors.FeedbackGroupPassedCount;
import edu.kit.kastel.sdq.scorestats.core.report.visitors.ManualDeductionAverage;
import edu.kit.kastel.sdq.scorestats.core.report.visitors.MistakeTypeFrequencyPerAnnotation;
import edu.kit.kastel.sdq.scorestats.core.report.visitors.MistakeTypeFrequencyPerSubmission;
import edu.kit.kastel.sdq.scorestats.core.report.visitors.ParticipationReport;
import edu.kit.kastel.sdq.scorestats.core.report.visitors.ScoreAverage;
import edu.kit.kastel.sdq.scorestats.core.report.visitors.TestResultGroupFailedFrequency;
import edu.kit.kastel.sdq.scorestats.core.report.visitors.TestResultGroupPassedAverage;
import edu.kit.kastel.sdq.scorestats.core.report.visitors.TestResultGroupPassedCount;
import edu.kit.kastel.sdq.scorestats.core.report.visitors.TestResultGroupResolver;
import edu.kit.kastel.sdq.scorestats.output.FileWriter;
import edu.kit.kastel.sdq.scorestats.output.Output;
import org.slf4j.Logger;
Expand All @@ -29,27 +35,37 @@ public class ReportBuilder {
private static final Logger logger = LoggerFactory.getLogger(ReportBuilder.class);
private Output output;

public ReportBuilder createReport(Arguments arguments, Course course, Exercise exercise, ExerciseConfig config,
Assessments<AutomaticFeedbackType> assessments, Set<String> students) {
public ReportBuilder createReport(Arguments arguments, Course course, ProgrammingExercise exercise, GradingConfig config, Assessments assessments,
Set<String> students) {

Report<AutomaticFeedbackType> report = new Report<>(course, exercise, config, assessments, students);
Report report = new Report(course, exercise, config, assessments, students);

this.output = new ReportOutput(arguments, course, exercise, report.accept(new ParticipationReport<>()),
report.count(new FeedbackGroupPassedCount<>(AutomaticFeedbackType.MANDATORY)), //
report.average(new ScoreAverage<>()), //
report.average(new FeedbackGroupPassedAverage<>(AutomaticFeedbackType.FUNCTIONAL)), //
report.average(new FeedbackGroupPassedAverage<>(AutomaticFeedbackType.MODELING_CHECK)), //
report.average(new FeedbackGroupPassedAverage<>(AutomaticFeedbackType.OPTIONAL_CHECK)), //
config == null ? null : report.average(new ManualDeductionAverage<>()), //
Map<Assessment, Map<TestResultType, TestResultGroup>> storedGroups = new IdentityHashMap<>();
TestResultGroupResolver groupResolver = (key, assessment) -> {
Map<TestResultType, TestResultGroup> groups = storedGroups.computeIfAbsent(assessment, k -> new EnumMap<>(TestResultType.class));

report.frequency(new FeedbackGroupFailedFrequency<>(AutomaticFeedbackType.MANDATORY)), //
report.frequency(new FeedbackGroupFailedFrequency<>(AutomaticFeedbackType.FUNCTIONAL)), //
report.frequency(new FeedbackGroupFailedFrequency<>(AutomaticFeedbackType.MODELING_CHECK)), //
report.frequency(new FeedbackGroupFailedFrequency<>(AutomaticFeedbackType.OPTIONAL_CHECK)), //
return groups.computeIfAbsent(key, k -> {
TestResultGroup group = new TestResultGroup(key.matcher(), assessment.getSubmission());
group.addMatchingTestResults(assessment.getTestResults());
return group;
});
};
this.output = new ReportOutput(arguments, course, exercise, report.accept(new ParticipationReport()),
report.count(new TestResultGroupPassedCount(TestResultType.MANDATORY, groupResolver)), //
report.average(new ScoreAverage()), //
report.average(new TestResultGroupPassedAverage(TestResultType.FUNCTIONAL, groupResolver)), //
report.average(new TestResultGroupPassedAverage(TestResultType.MODELING_CHECK, groupResolver)), //
report.average(new TestResultGroupPassedAverage(TestResultType.OPTIONAL_CHECK, groupResolver)), //
config == null ? null : report.average(new ManualDeductionAverage()), //

config == null ? null : report.frequency(new MistakeTypeFrequencyPerSubmission<>()), //
config == null ? null : report.frequency(new MistakeTypeFrequencyPerAnnotation<>()), //
config == null ? null : report.list(new CustomPenaltyAnnotationList<>()));//
report.frequency(new TestResultGroupFailedFrequency(TestResultType.MANDATORY, groupResolver)), //
report.frequency(new TestResultGroupFailedFrequency(TestResultType.FUNCTIONAL, groupResolver)), //
report.frequency(new TestResultGroupFailedFrequency(TestResultType.MODELING_CHECK, groupResolver)), //
report.frequency(new TestResultGroupFailedFrequency(TestResultType.OPTIONAL_CHECK, groupResolver)), //

config == null ? null : report.frequency(new MistakeTypeFrequencyPerSubmission()), //
config == null ? null : report.frequency(new MistakeTypeFrequencyPerAnnotation()), //
config == null ? null : report.list(new CustomPenaltyAnnotationList()));//
return this;
}

Expand Down
Loading

0 comments on commit e0b3ee5

Please sign in to comment.