diff --git a/backend/build.gradle.kts b/backend/build.gradle.kts
index 3fd1243..4eaa3bf 100644
--- a/backend/build.gradle.kts
+++ b/backend/build.gradle.kts
@@ -13,8 +13,8 @@ application{
dependencies{
implementation(project(":translations"))
+ implementation(project(":user"))
implementation(project(":web"))
- implementation("de.srsoftware:tools.http:6.0.0")
}
tasks.jar {
diff --git a/backend/src/main/java/de/srsoftware/umbrella/backend/Application.java b/backend/src/main/java/de/srsoftware/umbrella/backend/Application.java
index 546dd29..f44e6e9 100644
--- a/backend/src/main/java/de/srsoftware/umbrella/backend/Application.java
+++ b/backend/src/main/java/de/srsoftware/umbrella/backend/Application.java
@@ -7,6 +7,7 @@ import static java.lang.System.Logger.Level.INFO;
import com.sun.net.httpserver.HttpServer;
import de.srsoftware.tools.ColorLogger;
import de.srsoftware.umbrella.translations.Translations;
+import de.srsoftware.umbrella.user.UserModule;
import de.srsoftware.umbrella.web.WebHandler;
import java.io.IOException;
import java.net.InetSocketAddress;
@@ -22,6 +23,7 @@ public class Application {
HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);
server.setExecutor(Executors.newFixedThreadPool(threads));
new WebHandler().bindPath("/").on(server);
+ new UserModule().bindPath("/api/user").on(server);
new Translations().bindPath("/api/translations").on(server);
LOG.log(INFO,"Started web server at {0}",port);
server.start();
diff --git a/build.gradle.kts b/build.gradle.kts
index 8709c33..d868971 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -40,7 +40,7 @@ subprojects {
dependencies {
testImplementation(platform("org.junit:junit-bom:5.10.0"))
testImplementation("org.junit.jupiter:junit-jupiter")
-
+ implementation("de.srsoftware:tools.http:6.0.2")
implementation("de.srsoftware:tools.logging:1.3.2")
}
diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte
index 64780fe..7f8d333 100644
--- a/frontend/src/App.svelte
+++ b/frontend/src/App.svelte
@@ -1,6 +1,8 @@
-{#if translations_ready}
+{#if translations_ready }
+{#if user.username }
+{:else}
+{/if}
{:else}
Loading translations...
{/if}
\ No newline at end of file
diff --git a/frontend/src/Components/Homepage.svelte b/frontend/src/Components/Homepage.svelte
index f47aba5..24cce90 100644
--- a/frontend/src/Components/Homepage.svelte
+++ b/frontend/src/Components/Homepage.svelte
@@ -1 +1,5 @@
-Welcome
\ No newline at end of file
+
+{t('home.Welcome')}, {user.username}
\ No newline at end of file
diff --git a/frontend/src/Components/Login.svelte b/frontend/src/Components/Login.svelte
index d20f186..cd66614 100644
--- a/frontend/src/Components/Login.svelte
+++ b/frontend/src/Components/Login.svelte
@@ -1,5 +1,15 @@
+
- {t('login.Login')}
-
-
- Email/Username
-
-
-
- Password
-
- Login
-
-
-
- OIDC Login
+ {t('login.OIDC_Login')}
SRSoftware
ORC ID
diff --git a/frontend/src/Components/Menu.svelte b/frontend/src/Components/Menu.svelte
index de5b32b..3ffce07 100644
--- a/frontend/src/Components/Menu.svelte
+++ b/frontend/src/Components/Menu.svelte
@@ -1,3 +1,13 @@
+
- Home
+ {t('nav.Home')}
+ {t('nav.Tutorial')}
+ Logout
\ No newline at end of file
diff --git a/frontend/src/app.css b/frontend/src/app.css
index afcfe68..5298a0b 100644
--- a/frontend/src/app.css
+++ b/frontend/src/app.css
@@ -1,3 +1,6 @@
+a {
+ color: orange;
+}
body {
background: black;
color: orange;
@@ -14,6 +17,7 @@ input{
border-radius: 4px;
padding: 3px;
margin: 3px;
+ color: orange;
}
button{
diff --git a/frontend/src/translations.svelte.js b/frontend/src/translations.svelte.js
index 41bb40d..405192e 100644
--- a/frontend/src/translations.svelte.js
+++ b/frontend/src/translations.svelte.js
@@ -8,12 +8,11 @@ export async function loadTranslation(lang){
}
export function t(key){
- var keys = key.split('.');
let set = translations.values;
+ var keys = key.split('.');
for (let key of keys){
- if (set[key]) {
- set = set[key];
- } else return key;
+ if (!set[key]) return keys[keys.length-1];
+ set = set[key];
}
return set;
}
\ No newline at end of file
diff --git a/frontend/src/user.svelte.js b/frontend/src/user.svelte.js
new file mode 100644
index 0000000..3f016fd
--- /dev/null
+++ b/frontend/src/user.svelte.js
@@ -0,0 +1,20 @@
+export const user = $state({
+ name : null
+})
+
+export async function tryLogin(credentials){
+ var url = `${location.protocol}//${location.host.replace('5173','8080')}/api/user/login`;
+ let response = await fetch(url,{
+ headers: {
+ 'Content-Type':'application/json'
+ },
+ method: 'POST',
+ body: JSON.stringify(credentials)
+ });
+ if (response.ok){
+ const json = await response.json();
+ for (var key of Object.keys(json)) user[key] = json[key];
+ } else {
+ alert("Login failed!");
+ }
+}
\ No newline at end of file
diff --git a/settings.gradle.kts b/settings.gradle.kts
index cfacc5e..1e4f564 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,5 +1,6 @@
rootProject.name = "Umbrella25"
include("backend")
+include("translations")
+include("user")
include("web")
-include("translations")
\ No newline at end of file
diff --git a/translations/build.gradle.kts b/translations/build.gradle.kts
index 42cfea2..cb99751 100644
--- a/translations/build.gradle.kts
+++ b/translations/build.gradle.kts
@@ -1,6 +1,5 @@
description = "Umbrella : Translations"
dependencies{
- implementation("de.srsoftware:tools.http:6.0.0")
implementation("org.json:json:20240303")
}
\ No newline at end of file
diff --git a/translations/src/main/java/de/srsoftware/umbrella/translations/Translations.java b/translations/src/main/java/de/srsoftware/umbrella/translations/Translations.java
index e2ebc6c..8aa47ce 100644
--- a/translations/src/main/java/de/srsoftware/umbrella/translations/Translations.java
+++ b/translations/src/main/java/de/srsoftware/umbrella/translations/Translations.java
@@ -1,21 +1,17 @@
/* © SRSoftware 2025 */
package de.srsoftware.umbrella.translations;
-import static java.lang.System.Logger.Level.INFO;
import static java.lang.System.Logger.Level.WARNING;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.sun.net.httpserver.HttpExchange;
import de.srsoftware.tools.Path;
import de.srsoftware.tools.PathHandler;
-import org.json.JSONObject;
-
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URL;
-import java.nio.charset.StandardCharsets;
import java.util.HashMap;
-import java.util.Map;
+import org.json.JSONObject;
public class Translations extends PathHandler {
private static final System.Logger LOG = System.getLogger("Translations");
@@ -24,7 +20,6 @@ public class Translations extends PathHandler {
@Override
public boolean doGet(Path path, HttpExchange ex) throws IOException {
- LOG.log(INFO,"doGet({0},ex)",path);
allowOrigin(ex,"*");
if (path.empty())return sendContent(ex,501,"Language missing");
var lang = path.pop();
diff --git a/translations/src/main/resources/de.json b/translations/src/main/resources/de.json
index 79f1143..8e13952 100644
--- a/translations/src/main/resources/de.json
+++ b/translations/src/main/resources/de.json
@@ -1,5 +1,12 @@
{
- 'login' : {
- 'Login' : "Mist!"
+ "home" : {
+ "Welcome" : "Willkommen"
+ },
+ "login" : {
+ "do_login" : "anmelden",
+ "Email_or_Username": "Email oder Nutzername",
+ "Login" : "Anmeldung",
+ "OIDC_Login" : "Anmeldung mit OIDC",
+ "Password" : "Passwort"
}
}
\ No newline at end of file
diff --git a/user/build.gradle.kts b/user/build.gradle.kts
new file mode 100644
index 0000000..e21ca3b
--- /dev/null
+++ b/user/build.gradle.kts
@@ -0,0 +1,6 @@
+description = "Umbrella : User"
+
+dependencies{
+ implementation("de.srsoftware:tools.mime:1.1.2")
+ implementation("org.json:json:20240303")
+}
\ No newline at end of file
diff --git a/user/src/main/java/de/srsoftware/umbrella/user/UserModule.java b/user/src/main/java/de/srsoftware/umbrella/user/UserModule.java
new file mode 100644
index 0000000..2c7f736
--- /dev/null
+++ b/user/src/main/java/de/srsoftware/umbrella/user/UserModule.java
@@ -0,0 +1,54 @@
+/* © SRSoftware 2025 */
+package de.srsoftware.umbrella.user;
+
+import com.sun.net.httpserver.HttpExchange;
+import de.srsoftware.tools.MimeType;
+import de.srsoftware.tools.Path;
+import de.srsoftware.tools.PathHandler;
+import de.srsoftware.tools.SessionToken;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.UUID;
+
+import static de.srsoftware.tools.MimeType.MIME_JSON;
+
+
+public class UserModule extends PathHandler {
+
+ private HttpExchange addCors(HttpExchange ex){
+ var headers = ex.getResponseHeaders();
+ headers.add("Allow-Origin","*");
+ headers.add("Access-Control-Allow-Origin","*");
+ headers.add("Access-Control-Allow-Headers","Content-Type");
+ return ex;
+ }
+
+ @Override
+ public boolean doOptions(Path path, HttpExchange ex) throws IOException {
+ return sendEmptyResponse(200,addCors(ex));
+ }
+
+ @Override
+ public boolean doPost(Path path, HttpExchange ex) throws IOException {
+ addCors(ex);
+ var p = path.toString();
+ switch (p){
+ case "login": return postLogin(ex);
+ }
+ return super.doPost(path, ex);
+ }
+
+ private boolean postLogin(HttpExchange ex) throws IOException {
+ var json = json(ex);
+ if (!(json.has("username") && json.get("username") instanceof String username)) return sendContent(ex,402,"Username missing");
+ if (!(json.has("password") && json.get("password") instanceof String password)) return sendContent(ex,402,"Password missing");
+
+ if (!username.equals(password)) return sendContent(ex,401,"Login failed");
+ var sessionId = UUID.randomUUID().toString();
+ new SessionToken(sessionId).addTo(ex);
+ ex.getResponseHeaders().add("Content-Type", MIME_JSON);
+ return sendContent(ex,200,new JSONObject(Map.of("username",username)).toString());
+ }
+}
diff --git a/web/build.gradle.kts b/web/build.gradle.kts
index c2870d9..dae15cf 100644
--- a/web/build.gradle.kts
+++ b/web/build.gradle.kts
@@ -1,9 +1,5 @@
description = "Umbrella : Web"
-dependencies{
- implementation("de.srsoftware:tools.http:6.0.0")
-}
-
tasks.processResources {
System.out.println("Copying from dist…")
from("../frontend/dist") {