Skip to content

Commit 1215758

Browse files
authored
Merge pull request #166 from Learn-Monitor/v1.0.1
Full version V1.0.1
2 parents ef675b9 + 5cb4c41 commit 1215758

File tree

81 files changed

+3019
-2995
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+3019
-2995
lines changed

build.gradle.kts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ plugins {
55
}
66

77
group = "igs-landstuhl"
8-
version = "v1.0-PATCH-3"
8+
9+
version = "v1.0.1-SNAPSHOT-1"
10+
911
application {
1012
mainClass.set("de.igslandstuhl.database.Application")
1113
}
@@ -19,8 +21,10 @@ dependencies {
1921
implementation("com.google.code.gson:gson:2.13.1")
2022
implementation("commons-codec:commons-codec:1.19.0")
2123
implementation("com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20240325.1")
24+
implementation("org.jline:jline:3.30.6") // for better console input handling
2225

23-
testImplementation("org.junit.jupiter:junit-jupiter:5.10.0") // using JUnit 5 (latest)
26+
testImplementation("org.junit.jupiter:junit-jupiter:5.13.4") // using JUnit 5 (latest)
27+
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
2428
}
2529

2630
tasks.test {

src/main/java/de/igslandstuhl/database/Application.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@
77
import de.igslandstuhl.database.api.SerializationException;
88
import de.igslandstuhl.database.api.Subject;
99
import de.igslandstuhl.database.api.Topic;
10+
import de.igslandstuhl.database.api.modules.WebModule;
1011
import de.igslandstuhl.database.holidays.Holiday;
1112
import de.igslandstuhl.database.server.Server;
1213
import de.igslandstuhl.database.server.commands.Command;
13-
import de.igslandstuhl.database.server.webserver.PostRequestHandler;
14+
import de.igslandstuhl.database.server.webserver.WebPath;
15+
import de.igslandstuhl.database.server.webserver.handlers.GetRequestHandler;
16+
import de.igslandstuhl.database.server.webserver.handlers.PostRequestHandler;
1417
import de.igslandstuhl.database.utils.CommandLineUtils;
1518

1619
/**
@@ -92,18 +95,24 @@ public Topic[] readFile(String file) throws SerializationException, SQLException
9295

9396
public static void main(String[] args) throws Exception {
9497
instance = new Application(args);
98+
99+
if (!getInstance().suppressCmd()) {
100+
Command.registerCommands();
101+
CommandLineUtils.setup();
102+
}
103+
95104
Server.getInstance().getConnection().createTables();
96105

97106
Holiday.setupCurrentSchoolYear();
98107
PostRequestHandler.registerHandlers();
108+
WebModule.registerModules();
109+
110+
WebPath.registerPaths();
111+
GetRequestHandler.getInstance().registerHandlers();
99112

100113
if (getInstance().runsWebServer()) {
101114
Server.getInstance().getWebServer().start();
102115
}
103-
if (!getInstance().suppressCmd()) {
104-
Command.registerCommands();
105-
CommandLineUtils.setup();
106-
}
107116

108117
while (true) {
109118
if (!getInstance().suppressCmd()) {

src/main/java/de/igslandstuhl/database/Registry.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,21 @@
55
import java.util.Map;
66
import java.util.stream.Stream;
77

8+
import de.igslandstuhl.database.api.modules.WebModule;
89
import de.igslandstuhl.database.server.commands.Command;
10+
import de.igslandstuhl.database.server.commands.CommandDescription;
11+
import de.igslandstuhl.database.server.webserver.WebPath;
12+
import de.igslandstuhl.database.server.webserver.handlers.HttpHandler;
913
import de.igslandstuhl.database.server.webserver.requests.APIPostRequest;
1014
import de.igslandstuhl.database.server.webserver.requests.GetRequest;
11-
import de.igslandstuhl.database.server.webserver.requests.HttpHandler;
1215

1316
public class Registry<K, V> implements Closeable {
1417
private static final Registry<String,Command> COMMAND_REGISTRY = new Registry<>();
18+
private static final Registry<String,CommandDescription> COMMAND_DESCRIPTION_REGISTRY = new Registry<>();
1519
private static final Registry<String,HttpHandler<APIPostRequest>> POST_HANDLER_REGISTRY = new Registry<>();
1620
private static final Registry<String,HttpHandler<GetRequest>> GET_HANDLER_REGISTRY = new Registry<>();
21+
private static final Registry<String,WebModule> MODULE_REGISTRY = new Registry<>();
22+
private static final Registry<String,WebPath> WEB_PATH_REGISTRY = new Registry<>();
1723
public static Registry<String,Command> commandRegistry() {
1824
return COMMAND_REGISTRY;
1925
}
@@ -23,6 +29,15 @@ public static Registry<String, HttpHandler<APIPostRequest>> postRequestHandlerRe
2329
public static Registry<String, HttpHandler<GetRequest>> getRequestHandlerRegistry() {
2430
return GET_HANDLER_REGISTRY;
2531
}
32+
public static Registry<String, WebModule> moduleRegistry() {
33+
return MODULE_REGISTRY;
34+
}
35+
public static Registry<String, CommandDescription> commandDescriptionRegistry() {
36+
return COMMAND_DESCRIPTION_REGISTRY;
37+
}
38+
public static Registry<String, WebPath> webPathRegistry() {
39+
return WEB_PATH_REGISTRY;
40+
}
2641

2742
private final Map<K,V> objects = new HashMap<>();
2843

src/main/java/de/igslandstuhl/database/api/Room.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ public static Room getRoom(String label) {
101101
} else {
102102
try {
103103
Room room = Server.getInstance().processSingleRequest(Room::fromSQLFields, "get_room_by_label", SQL_FIELDS, label);
104+
if (room == null) {
105+
return null;
106+
}
104107
rooms.put(label, room);
105108
return room;
106109
} catch (SQLException e) {

src/main/java/de/igslandstuhl/database/api/SchoolClass.java

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import java.sql.SQLException;
44
import java.util.ArrayList;
5+
import java.util.LinkedList;
56
import java.util.List;
7+
import java.util.Locale;
68
import java.util.Objects;
79
import java.util.stream.Collectors;
810

@@ -326,5 +328,80 @@ public boolean equals(Object obj) {
326328
public String toJSON() {
327329
return "{\"id\": " + id + ", \"label\": \"" + label + "\", \"grade\": " + grade + "}";
328330
}
329-
331+
332+
/**
333+
* Generates a CSV representation of completed tasks for each student in the class for a given subject.
334+
* @param subject the subject for which to generate the CSV
335+
* @return a CSV string representing the completed tasks of each student for this subject
336+
*/
337+
public String getCompletedTasksCSV(Subject subject) {
338+
StringBuilder csvBuilder = new StringBuilder();
339+
List<Student> students = getStudents();
340+
List<Task> tasks = new LinkedList<>();
341+
subject.getTopics(grade).forEach((t) -> tasks.addAll(t.getTasks()));
342+
csvBuilder.append("Student ID,First Name,Last Name,Email");
343+
tasks.forEach((t) -> csvBuilder.append(",").append(t.getNumber()));
344+
csvBuilder.append("\n");
345+
for (Student student : students) {
346+
csvBuilder.append(student.getId()).append(",")
347+
.append(student.getFirstName()).append(",")
348+
.append(student.getLastName()).append(",")
349+
.append(student.getEmail());
350+
for (Task task : tasks) {
351+
boolean completed = student.hasCompletedTask(task);
352+
csvBuilder.append(",").append(completed ? "1" : "0");
353+
}
354+
csvBuilder.append("\n");
355+
}
356+
return csvBuilder.toString();
357+
}
358+
359+
/**
360+
* Generates a CSV representation of the results for each student in the class for a given subject.
361+
* @param subject the subject for which to generate the CSV
362+
* @return a CSV string representing the results of each student for this subject
363+
*/
364+
public String getResultsCSV(Subject subject) {
365+
StringBuilder csvBuilder = new StringBuilder();
366+
List<Student> students = getStudents();
367+
368+
csvBuilder.append("Student ID,First Name,Last Name,Email,Total Score(%)\n");
369+
for (Student student : students) {
370+
double totalScore = student.getCurrentProgress(subject) * 100.;
371+
csvBuilder.append(student.getId()).append(",")
372+
.append(student.getFirstName()).append(",")
373+
.append(student.getLastName()).append(",")
374+
.append(student.getEmail()).append(",")
375+
.append(String.format(Locale.US, "%.2f", totalScore)).append("\n");
376+
}
377+
378+
return csvBuilder.toString();
379+
}
380+
/**
381+
* Generates a CSV representation of the results for all students in all classes of a given grade for a given subject.
382+
* @param grade the grade level for which to generate the CSV
383+
* @param subject the subject for which to generate the CSV
384+
* @return a CSV string representing the results of each student for this subject across all classes of the specified grade
385+
*/
386+
public static String getResultsCSV(int grade, Subject subject) {
387+
StringBuilder csvBuilder = new StringBuilder();
388+
List<SchoolClass> classes = getAll().stream().filter(c -> c.getGrade() == grade).toList();
389+
390+
csvBuilder.append("Class,Student ID,First Name,Last Name,Email,Total Score(%)\n");
391+
for (SchoolClass schoolClass : classes) {
392+
List<Student> students = schoolClass.getStudents();
393+
for (Student student : students) {
394+
double totalScore = student.getCurrentProgress(subject) * 100.;
395+
csvBuilder.append(schoolClass.getLabel()).append(",")
396+
.append(student.getId()).append(",")
397+
.append(student.getFirstName()).append(",")
398+
.append(student.getLastName()).append(",")
399+
.append(student.getEmail()).append(",")
400+
.append(String.format(Locale.US, "%.2f", totalScore)).append("\n");
401+
}
402+
}
403+
404+
return csvBuilder.toString();
405+
}
406+
330407
}

src/main/java/de/igslandstuhl/database/api/Student.java

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.util.HashMap;
66
import java.util.HashSet;
77
import java.util.List;
8+
import java.util.Locale;
89
import java.util.Map;
910
import java.util.Objects;
1011
import java.util.Random;
@@ -404,6 +405,15 @@ public Set<SubjectRequest> getCurrentRequests(Subject subject) {
404405
*/
405406
public SchoolClass getSchoolClass() { return schoolClass; }
406407

408+
/**
409+
* Checks if the student has completed a specific task.
410+
* @param task the task to check
411+
* @return true if the student has completed the task, false otherwise
412+
*/
413+
public boolean hasCompletedTask(Task task) {
414+
return completedTasks.contains(task);
415+
}
416+
407417
/**
408418
* Adds a subject request for this student.
409419
* @param subjectId the subject ID
@@ -801,4 +811,53 @@ public Student setPassword(String password) throws SQLException {
801811
students.remove(id);
802812
return get(id);
803813
}
814+
815+
/**
816+
* Generates a CSV string containing the student's results.
817+
* @return a CSV string of the student's results
818+
*/
819+
public String getResultsCSV() {
820+
StringBuilder csvBuilder = new StringBuilder();
821+
csvBuilder.append("Subject,Current Progress (%),Predicted Progress (%),Currently Achieved Grade,Predicted Grade\n");
822+
for (Subject subject : getSchoolClass().getSubjects()) {
823+
double currentProgress = getCurrentProgress(subject) * 100;
824+
double predictedProgress = getPredictedProgress(subject) * 100;
825+
int currentGrade = getCurrentlyAchievedGrade(subject);
826+
int predictedGrade = getPredictedGrade(subject);
827+
csvBuilder.append(String.format(Locale.US, "%s,%.2f,%.2f,%d,%d\n",
828+
subject.getName(),
829+
currentProgress,
830+
predictedProgress,
831+
currentGrade,
832+
predictedGrade));
833+
}
834+
return csvBuilder.toString();
835+
}
836+
/**
837+
* Generates a CSV string containing all students' results.
838+
* @return a CSV string of all students' results
839+
*/
840+
public static String getAllResultsCSV() {
841+
StringBuilder csvBuilder = new StringBuilder();
842+
csvBuilder.append("Student ID,First Name,Last Name,Email,Subject,Current Progress (%),Predicted Progress (%),Currently Achieved Grade,Predicted Grade\n");
843+
for (Student student : getAll()) {
844+
for (Subject subject : student.getSchoolClass().getSubjects()) {
845+
double currentProgress = student.getCurrentProgress(subject) * 100;
846+
double predictedProgress = student.getPredictedProgress(subject) * 100;
847+
int currentGrade = student.getCurrentlyAchievedGrade(subject);
848+
int predictedGrade = student.getPredictedGrade(subject);
849+
csvBuilder.append(String.format(Locale.US, "%d,%s,%s,%s,%s,%.2f,%.2f,%d,%d\n",
850+
student.getId(),
851+
student.getFirstName(),
852+
student.getLastName(),
853+
student.getEmail(),
854+
subject.getName(),
855+
currentProgress,
856+
predictedProgress,
857+
currentGrade,
858+
predictedGrade));
859+
}
860+
}
861+
return csvBuilder.toString();
862+
}
804863
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package de.igslandstuhl.database.api.modules;
2+
3+
public class BoolSetting extends ModuleSetting<Boolean> {
4+
public BoolSetting(String key, String name, String description, boolean defaultValue) {
5+
super(key, name, description, defaultValue);
6+
}
7+
8+
public void toggle() {
9+
setValue(!getValue());
10+
}
11+
public void enable() {
12+
setValue(true);
13+
}
14+
public void disable() {
15+
setValue(false);
16+
}
17+
public boolean isEnabled() {
18+
return getValue();
19+
}
20+
21+
@Override
22+
public String toJSON() {
23+
return "{" +
24+
"\"key\":\"" + getKey() + "\"," +
25+
"\"name\":\"" + getName() + "\"," +
26+
"\"description\":\"" + getDescription() + "\"," +
27+
"\"defaultValue\":" + getDefaultValue() + "," +
28+
"\"value\":" + getValue() +
29+
"}";
30+
}
31+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package de.igslandstuhl.database.api.modules;
2+
3+
public class ModuleSetting<T> {
4+
private final String key;
5+
private final String name;
6+
private final String description;
7+
private final T defaultValue;
8+
private T value;
9+
10+
public ModuleSetting(String key, String name, String description, T defaultValue) {
11+
this.key = key;
12+
this.name = name;
13+
this.description = description;
14+
this.defaultValue = defaultValue;
15+
this.value = defaultValue;
16+
}
17+
18+
public String getKey() {
19+
return key;
20+
}
21+
public String getName() {
22+
return name;
23+
}
24+
public String getDescription() {
25+
return description;
26+
}
27+
public T getDefaultValue() {
28+
return defaultValue;
29+
}
30+
31+
public T getValue() {
32+
return value;
33+
}
34+
35+
public void setValue(T value) {
36+
this.value = value;
37+
}
38+
39+
public String toJSON() {
40+
return "{" +
41+
"\"key\":\"" + key + "\"," +
42+
"\"name\":\"" + name + "\"," +
43+
"\"description\":\"" + description + "\"," +
44+
"\"defaultValue\":\"" + defaultValue + "\"," +
45+
"\"value\":\"" + value + "\"" +
46+
"}";
47+
}
48+
49+
}

0 commit comments

Comments
 (0)