diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..d10dc41 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,37 @@ +# .github/workflows/publish.yml +name: Publish +on: + release: + types: [released, prereleased] + +jobs: + publish: + name: Release build and publish + runs-on: macOS-latest + permissions: + contents: read + packages: write + steps: + - name: Check out code + uses: actions/checkout@v4 + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: 21 + - name: Publish SNAPSHOT to snapshot repo + if: github.event.action == 'prereleased' + run: ./gradlew publishAllPublicationsToSnapshotsRepository --no-configuration-cache + env: + GITHUB_ACTOR: ${{ github.actor }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Publish release to Maven Central + if: github.event.action == 'released' + run: ./gradlew publishToMavenCentral --no-configuration-cache + env: + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} + ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.SIGNING_KEY_ID }} + ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.SIGNING_PASSWORD }} + ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_KEY_CONTENTS }} \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 648b95e..165af06 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,13 +1,13 @@ plugins { java application - id("com.github.johnrengelman.shadow") version "8.1.1" - id("maven-publish") + id("com.gradleup.shadow") version "9.4.3" + id("com.vanniktech.maven.publish") version "0.37.0" } -group = "igs-landstuhl" +group = "io.github.learn-monitor" -version = "v2.0.0-SNAPSHOT-2" +version = "s2607b1-SNAPSHOT" application { mainClass.set("de.igslandstuhl.database.Application") @@ -15,14 +15,6 @@ application { repositories { mavenCentral() - maven { - name = "Plugin Loader Repository" - url = uri("https://maven.pkg.github.com/Learn-Monitor/plugin-loader/") - credentials { - username = System.getenv("GITHUB_ACTOR") - password = System.getenv("GITHUB_TOKEN") - } - } } dependencies { @@ -37,12 +29,15 @@ dependencies { implementation("ch.qos.logback:logback-classic:1.5.6") // built-in plugins - implementation("de.igs-landstuhl:plugin-loader:v1.0.5") + implementation("io.github.learn-monitor:plugin-loader:v1.0.5") testImplementation("org.junit.jupiter:junit-jupiter:5.13.4") // using JUnit 5 (latest) testRuntimeOnly("org.junit.platform:junit-platform-launcher") } +tasks.javadoc { + classpath = sourceSets.main.get().compileClasspath +} tasks.test { useJUnitPlatform() systemProperty("test.environment", "true") @@ -67,25 +62,49 @@ java { } } -publishing { - publications { - create("mavenJava") { - from(components["java"]) +mavenPublishing { + publishToMavenCentral() - groupId = "igs-landstuhl" - artifactId = "student-database" - version = project.version.toString() + signAllPublications() + + coordinates(group.toString(), "student-database", version.toString()) + + pom { + name = "Student database" + description = "A Java-based application designed to manage and store student information efficiently. It allows admins to perform CRUD (Create, Read, Update, Delete) operations on student records, classes, subjects, and other school-related data, making it a valuable tool for educational institutions. Students can view their progress, and teachers can assign them topics, based on subjects." + url = "https://github.com/Learn-Monitor/student-database" + + licenses { + license { + name = "GNU General Public License v3.0" + url = "http://www.gnu.org/licenses/gpl-3.0.txt" + } + } + developers { + developer { + id = "schlaumeier5" + name = "Lukas Morgenstern" + url = "https://github.com/schlaumeier5" + } + } + scm { + url = "https://github.com/Learn-Monitor/student-database" + connection = "scm:git:https://github.com/Learn-Monitor/student-database.git" + developerConnection = "scm:git:ssh://git@github.com/Learn-Monitor/student-database.git" } } - +} +tasks.withType().configureEach { + dependsOn(tasks.withType()) +} +publishing { repositories { maven { - name = "GitHubPackages" - url = uri("https://maven.pkg.github.com/Learn-Monitor/student-database/") - + name = "snapshots" + url = uri("https://maven.pkg.github.com/Learn-Monitor/student-database") credentials { - username = System.getenv("GITHUB_ACTOR") - password = System.getenv("GITHUB_TOKEN") + username = System.getenv("GITHUB_ACTOR") ?: findProperty("gpr.user") as String? + password = System.getenv("GITHUB_TOKEN") ?: findProperty("gpr.key") as String? } } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a441313..7e7d24f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew.bat b/gradlew.bat index 25da30d..7101f8e 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,92 +1,92 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/src/main/java/de/igslandstuhl/database/Application.java b/src/main/java/de/igslandstuhl/database/Application.java index 7884e4c..6e051ee 100644 --- a/src/main/java/de/igslandstuhl/database/Application.java +++ b/src/main/java/de/igslandstuhl/database/Application.java @@ -28,15 +28,29 @@ * It will later replace Server as main class. */ public final class Application { + /** The delimiter for topics in LPT save files. */ public static final String TOPIC_DELIMITER = "\n"; + /** The delimiter for titles in LPT save files. */ public static final String TITLE_DELIMITER = "¶"; + /** The delimiter for task titles in LPT save files. */ public static final String TASK_TITLE_DELIMITER = "\\|"; + /** The delimiter for tasks in LPT save files. */ public static final String TASK_DELIMITER = "¤"; + /** + * The application main logger + */ public static final Logger LOGGER = LoggerFactory.getLogger(Application.class); + /** + * The logger for the student-database api + */ public static final Logger LOGGER_API = LoggerFactory.getLogger("de.igslandstuhl.database.api"); private static Application instance = new Application(new String[] {"--test-environment", "true"}); + /** + * Returns the singleton instance of the Application. + * @return the singleton instance of the Application + */ public static Application getInstance() { return instance; } diff --git a/src/main/java/de/igslandstuhl/database/api/APIObject.java b/src/main/java/de/igslandstuhl/database/api/APIObject.java index 9dbac05..017ce52 100644 --- a/src/main/java/de/igslandstuhl/database/api/APIObject.java +++ b/src/main/java/de/igslandstuhl/database/api/APIObject.java @@ -1,5 +1,12 @@ package de.igslandstuhl.database.api; +/** + * An interface representing any object that is part of the student-database API + */ public interface APIObject { + /** + * Returns a JSON representation of the object. + * @return a JSON representation of the object. + */ public String toJSON(); } diff --git a/src/main/java/de/igslandstuhl/database/api/Admin.java b/src/main/java/de/igslandstuhl/database/api/Admin.java index 04b83a9..e882ad8 100644 --- a/src/main/java/de/igslandstuhl/database/api/Admin.java +++ b/src/main/java/de/igslandstuhl/database/api/Admin.java @@ -6,6 +6,9 @@ import de.igslandstuhl.database.server.Server; import de.igslandstuhl.database.server.sql.SQLHelper; +/** + * Represents an administrator user in the system. + */ public class Admin extends User { private static final String[] SQL_FIELDS = { "username", "password_hash" }; @@ -17,12 +20,23 @@ private Admin(String username, String passwordHash) { this.passwordHash = passwordHash; } + /** + * Creates a new Admin user with the specified username and password. + * @param username the username + * @param password the password + * @return the newly created Admin object + * @throws SQLException if there's an underlying sql error during the creation process + */ public static Admin create(String username, String password) throws SQLException { String passwordHash = passHash(password); Server.getInstance().getConnection().executeVoidProcessSecure(SQLHelper.getAddObjectProcess("admin", username, passwordHash)); return new Admin(username, passwordHash); } + /** + * Deletes this Admin user from the database. + * @throws SQLException if there's an underlying sql error during the deletion process + */ public void delete() throws SQLException { Server.getInstance().getConnection().executeVoidProcessSecure(SQLHelper.getDeleteObjectProcess("admin", username)); } @@ -58,6 +72,11 @@ private static Admin fromSQL(String[] fields) { } return new Admin(fields[0], fields[1]); } + /** + * Retrieves an Admin user from the database by their username. + * @param username the username of the admin + * @return the Admin object if found, or null if not found + */ public static Admin get(String username) { try { return Server.getInstance().processSingleRequest(Admin::fromSQL, "get_admin_by_username", SQL_FIELDS, username); diff --git a/src/main/java/de/igslandstuhl/database/api/SpecialTask.java b/src/main/java/de/igslandstuhl/database/api/SpecialTask.java index 709c0cf..f012367 100644 --- a/src/main/java/de/igslandstuhl/database/api/SpecialTask.java +++ b/src/main/java/de/igslandstuhl/database/api/SpecialTask.java @@ -126,9 +126,9 @@ public static List getSpecialTasksByName(String name) { * Adds a new special task to the database. * This method creates a new task associated with a specific topic and level of difficulty. * - * @param topic the topic to which the task belongs, or null if not associated with any topic * @param name the name of the task - * @param niveau the level of difficulty for the task + * @param ratio the ratio indicating the proportion of progress achievable at this level + * @param subject the subject area to which the task belongs * @throws SQLException if there is an error accessing the database * @return the newly created SpecialTask object, or null if the task could not be added */ diff --git a/src/main/java/de/igslandstuhl/database/api/Student.java b/src/main/java/de/igslandstuhl/database/api/Student.java index f7c336f..80ee99f 100644 --- a/src/main/java/de/igslandstuhl/database/api/Student.java +++ b/src/main/java/de/igslandstuhl/database/api/Student.java @@ -400,6 +400,7 @@ public boolean hasCompletedTask(Task task) { * @param type the request type * @deprecated Use addSubjectRequest(Subject, SubjectRequest) instead */ + @Deprecated public void addSubjectRequest(int subjectId, String type) { currentRequests.computeIfPresent(subjectId, (key, value) -> { value.add(SubjectRequest.fromGermanTranslation(type)); @@ -421,6 +422,7 @@ public void addSubjectRequest(Subject subject, SubjectRequest subjectRequest) { * @param type the request type to remove * @deprecated Use removeSubjectRequest(Subject, SubjectRequest) instead */ + @Deprecated public void removeSubjectRequest(int subjectId, String type) { currentRequests.computeIfPresent(subjectId, (key, value) -> { value.remove(SubjectRequest.fromGermanTranslation(type)); diff --git a/src/main/java/de/igslandstuhl/database/api/User.java b/src/main/java/de/igslandstuhl/database/api/User.java index a86b371..03654d3 100644 --- a/src/main/java/de/igslandstuhl/database/api/User.java +++ b/src/main/java/de/igslandstuhl/database/api/User.java @@ -76,8 +76,20 @@ public String getUsername() { */ public abstract String toJSON(); + /** + * Sets the password for the user. + * This method should be implemented by subclasses to update the user's password. + * @param password the new password + * @return the updated User object + * @throws SQLException if an error occurs while updating the password + */ public abstract User setPassword(String password) throws SQLException; + /** + * Returns the username of the user. + * This method should be implemented by subclasses to provide the user's username. + * @return the username of the user + */ public abstract String getUsername(); /** @@ -113,6 +125,7 @@ public static String generateRandomPassword(int length, long seed) { /** * Returns the password hash of the user. * This method should be implemented by subclasses to provide the user's password hash. + * @param password the password to hash * @return the password hash of the user */ public static String passHash(String password) { diff --git a/src/main/java/de/igslandstuhl/database/api/results/GenerationResult.java b/src/main/java/de/igslandstuhl/database/api/results/GenerationResult.java index e47ab60..ee362ad 100644 --- a/src/main/java/de/igslandstuhl/database/api/results/GenerationResult.java +++ b/src/main/java/de/igslandstuhl/database/api/results/GenerationResult.java @@ -1,21 +1,42 @@ package de.igslandstuhl.database.api.results; +/** + * Represents the result of a generation process for an user of type T. + * @param the type of the generated entity + */ public abstract class GenerationResult { private final T entity; private final String password; + /** + * Constructs a GenerationResult with the specified entity and password. + * @param entity the generated entity of type T + * @param password the password associated with the generated entity + */ public GenerationResult(T entity, String password) { this.entity = entity; this.password = password; } + /** + * Returns the generated entity of type T. + * @return the generated entity + */ public T getEntity() { return entity; } + /** + * Returns the corresponding password associated with the generated entity. + * @return the password + */ public String getPassword() { return password; } + /** + * Returns a CSV representation of the generation result. + * @return a CSV representation of the generation result. + */ public abstract String toCSVRow(); } diff --git a/src/main/java/de/igslandstuhl/database/events/Event.java b/src/main/java/de/igslandstuhl/database/events/Event.java new file mode 100644 index 0000000..5f3497c --- /dev/null +++ b/src/main/java/de/igslandstuhl/database/events/Event.java @@ -0,0 +1,18 @@ +package de.igslandstuhl.database.events; + +public abstract class Event { + private boolean cancelled = false; + + public abstract EventType getType(); + protected void onCancel() { + // Override this method to handle cancellation logic in subclasses + } + + public boolean isCancelled() { + return this.cancelled; + } + public void cancel() { + this.cancelled = true; + onCancel(); + } +} diff --git a/src/main/java/de/igslandstuhl/database/events/EventFilter.java b/src/main/java/de/igslandstuhl/database/events/EventFilter.java new file mode 100644 index 0000000..ef40815 --- /dev/null +++ b/src/main/java/de/igslandstuhl/database/events/EventFilter.java @@ -0,0 +1,17 @@ +package de.igslandstuhl.database.events; + +@FunctionalInterface +public interface EventFilter { + public boolean filter(T event); + @SafeVarargs + public static EventFilter linked(EventFilter... filters) { + return event -> { + for (EventFilter filter : filters) { + if (!filter.filter(event)) { + return false; + } + } + return true; + }; + } +} diff --git a/src/main/java/de/igslandstuhl/database/events/EventListener.java b/src/main/java/de/igslandstuhl/database/events/EventListener.java new file mode 100644 index 0000000..190de5f --- /dev/null +++ b/src/main/java/de/igslandstuhl/database/events/EventListener.java @@ -0,0 +1,55 @@ +package de.igslandstuhl.database.events; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Set; + +import de.igslandstuhl.database.Registry; + +public abstract class EventListener { + private static final Registry, Set>> listeners = new Registry<>(); + + private final ListenerPriority priority; + + public EventListener(ListenerPriority priority) { + this.priority = priority; + } + + public abstract void onEvent(T event); + public abstract EventType getEventType(); + public EventFilter getFilter() { + return event -> true; + } + + public ListenerPriority getPriority() { + return priority; + } + public void register() { + listeners.get(getEventType()).add(this); + } + + public static void register(EventType type) { + listeners.register(type, new HashSet<>()); + } + + @SuppressWarnings("unchecked") + private static Set> getListeners(EventType type) { + return (Set>) (Set) listeners.get(type); + } + public static void fireEvent(T event) { + Set> eventListeners = getListeners(EventType.of(event)); + if (eventListeners != null) { + new LinkedList<>(eventListeners).stream() + .filter(listener -> listener.getFilter().filter(event)) + .sorted((a, b) -> a.getPriority().compareTo(b.getPriority())) + .forEach(listener -> { + if (!event.isCancelled()) { + listener.onEvent(event); + if (event.isCancelled() && listener.getPriority() == ListenerPriority.MONITOR) { + throw new IllegalStateException("Event was cancelled but a monitor listener was called."); + } + } + }); + } + } +} diff --git a/src/main/java/de/igslandstuhl/database/events/EventType.java b/src/main/java/de/igslandstuhl/database/events/EventType.java new file mode 100644 index 0000000..0e3735e --- /dev/null +++ b/src/main/java/de/igslandstuhl/database/events/EventType.java @@ -0,0 +1,8 @@ +package de.igslandstuhl.database.events; + +public record EventType(String name) { + @SuppressWarnings("unchecked") + public static EventType of(T event) { + return (EventType) event.getType(); + } +} diff --git a/src/main/java/de/igslandstuhl/database/events/ListenerPriority.java b/src/main/java/de/igslandstuhl/database/events/ListenerPriority.java new file mode 100644 index 0000000..9d7c30c --- /dev/null +++ b/src/main/java/de/igslandstuhl/database/events/ListenerPriority.java @@ -0,0 +1,9 @@ +package de.igslandstuhl.database.events; + +public enum ListenerPriority { + LOWEST, + LOW, + HIGH, + HIGHEST, + MONITOR +} diff --git a/src/main/java/de/igslandstuhl/database/server/resources/ResourceLocation.java b/src/main/java/de/igslandstuhl/database/server/resources/ResourceLocation.java index b1f7ca8..a539826 100644 --- a/src/main/java/de/igslandstuhl/database/server/resources/ResourceLocation.java +++ b/src/main/java/de/igslandstuhl/database/server/resources/ResourceLocation.java @@ -13,8 +13,7 @@ public record ResourceLocation(String context, String namespace, String resource * Constructs a ResourceLocation with the specified context, namespace, and resource name. * * @param context the context of the resource (e.g., "virtual", "main") - * @param namespace the namespace of the resource (e.g., "default", "custom") - * @param resource the name of the resource (e.g., "config.json", "data.txt") + * @param resourceID the name of the resource (e.g., "json:config.json", "meta:data.txt") */ public static ResourceLocation get(String context, String resourceID) { String[] parts = resourceID.split(":"); @@ -24,13 +23,6 @@ public static ResourceLocation get(String context, String resourceID) { return new ResourceLocation(context, "main", resourceID); } } - /** - * Constructs a ResourceLocation with the specified context and resource name. - * The namespace is set to "main" by default. - * - * @param context the context of the resource (e.g., "virtual", "main") - * @param resource the name of the resource (e.g., "config.json", "data.txt") - */ public boolean isVirtual() { return context.equals("virtual"); } diff --git a/src/main/java/de/igslandstuhl/database/server/sql/PreparedStatementSupplier.java b/src/main/java/de/igslandstuhl/database/server/sql/PreparedStatementSupplier.java index 87df02e..159b600 100644 --- a/src/main/java/de/igslandstuhl/database/server/sql/PreparedStatementSupplier.java +++ b/src/main/java/de/igslandstuhl/database/server/sql/PreparedStatementSupplier.java @@ -7,7 +7,7 @@ public interface PreparedStatementSupplier { /** * Prepares a SQL statement for execution. - * @param sql the SQL query to prepare + * @param query the SQL query to prepare * @return a PreparedStatement object * @throws SQLException if an SQL error occurs during preparation */ diff --git a/src/main/java/de/igslandstuhl/database/server/sql/SQLHelper.java b/src/main/java/de/igslandstuhl/database/server/sql/SQLHelper.java index a547b33..f1d64db 100644 --- a/src/main/java/de/igslandstuhl/database/server/sql/SQLHelper.java +++ b/src/main/java/de/igslandstuhl/database/server/sql/SQLHelper.java @@ -41,7 +41,6 @@ public static void insertArgs(PreparedStatement s, String[] args) throws SQLExce * Gets an SQL query by its name and replaces placeholders with provided arguments. * * @param queryName the name of the SQL query file (without extension) - * @param args the arguments to replace in the query * @return the SQL query as a String with placeholders replaced */ public static String getSQLQuery(String queryName) { diff --git a/src/main/java/de/igslandstuhl/database/server/sql/SQLProcess.java b/src/main/java/de/igslandstuhl/database/server/sql/SQLProcess.java index 2be0a87..8ff9c14 100644 --- a/src/main/java/de/igslandstuhl/database/server/sql/SQLProcess.java +++ b/src/main/java/de/igslandstuhl/database/server/sql/SQLProcess.java @@ -11,7 +11,7 @@ public interface SQLProcess { /** * Executes the SQL process using the given Statement. - * @param stmt the Statement to use for execution + * @param supplier the statement supplier to prepare the SQL statement * @return a ResultSet containing the results of the query * @throws SQLException if an SQL error occurs during execution */ diff --git a/src/main/java/de/igslandstuhl/database/server/webserver/AccessManager.java b/src/main/java/de/igslandstuhl/database/server/webserver/AccessManager.java deleted file mode 100644 index 53ca04a..0000000 --- a/src/main/java/de/igslandstuhl/database/server/webserver/AccessManager.java +++ /dev/null @@ -1,192 +0,0 @@ -package de.igslandstuhl.database.server.webserver; - -import java.io.IOException; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import de.igslandstuhl.database.Registry; -import de.igslandstuhl.database.api.User; -import de.igslandstuhl.database.server.Server; -import de.igslandstuhl.database.server.resources.ResourceLocation; - -/** - * AccessManager is responsible for managing access to resources based on user roles and resource locations. - * It determines whether a user has access to a specific resource based on predefined rules. - */ -public class AccessManager { - private static final Logger LOGGER = LoggerFactory.getLogger(AccessManager.class); - private static final AccessManager INSTANCE = new AccessManager(); - public static AccessManager getInstance() { - return INSTANCE; - } - /** - * Public spaces and locations that are accessible without authentication. - * These resources can be accessed by anyone, regardless of their authentication status. - */ - private final String[] PUBLIC_SPACES; - /** - * The user space is restricted to authenticated users. - */ - private final String USER_SPACE; - /** - * The teacher space is restricted to authenticated teachers. - */ - private final String TEACHER_SPACE; - /** - * The admin space is restricted to authenticated admins. - */ - private final String ADMIN_SPACE; - /** - * Public locations that are accessible without authentication. - * These resources can be accessed by anyone, regardless of their authentication status. - */ - private final String[] PUBLIC_LOCATIONS; - /** - * User locations that are accessible only to authenticated users. - * These resources require user login for access. - */ - private final String[] USER_LOCATIONS; - /** - * Teacher locations that are accessible only to authenticated teachers. - * These resources require teacher privileges for access. - */ - private final String[] TEACHER_LOCATIONS; - /** - * Admin locations that are accessible only to authenticated admins. - * These resources require admin privileges for access. - */ - private final String[] ADMIN_LOCATIONS; - - - @SuppressWarnings("unchecked") - private AccessManager() { - LOGGER.info("Setting up AccessManager..."); - ResourceLocation metaLocation = new ResourceLocation("meta", "paths", "spaces.json"); - String userSpace = "user"; - String teacherSpace = "teacher"; - String adminSpace = "admin"; - - String[] publicSpaces = {"error", "site", "icons"}; - String[] publicLocations = {"rooms", "subjects"}; - String[] userLocations = {}; - String[] teacherLocations = {}; - String[] adminLocations = {"students", "teachers", "classes"}; - try { - LOGGER.debug("Trying to read spaces metadata..."); - Map pathData = Server.getInstance().getResourceManager().readJsonResourceAsMap(metaLocation); - List publicSpacesList = (List) pathData.get("public_spaces"); - List publicLocationsList = (List) pathData.get("public_locations"); - List userLocationsList = (List) pathData.get("user_locations"); - List teacherLocationsList = (List) pathData.get("teacher_locations"); - List adminLocationsList = (List) pathData.get("admin_locations"); - userSpace = (String) pathData.get("user_space"); - teacherSpace = (String) pathData.get("teacher_space"); - adminSpace = (String) pathData.get("admin_space"); - publicSpaces = publicSpacesList.toArray(new String[publicSpacesList.size()]); - publicLocations = publicLocationsList.toArray(new String[publicLocationsList.size()]); - userLocations = userLocationsList.toArray(new String[userLocationsList.size()]); - teacherLocations = teacherLocationsList.toArray(new String[teacherLocationsList.size()]); - adminLocations = adminLocationsList.toArray(new String[adminLocationsList.size()]); - } catch (IOException e) { - LOGGER.error("Could not read spaces metadata!", e); - } finally { - USER_SPACE = userSpace; - TEACHER_SPACE = teacherSpace; - ADMIN_SPACE = adminSpace; - PUBLIC_SPACES = publicSpaces; - PUBLIC_LOCATIONS = publicLocations; - USER_LOCATIONS = userLocations; - TEACHER_LOCATIONS = teacherLocations; - ADMIN_LOCATIONS = adminLocations; - } - - - } - - /** - * Checks if a user has access to a specific resource. - * - * @param user the username of the user, or null if not authenticated - * @param resource the ResourceLocation representing the resource to check access for - * @return true if the user has access to the resource, false otherwise - * @deprecated Use hasAccess(String user, String path) - */ - @Deprecated - public boolean hasAccess(String user, ResourceLocation resource) { - return hasAccess(User.getUser(user), resource); - } - /** - * Checks if a user has access to a specific resource. - * - * @param user the user, or null if not authenticated - * @param resource the ResourceLocation representing the resource to check access for - * @return true if the user has access to the resource, false otherwise - * @deprecated Use hasAccess(User user, String path) - */ - @Deprecated - public boolean hasAccess(User user, ResourceLocation resource) { - if (Arrays.asList(PUBLIC_SPACES).contains(resource.namespace()) || Arrays.asList(PUBLIC_LOCATIONS).contains(resource.resource())) { - return true; - } else if (user != null) { - if (resource.namespace().equals(USER_SPACE) || resource.resource().startsWith("my") && !(user == User.ANONYMOUS)) { - return true; - } else if (resource.namespace().equals(TEACHER_SPACE)) { - return user.isTeacher() || user.isAdmin(); - } else if (resource.namespace().equals(ADMIN_SPACE) || Arrays.asList(ADMIN_LOCATIONS).contains(resource.resource())) { - return user.isAdmin(); - } else { - return false; - } - } else { - return false; - } - } - /** - * Checks if a user has access to a specific access level - * @param user the user, can be null to indicate no user logged in - * @param accessLevel the access level - * @return true, if the user has access, otherwise false - */ - public boolean hasAccess(User user, AccessLevel accessLevel) { - if (accessLevel == AccessLevel.PUBLIC) { - return true; - } else if (user == null || user == User.ANONYMOUS) { - return false; - } else if (accessLevel == AccessLevel.NONE) { - return false; - } else if (accessLevel == AccessLevel.USER) { - return true; - } else if (accessLevel == AccessLevel.STUDENT) { - return user.isStudent(); - } else if (user.isStudent()) { - return false; - } else if (accessLevel == AccessLevel.TEACHER) { - return true; - } else { - return user.isAdmin(); // Must be AccessLevel.ADMIN - } - } - /** - * Checks if a user has access to a specific web path - * @param user the username of the user, can be null to indicate no user logged in - * @param path the web path - * @return true, if the user has access, otherwise false - */ - public boolean hasAccess(String user, String path) { - return hasAccess(User.getUser(user), path); - } - /** - * Checks if a user has access to a specific web path - * @param user user, can be null to indicate no user logged in - * @param path the web path - * @return true, if the user has access, otherwise false - */ - public boolean hasAccess(User user, String path) { - AccessLevel accessLevel = Registry.webPathRegistry().get(path).accessLevel(); - return hasAccess(user, accessLevel); - } -} diff --git a/src/main/java/de/igslandstuhl/database/server/webserver/WebPath.java b/src/main/java/de/igslandstuhl/database/server/webserver/WebPath.java index 075401d..062b1f9 100644 --- a/src/main/java/de/igslandstuhl/database/server/webserver/WebPath.java +++ b/src/main/java/de/igslandstuhl/database/server/webserver/WebPath.java @@ -10,6 +10,7 @@ import de.igslandstuhl.database.Registry; import de.igslandstuhl.database.server.Server; import de.igslandstuhl.database.server.resources.ResourceLocation; +import de.igslandstuhl.database.server.webserver.access.AccessLevel; import de.igslandstuhl.database.server.webserver.requests.RequestType; public record WebPath(RequestType type, String handlerType, List namespaces, String context, AccessLevel accessLevel) { diff --git a/src/main/java/de/igslandstuhl/database/server/webserver/AccessLevel.java b/src/main/java/de/igslandstuhl/database/server/webserver/access/AccessLevel.java similarity index 90% rename from src/main/java/de/igslandstuhl/database/server/webserver/AccessLevel.java rename to src/main/java/de/igslandstuhl/database/server/webserver/access/AccessLevel.java index 9119790..f18b5f3 100644 --- a/src/main/java/de/igslandstuhl/database/server/webserver/AccessLevel.java +++ b/src/main/java/de/igslandstuhl/database/server/webserver/access/AccessLevel.java @@ -1,4 +1,4 @@ -package de.igslandstuhl.database.server.webserver; +package de.igslandstuhl.database.server.webserver.access; import de.igslandstuhl.database.api.User; diff --git a/src/main/java/de/igslandstuhl/database/server/webserver/access/AccessManager.java b/src/main/java/de/igslandstuhl/database/server/webserver/access/AccessManager.java new file mode 100644 index 0000000..687605b --- /dev/null +++ b/src/main/java/de/igslandstuhl/database/server/webserver/access/AccessManager.java @@ -0,0 +1,78 @@ +package de.igslandstuhl.database.server.webserver.access; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import de.igslandstuhl.database.Registry; +import de.igslandstuhl.database.api.User; +import de.igslandstuhl.database.events.EventListener; + +/** + * AccessManager is responsible for managing access to resources based on user roles and resource locations. + * It determines whether a user has access to a specific resource based on predefined rules. + */ +public class AccessManager { + private static final Logger LOGGER = LoggerFactory.getLogger(AccessManager.class); + private static final AccessManager INSTANCE = new AccessManager(); + public static AccessManager getInstance() { + return INSTANCE; + } + + private AccessManager() { + LOGGER.info("Setting up AccessManager..."); + } + /** + * Checks if a user has access to a specific access level + * @param user the user, can be null to indicate no user logged in + * @param accessLevel the access level + * @return the access state of the user for the given access level + */ + private AccessState getAccessState(User user, AccessLevel accessLevel) { + AccessState result; + if (accessLevel == AccessLevel.PUBLIC) { + result = AccessState.PERMITTED; + } else if (user == null || user == User.ANONYMOUS) { + result = AccessState.UNAUTHORIZED; + } else if (accessLevel == AccessLevel.NONE) { + result = AccessState.RESTRICTED; + } else if (accessLevel == AccessLevel.USER) { + result = AccessState.AUTHORIZED; + } else if (accessLevel == AccessLevel.STUDENT) { + result = user.isStudent() ? AccessState.AUTHORIZED : AccessState.RESTRICTED; + } else if (user.isStudent()) { + result = AccessState.RESTRICTED; + } else if (accessLevel == AccessLevel.TEACHER) { + result = AccessState.AUTHORIZED; + } else { + result = user.isAdmin() ? AccessState.AUTHORIZED : AccessState.RESTRICTED; // Must be AccessLevel.ADMIN + } + // Fire an AccessManagerEvent to allow for external modifications of the access decision + return result; + } + /** + * Checks if a user has access to a specific web path + * @param user the username of the user, can be null to indicate no user logged in + * @param path the web path + * @return true, if the user has access, otherwise false + */ + public boolean hasAccess(String user, String path) { + return hasAccess(User.getUser(user), path); + } + /** + * Checks if a user has access to a specific web path + * @param user user, can be null to indicate no user logged in + * @param path the web path + * @return true, if the user has access, otherwise false + */ + public boolean hasAccess(User user, String path) { + AccessLevel accessLevel = Registry.webPathRegistry().get(path).accessLevel(); + AccessState result = getAccessState(user, accessLevel); + + AccessManagerEvent event = new AccessManagerEvent(result, path); + EventListener.fireEvent(event); + + result = event.getChangedAccessState().orElse(result); + + return result == AccessState.AUTHORIZED || result == AccessState.PERMITTED; + } +} diff --git a/src/main/java/de/igslandstuhl/database/server/webserver/access/AccessManagerEvent.java b/src/main/java/de/igslandstuhl/database/server/webserver/access/AccessManagerEvent.java new file mode 100644 index 0000000..3615a0a --- /dev/null +++ b/src/main/java/de/igslandstuhl/database/server/webserver/access/AccessManagerEvent.java @@ -0,0 +1,53 @@ +package de.igslandstuhl.database.server.webserver.access; + +import java.util.Optional; + +import de.igslandstuhl.database.events.Event; +import de.igslandstuhl.database.events.EventType; + +public class AccessManagerEvent extends Event { + public static final EventType TYPE = new EventType<>("AccessManagerEvent"); + + private final AccessState accessState; + + private final String path; + + private Optional changedAccessState = Optional.empty(); + + public AccessManagerEvent(AccessState accessState, String path) { + this.accessState = accessState; + this.path = path; + } + + public AccessState getAccessState() { + return accessState; + } + public String getPath() { + return path; + } + public Optional getChangedAccessState() { + return changedAccessState; + } + @Override + public EventType getType() { + return TYPE; + } + + public void changeAccessState(AccessState newAccessState) { + this.changedAccessState = Optional.of(newAccessState); + this.cancel(); + } + + public static AccessManagerEvent unauthorized(String path) { + return new AccessManagerEvent(AccessState.UNAUTHORIZED, path); + } + public static AccessManagerEvent authorized(String path) { + return new AccessManagerEvent(AccessState.AUTHORIZED, path); + } + public static AccessManagerEvent restricted(String path) { + return new AccessManagerEvent(AccessState.RESTRICTED, path); + } + public static AccessManagerEvent pending(String path) { + return new AccessManagerEvent(AccessState.PENDING, path); + } +} diff --git a/src/main/java/de/igslandstuhl/database/server/webserver/access/AccessState.java b/src/main/java/de/igslandstuhl/database/server/webserver/access/AccessState.java new file mode 100644 index 0000000..8ccc019 --- /dev/null +++ b/src/main/java/de/igslandstuhl/database/server/webserver/access/AccessState.java @@ -0,0 +1,27 @@ +package de.igslandstuhl.database.server.webserver.access; + +/** + * AccessState represents the different states of access a user can have to a resource. + */ +public enum AccessState { + /** + * The user is not logged in and does not have access to the resource. + */ + UNAUTHORIZED, + /** + * The user is logged in and has access to the resource. + */ + AUTHORIZED, + /** + * The user is logged in but does not have access to the resource. + */ + RESTRICTED, + /** + * The user is logged in and has requested access to the resource. + */ + PENDING, + /** + * The user is logged in and has been granted access to the resource. + */ + PERMITTED +} diff --git a/src/main/java/de/igslandstuhl/database/server/webserver/access/AccessStateFilter.java b/src/main/java/de/igslandstuhl/database/server/webserver/access/AccessStateFilter.java new file mode 100644 index 0000000..1c88008 --- /dev/null +++ b/src/main/java/de/igslandstuhl/database/server/webserver/access/AccessStateFilter.java @@ -0,0 +1,16 @@ +package de.igslandstuhl.database.server.webserver.access; + +import de.igslandstuhl.database.events.EventFilter; + +public class AccessStateFilter implements EventFilter { + private final AccessState state; + + public AccessStateFilter(AccessState state) { + this.state = state; + } + + @Override + public boolean filter(AccessManagerEvent event) { + return event.getAccessState() == state; + } +} diff --git a/src/main/java/de/igslandstuhl/database/server/webserver/handlers/HttpHandler.java b/src/main/java/de/igslandstuhl/database/server/webserver/handlers/HttpHandler.java index d64604b..2ab3eba 100644 --- a/src/main/java/de/igslandstuhl/database/server/webserver/handlers/HttpHandler.java +++ b/src/main/java/de/igslandstuhl/database/server/webserver/handlers/HttpHandler.java @@ -5,8 +5,8 @@ import de.igslandstuhl.database.Registry; import de.igslandstuhl.database.server.Server; -import de.igslandstuhl.database.server.webserver.AccessLevel; import de.igslandstuhl.database.server.webserver.Status; +import de.igslandstuhl.database.server.webserver.access.AccessLevel; import de.igslandstuhl.database.server.webserver.requests.APIPostRequest; import de.igslandstuhl.database.server.webserver.requests.GetRequest; import de.igslandstuhl.database.server.webserver.requests.HttpRequest; diff --git a/src/main/java/de/igslandstuhl/database/server/webserver/handlers/PostRequestHandler.java b/src/main/java/de/igslandstuhl/database/server/webserver/handlers/PostRequestHandler.java index a60266a..594e66f 100644 --- a/src/main/java/de/igslandstuhl/database/server/webserver/handlers/PostRequestHandler.java +++ b/src/main/java/de/igslandstuhl/database/server/webserver/handlers/PostRequestHandler.java @@ -37,8 +37,8 @@ import de.igslandstuhl.database.plugins.config.PluginSetting; import de.igslandstuhl.database.plugins.config.ShortAnswerSetting; import de.igslandstuhl.database.server.Server; -import de.igslandstuhl.database.server.webserver.AccessLevel; import de.igslandstuhl.database.server.webserver.ContentType; +import de.igslandstuhl.database.server.webserver.access.AccessLevel; import de.igslandstuhl.database.server.webserver.requests.APIPostRequest; import de.igslandstuhl.database.server.webserver.requests.PostRequest; import de.igslandstuhl.database.server.webserver.responses.HttpResponse; @@ -79,8 +79,6 @@ private PostRequestHandler() { * Handles the POST request based on the path specified in the request. * It routes the request to the appropriate handler method based on the path. * @param request - * @param in - * @param out * @throws IOException */ public HttpResponse handlePostRequest(PostRequest request) throws IOException { diff --git a/src/main/java/de/igslandstuhl/database/server/webserver/requests/HttpHeader.java b/src/main/java/de/igslandstuhl/database/server/webserver/requests/HttpHeader.java index d08ade1..61cff76 100644 --- a/src/main/java/de/igslandstuhl/database/server/webserver/requests/HttpHeader.java +++ b/src/main/java/de/igslandstuhl/database/server/webserver/requests/HttpHeader.java @@ -27,7 +27,6 @@ public class HttpHeader { /** * Constructs a new PostRequest with the given header and body. * @param header the header of the POST request - * @param body the body of the POST request */ public HttpHeader(String header) { // Example: "POST /login HTTP/1.1" diff --git a/src/main/java/de/igslandstuhl/database/server/webserver/responses/GetResponse.java b/src/main/java/de/igslandstuhl/database/server/webserver/responses/GetResponse.java index 7189ed0..76c5ece 100644 --- a/src/main/java/de/igslandstuhl/database/server/webserver/responses/GetResponse.java +++ b/src/main/java/de/igslandstuhl/database/server/webserver/responses/GetResponse.java @@ -7,10 +7,10 @@ import de.igslandstuhl.database.client.TemplatingPreprocessor; import de.igslandstuhl.database.server.Server; import de.igslandstuhl.database.server.resources.ResourceLocation; -import de.igslandstuhl.database.server.webserver.AccessManager; import de.igslandstuhl.database.server.webserver.ContentType; import de.igslandstuhl.database.server.webserver.NoWebResourceException; import de.igslandstuhl.database.server.webserver.Status; +import de.igslandstuhl.database.server.webserver.access.AccessManager; import de.igslandstuhl.database.server.webserver.handlers.HttpHandler; import de.igslandstuhl.database.server.webserver.handlers.get.PluginRequestHandler; import de.igslandstuhl.database.server.webserver.requests.HttpRequest; diff --git a/src/main/java/de/igslandstuhl/database/server/webserver/responses/PostResponse.java b/src/main/java/de/igslandstuhl/database/server/webserver/responses/PostResponse.java index f2d373a..2181ca8 100644 --- a/src/main/java/de/igslandstuhl/database/server/webserver/responses/PostResponse.java +++ b/src/main/java/de/igslandstuhl/database/server/webserver/responses/PostResponse.java @@ -8,11 +8,11 @@ import de.igslandstuhl.database.server.Server; import de.igslandstuhl.database.server.WebServer; import de.igslandstuhl.database.server.resources.ResourceLocation; -import de.igslandstuhl.database.server.webserver.AccessManager; import de.igslandstuhl.database.server.webserver.ContentType; import de.igslandstuhl.database.server.webserver.Cookie; import de.igslandstuhl.database.server.webserver.NoWebResourceException; import de.igslandstuhl.database.server.webserver.Status; +import de.igslandstuhl.database.server.webserver.access.AccessManager; import de.igslandstuhl.database.server.webserver.handlers.HttpHandler; import de.igslandstuhl.database.server.webserver.requests.HttpRequest; import de.igslandstuhl.database.server.webserver.requests.PostRequest; diff --git a/src/main/java/de/igslandstuhl/database/server/webserver/sessions/SessionManager.java b/src/main/java/de/igslandstuhl/database/server/webserver/sessions/SessionManager.java index dd5114c..74536e6 100644 --- a/src/main/java/de/igslandstuhl/database/server/webserver/sessions/SessionManager.java +++ b/src/main/java/de/igslandstuhl/database/server/webserver/sessions/SessionManager.java @@ -134,7 +134,7 @@ public User getSessionUser(HttpRequest request) { * Adds a session to the session store. * This method is used to create a new session for a user. * - * @param sessionId The session ID to be added. + * @param session The session to be added. * @param username The username associated with the session. */ public void addSessionUser(Session session, String username) { diff --git a/src/main/resources/meta/paths/spaces.json b/src/main/resources/meta/paths/spaces.json deleted file mode 100644 index e1f899a..0000000 --- a/src/main/resources/meta/paths/spaces.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "public_spaces": [ - "error", - "site", - "icons" - ], - "user_space": "user", - "teacher_space": "teacher", - "admin_space": "admin", - "public_locations": [ - "rooms", - "subjects" - ], - "user_locations": [], - "teacher_locations": [], - "admin_locations": [ - "students", - "teachers", - "classes", - "all-student-results" - ] -} \ No newline at end of file diff --git a/src/test/java/de/igslandstuhl/database/server/webserver/AccessManagerTest.java b/src/test/java/de/igslandstuhl/database/server/webserver/AccessManagerTest.java index 940bcc4..d9815a0 100644 --- a/src/test/java/de/igslandstuhl/database/server/webserver/AccessManagerTest.java +++ b/src/test/java/de/igslandstuhl/database/server/webserver/AccessManagerTest.java @@ -11,8 +11,7 @@ import org.junit.jupiter.api.Test; import de.igslandstuhl.database.api.User; -import de.igslandstuhl.database.server.resources.ResourceLocation; -import de.igslandstuhl.database.server.webserver.handlers.WebResourceHandler; +import de.igslandstuhl.database.server.webserver.access.AccessManager; public class AccessManagerTest { private User teacher; @@ -120,45 +119,38 @@ public String getUsername() { anonymous = User.ANONYMOUS; } @Test - public void testErrorMessageAccess() { - assertTrue(AccessManager.getInstance().hasAccess(anonymous, ResourceLocation.get("html", "error:404"))); - assertTrue(AccessManager.getInstance().hasAccess(student, ResourceLocation.get("html", "error:404"))); - assertTrue(AccessManager.getInstance().hasAccess(teacher, ResourceLocation.get("html", "error:404"))); - assertTrue(AccessManager.getInstance().hasAccess(admin, ResourceLocation.get("html", "error:404"))); - } - @Test public void testIconAccess() { - assertTrue(AccessManager.getInstance().hasAccess(anonymous, ResourceLocation.get("imgs", "icons:favicon.ico"))); - assertTrue(AccessManager.getInstance().hasAccess(student, ResourceLocation.get("imgs", "icons:favicon.ico"))); - assertTrue(AccessManager.getInstance().hasAccess(teacher, ResourceLocation.get("imgs", "icons:favicon.ico"))); - assertTrue(AccessManager.getInstance().hasAccess(admin, ResourceLocation.get("imgs", "icons:favicon.ico"))); + assertTrue(AccessManager.getInstance().hasAccess(anonymous, "/favicon.ico")); + assertTrue(AccessManager.getInstance().hasAccess(student, "/favicon.ico")); + assertTrue(AccessManager.getInstance().hasAccess(teacher, "/favicon.ico")); + assertTrue(AccessManager.getInstance().hasAccess(admin, "/favicon.ico")); } @Test public void testLoginAccess() { - assertTrue(AccessManager.getInstance().hasAccess(anonymous, ResourceLocation.get("html", "site:login"))); - assertTrue(AccessManager.getInstance().hasAccess(student, ResourceLocation.get("html", "site:login"))); - assertTrue(AccessManager.getInstance().hasAccess(teacher, ResourceLocation.get("html", "site:login"))); - assertTrue(AccessManager.getInstance().hasAccess(admin, ResourceLocation.get("html", "site:login"))); + assertTrue(AccessManager.getInstance().hasAccess(anonymous, "/login")); + assertTrue(AccessManager.getInstance().hasAccess(student, "/login")); + assertTrue(AccessManager.getInstance().hasAccess(teacher, "/login")); + assertTrue(AccessManager.getInstance().hasAccess(admin, "/login")); } @Test public void testDashboardAccess() { - assertFalse(AccessManager.getInstance().hasAccess(anonymous, WebResourceHandler.locationFromPath("/dashboard", anonymous))); - assertTrue(AccessManager.getInstance().hasAccess(student, WebResourceHandler.locationFromPath("/dashboard", student))); - assertTrue(AccessManager.getInstance().hasAccess(teacher, WebResourceHandler.locationFromPath("/dashboard", teacher))); - assertTrue(AccessManager.getInstance().hasAccess(admin, WebResourceHandler.locationFromPath("/dashboard", admin))); + assertFalse(AccessManager.getInstance().hasAccess(anonymous, "/dashboard")); + assertTrue(AccessManager.getInstance().hasAccess(student, "/dashboard")); + assertTrue(AccessManager.getInstance().hasAccess(teacher, "/dashboard")); + assertTrue(AccessManager.getInstance().hasAccess(admin, "/dashboard")); } @Test public void testStudentManagementAccess() { - assertFalse(AccessManager.getInstance().hasAccess(anonymous, WebResourceHandler.locationFromPath("/student", anonymous))); - assertFalse(AccessManager.getInstance().hasAccess(student, WebResourceHandler.locationFromPath("/student", student))); - assertTrue(AccessManager.getInstance().hasAccess(teacher, WebResourceHandler.locationFromPath("/student", teacher))); - assertTrue(AccessManager.getInstance().hasAccess(admin, WebResourceHandler.locationFromPath("/student", admin))); + assertFalse(AccessManager.getInstance().hasAccess(anonymous, "/student")); + assertFalse(AccessManager.getInstance().hasAccess(student, "/student")); + assertTrue(AccessManager.getInstance().hasAccess(teacher, "/student")); + assertTrue(AccessManager.getInstance().hasAccess(admin, "/student")); } @Test public void testTeacherManagementAccess() { - assertFalse(AccessManager.getInstance().hasAccess(anonymous, WebResourceHandler.locationFromPath("/teacher", anonymous))); - assertFalse(AccessManager.getInstance().hasAccess(student, WebResourceHandler.locationFromPath("/teacher", student))); - assertFalse(AccessManager.getInstance().hasAccess(teacher, WebResourceHandler.locationFromPath("/teacher", teacher))); - assertTrue(AccessManager.getInstance().hasAccess(admin, WebResourceHandler.locationFromPath("/teacher", admin))); + assertFalse(AccessManager.getInstance().hasAccess(anonymous, "/teacher")); + assertFalse(AccessManager.getInstance().hasAccess(student, "/teacher")); + assertFalse(AccessManager.getInstance().hasAccess(teacher, "/teacher")); + assertTrue(AccessManager.getInstance().hasAccess(admin, "/teacher")); } }