major refactoring: working towards more interface-implementation splitting

This commit is contained in:
2025-07-10 10:56:03 +02:00
parent d68dc991d0
commit 21812d2b42
22 changed files with 168 additions and 84 deletions

View File

@@ -1,4 +1,3 @@
import org.gradle.jvm.tasks.Jar import org.gradle.jvm.tasks.Jar
description = "Umbrella : Backend" description = "Umbrella : Backend"
@@ -22,6 +21,7 @@ dependencies{
implementation("de.srsoftware:configuration.api:1.0.2") implementation("de.srsoftware:configuration.api:1.0.2")
implementation("de.srsoftware:configuration.json:1.0.3") implementation("de.srsoftware:configuration.json:1.0.3")
implementation("de.srsoftware:tools.optionals:1.0.0") implementation("de.srsoftware:tools.optionals:1.0.0")
implementation("de.srsoftware:tools.slf4j2syslog:1.0.1") // this provides a slf4j implementation that forwards to System.Logger
implementation("de.srsoftware:tools.util:2.0.3") implementation("de.srsoftware:tools.util:2.0.3")
implementation("org.json:json:20240303") implementation("org.json:json:20240303")
} }

View File

@@ -4,22 +4,17 @@ package de.srsoftware.umbrella.backend;
import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.Constants.*;
import static de.srsoftware.umbrella.core.Util.mapLogLevel; import static de.srsoftware.umbrella.core.Util.mapLogLevel;
import static java.lang.System.Logger.Level.INFO; import static java.lang.System.Logger.Level.INFO;
import static java.text.MessageFormat.format;
import com.sun.net.httpserver.HttpServer; import com.sun.net.httpserver.HttpServer;
import de.srsoftware.configuration.JsonConfig; import de.srsoftware.configuration.JsonConfig;
import de.srsoftware.tools.ColorLogger; import de.srsoftware.tools.ColorLogger;
import de.srsoftware.umbrella.core.ConnectionProvider;
import de.srsoftware.umbrella.core.UmbrellaException; import de.srsoftware.umbrella.core.UmbrellaException;
import de.srsoftware.umbrella.documents.DocumentApi; import de.srsoftware.umbrella.documents.DocumentApi;
import de.srsoftware.umbrella.documents.SqliteDb;
import de.srsoftware.umbrella.legacy.LegacyApi; import de.srsoftware.umbrella.legacy.LegacyApi;
import de.srsoftware.umbrella.message.MessageApi; import de.srsoftware.umbrella.message.MessageApi;
import de.srsoftware.umbrella.message.MessageSystem; import de.srsoftware.umbrella.message.MessageSystem;
import de.srsoftware.umbrella.message.SqliteMessageDb;
import de.srsoftware.umbrella.translations.Translations; import de.srsoftware.umbrella.translations.Translations;
import de.srsoftware.umbrella.user.UserModule; import de.srsoftware.umbrella.user.UserModule;
import de.srsoftware.umbrella.user.sqlite.SqliteDB;
import de.srsoftware.umbrella.web.WebHandler; import de.srsoftware.umbrella.web.WebHandler;
import java.io.IOException; import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
@@ -29,7 +24,7 @@ import org.json.JSONObject;
public class Application { public class Application {
private static final System.Logger LOG = System.getLogger("Umbrella"); private static final System.Logger LOG = System.getLogger("Umbrella");
private static void configureLogging(JsonConfig jsonConfig) { private static JsonConfig configureLogging(JsonConfig jsonConfig) {
var rootLevel = jsonConfig.get("umbrella.logging.rootLevel", "INFO"); var rootLevel = jsonConfig.get("umbrella.logging.rootLevel", "INFO");
ColorLogger.setRootLogLevel(mapLogLevel(rootLevel)); ColorLogger.setRootLogLevel(mapLogLevel(rootLevel));
@@ -40,36 +35,33 @@ public class Application {
ColorLogger.setLogLevel(key,lvl); ColorLogger.setLogLevel(key,lvl);
}); });
} }
return jsonConfig;
} }
public static void main(String[] args) throws IOException, UmbrellaException { public static void main(String[] args) throws IOException, UmbrellaException {
LOG.log(INFO, "Starting Umbrella:"); LOG.log(INFO, "Starting Umbrella:");
var config = new JsonConfig(UMBRELLA); var config = configureLogging(new JsonConfig(UMBRELLA));
configureLogging(config); var port = config.get("umbrella.http.port", 8080);
var port = config.get("umbrella.http.port", 8080); var threads = config.get("umbrella.threads", 16);
var threads = config.get("umbrella.threads", 16);
var docDbFile = config.get("umbrella.database.documents",config.file().getParent()+"/documents.db"); var translationModule = new Translations();
var userDbFile = config.get("umbrella.database.user", config.file().getParent()+"/umbrella.db"); var messageSystem = new MessageSystem(translationModule,config);
var loginDbFile = config.get("umbrella.database.login_services",config.file().getParent()+"/umbrella.db"); var server = HttpServer.create(new InetSocketAddress(port), 0);
var messageDbFile = config.get("umbrella.database.messages", config.file().getParent()+"/umbrella.db");
var connectionProvider = new ConnectionProvider(); var userModule = new UserModule(config,messageSystem);
var documentDb = new SqliteDb(connectionProvider.get(docDbFile)); var documentApi = new DocumentApi(userModule, config);
var messageDb = new SqliteMessageDb(connectionProvider.get(messageDbFile)); var legacyApi = new LegacyApi(userModule.userDb(),config);
var userDb = new SqliteDB(connectionProvider.get(userDbFile)); var messageApi = new MessageApi(messageSystem);
var loginServiceDb = new SqliteDB(connectionProvider.get(loginDbFile)); var webHandler = new WebHandler();
var moduleConfig = config.subset("umbrella.modules").orElseThrow(() -> new RuntimeException(format(ERROR_MISSING_CONFIG,"umbrella.modules")));
var translationModule = new Translations(); documentApi .bindPath("/api/document") .on(server);
legacyApi .bindPath("/legacy") .on(server);
messageApi .bindPath("/api/messages") .on(server);
translationModule.bindPath("/api/translations").on(server);
userModule .bindPath("/api/user") .on(server);
webHandler .bindPath("/") .on(server);
var messageSystem = new MessageSystem(messageDb,translationModule,moduleConfig.subset("message").orElseThrow(() -> new RuntimeException(format(ERROR_MISSING_CONFIG,"umbrella.modules.message"))));
var server = HttpServer.create(new InetSocketAddress(port), 0);
server.setExecutor(Executors.newFixedThreadPool(threads)); server.setExecutor(Executors.newFixedThreadPool(threads));
var userModule = new UserModule(userDb,loginServiceDb,messageSystem);
new LegacyApi(userDb,config) .bindPath("/legacy") .on(server);
new DocumentApi(documentDb, userModule, moduleConfig) .bindPath("/api/document") .on(server);
new MessageApi(messageSystem).bindPath("/api/messages") .on(server);
translationModule .bindPath("/api/translations").on(server);
userModule .bindPath("/api/user") .on(server);
new WebHandler() .bindPath("/") .on(server);
server.start(); server.start();
LOG.log(INFO,"Started web server at {0}",port); LOG.log(INFO,"Started web server at {0}",port);
} }

6
company/build.gradle.kts Normal file
View File

@@ -0,0 +1,6 @@
description = "Umbrella : Companies"
dependencies{
implementation(project(":core"))
}

View File

@@ -0,0 +1,21 @@
/* © SRSoftware 2025 */
package de.srsoftware.umbrella.company;
import de.srsoftware.umbrella.core.api.CompanyService;
import de.srsoftware.umbrella.core.api.UserService;
import de.srsoftware.umbrella.core.model.UmbrellaUser;
import java.util.List;
public class CompanyModule implements CompanyService {
private final UserService users;
public CompanyModule(UserService userService){
users = userService;
}
@Override
public List<UmbrellaUser> getMembers(long companyId) {
return null;
}
}

View File

@@ -5,6 +5,7 @@ import static de.srsoftware.tools.Optionals.nullable;
import static java.lang.System.Logger.Level.DEBUG; import static java.lang.System.Logger.Level.DEBUG;
import static java.lang.System.Logger.Level.WARNING; import static java.lang.System.Logger.Level.WARNING;
import static java.net.HttpURLConnection.*; import static java.net.HttpURLConnection.*;
import static java.text.MessageFormat.format;
import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpExchange;
import de.srsoftware.tools.Path; import de.srsoftware.tools.Path;
@@ -73,4 +74,8 @@ public abstract class BaseHandler extends PathHandler {
public boolean unauthorized(HttpExchange ex) throws IOException { public boolean unauthorized(HttpExchange ex) throws IOException {
return sendEmptyResponse(HTTP_FORBIDDEN,ex); return sendEmptyResponse(HTTP_FORBIDDEN,ex);
} }
public boolean notImplemented(HttpExchange ex,String message,Object clazz) throws IOException{
return sendContent(ex,HTTP_NOT_IMPLEMENTED,format(message,clazz.getClass().getSimpleName()));
}
} }

View File

@@ -7,12 +7,17 @@ import java.sql.SQLException;
import java.util.HashMap; import java.util.HashMap;
import org.sqlite.SQLiteDataSource; import org.sqlite.SQLiteDataSource;
public class ConnectionProvider extends HashMap<File, Connection> { public class ConnectionProvider {
public Connection get(Object o) {
private static final HashMap<File, Connection> connections = new HashMap<>();
private ConnectionProvider(){}
public static Connection connect(Object o) {
if (o instanceof String filename) o = new File(filename); if (o instanceof String filename) o = new File(filename);
if (o instanceof File dbFile) try { if (o instanceof File dbFile) try {
var conn = super.get(dbFile); var conn = connections.get(dbFile);
if (conn == null) put(dbFile, conn = open(dbFile)); if (conn == null) connections.put(dbFile, conn = open(dbFile));
return conn; return conn;
} catch (SQLException sqle) { } catch (SQLException sqle) {
throw new RuntimeException(sqle); throw new RuntimeException(sqle);
@@ -20,7 +25,7 @@ public class ConnectionProvider extends HashMap<File, Connection> {
return null; return null;
} }
private Connection open(File dbFile) throws SQLException { private static Connection open(File dbFile) throws SQLException {
SQLiteDataSource dataSource = new SQLiteDataSource(); SQLiteDataSource dataSource = new SQLiteDataSource();
dataSource.setUrl("jdbc:sqlite:%s".formatted(dbFile)); dataSource.setUrl("jdbc:sqlite:%s".formatted(dbFile));
return dataSource.getConnection(); return dataSource.getConnection();

View File

@@ -1,19 +1,20 @@
/* © SRSoftware 2025 */ /* © SRSoftware 2025 */
package de.srsoftware.umbrella.core; package de.srsoftware.umbrella.core;
import static de.srsoftware.umbrella.core.ResponseCode.HTTP_SERVER_ERROR;
import static java.text.MessageFormat.format; import static java.text.MessageFormat.format;
public class UmbrellaException extends Exception{ public class UmbrellaException extends Exception{
private final int statusCode; private final int statusCode;
public UmbrellaException(int statusCode, String message){ public UmbrellaException(String message, Object ... fills){
super(message); this(HTTP_SERVER_ERROR,message,fills);
this.statusCode = statusCode;
} }
public UmbrellaException(int statusCode, String message, Object ... fills){ public UmbrellaException(int statusCode, String message, Object ... fills){
this(statusCode,format(message,fills)); super(format(message,fills));
this.statusCode = statusCode;
} }
public UmbrellaException causedBy(Exception e) { public UmbrellaException causedBy(Exception e) {

View File

@@ -0,0 +1,9 @@
/* © SRSoftware 2025 */
package de.srsoftware.umbrella.core.api;
import de.srsoftware.umbrella.core.model.UmbrellaUser;
import java.util.List;
public interface CompanyService {
public List<UmbrellaUser> getMembers(long companyId);
}

View File

@@ -2,12 +2,13 @@
package de.srsoftware.umbrella.core.api; package de.srsoftware.umbrella.core.api;
import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpExchange;
import de.srsoftware.umbrella.core.Token;
import de.srsoftware.umbrella.core.UmbrellaException; import de.srsoftware.umbrella.core.UmbrellaException;
import de.srsoftware.umbrella.core.model.Token;
import de.srsoftware.umbrella.core.model.UmbrellaUser; import de.srsoftware.umbrella.core.model.UmbrellaUser;
import java.util.Optional; import java.util.Optional;
public interface UserHelper { public interface UserService {
UmbrellaUser loadUser(long userId) throws UmbrellaException;
Optional<UmbrellaUser> loadUser(Optional<Token> sessionToken) throws UmbrellaException; Optional<UmbrellaUser> loadUser(Optional<Token> sessionToken) throws UmbrellaException;
Optional<UmbrellaUser> loadUser(HttpExchange ex) throws UmbrellaException; Optional<UmbrellaUser> loadUser(HttpExchange ex) throws UmbrellaException;
} }

View File

@@ -1,9 +1,7 @@
/* © SRSoftware 2025 */ /* © SRSoftware 2025 */
package de.srsoftware.umbrella.user.model; package de.srsoftware.umbrella.core.model;
import de.srsoftware.tools.SessionToken; import de.srsoftware.tools.SessionToken;
import de.srsoftware.umbrella.core.Token;
import de.srsoftware.umbrella.core.model.UmbrellaUser;
import java.time.Instant; import java.time.Instant;
/* © SRSoftware 2025 */ /* © SRSoftware 2025 */

View File

@@ -1,9 +1,10 @@
/* © SRSoftware 2025 */ /* © SRSoftware 2025 */
package de.srsoftware.umbrella.core; package de.srsoftware.umbrella.core.model;
import static de.srsoftware.umbrella.core.Constants.TOKEN; import static de.srsoftware.umbrella.core.Constants.TOKEN;
import de.srsoftware.tools.SessionToken; import de.srsoftware.tools.SessionToken;
import de.srsoftware.umbrella.core.AddableMap;
import java.util.UUID; import java.util.UUID;
public class Token implements CharSequence{ public class Token implements CharSequence{

View File

@@ -10,6 +10,8 @@ public class Constants {
private Constants(){} private Constants(){}
public static final Pattern POST_CODE = compile("(.*\\w+.*)\n(.*\\d+.*)\n(\\d{5}) (\\w+)",DOTALL); public static final Pattern POST_CODE = compile("(.*\\w+.*)\n(.*\\d+.*)\n(\\d{5}) (\\w+)",DOTALL);
public static final String CONFIG_DATABASE = "umbrella.modules.document.database";
public static final String CONTACTS = "contacts"; public static final String CONTACTS = "contacts";
public static final String CUSTOMER_NUMBER_PREFIX = "customer_number_prefix"; public static final String CUSTOMER_NUMBER_PREFIX = "customer_number_prefix";

View File

@@ -2,10 +2,12 @@
package de.srsoftware.umbrella.documents; package de.srsoftware.umbrella.documents;
import static de.srsoftware.tools.MimeType.MIME_FORM_URL; import static de.srsoftware.tools.MimeType.MIME_FORM_URL;
import static de.srsoftware.umbrella.core.ConnectionProvider.connect;
import static de.srsoftware.umbrella.core.Constants.ERROR_MISSING_FIELD; import static de.srsoftware.umbrella.core.Constants.ERROR_MISSING_FIELD;
import static de.srsoftware.umbrella.core.Paths.LIST; import static de.srsoftware.umbrella.core.Paths.LIST;
import static de.srsoftware.umbrella.core.Util.request; import static de.srsoftware.umbrella.core.Util.request;
import static de.srsoftware.umbrella.documents.Constants.*; import static de.srsoftware.umbrella.documents.Constants.*;
import static java.lang.System.Logger.Level.DEBUG;
import static java.lang.System.Logger.Level.WARNING; import static java.lang.System.Logger.Level.WARNING;
import static java.net.HttpURLConnection.HTTP_BAD_REQUEST; import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
@@ -14,29 +16,29 @@ import de.srsoftware.configuration.Configuration;
import de.srsoftware.tools.Path; import de.srsoftware.tools.Path;
import de.srsoftware.tools.SessionToken; import de.srsoftware.tools.SessionToken;
import de.srsoftware.umbrella.core.BaseHandler; import de.srsoftware.umbrella.core.BaseHandler;
import de.srsoftware.umbrella.core.Token;
import de.srsoftware.umbrella.core.UmbrellaException; import de.srsoftware.umbrella.core.UmbrellaException;
import de.srsoftware.umbrella.core.api.UserHelper; import de.srsoftware.umbrella.core.api.UserService;
import de.srsoftware.umbrella.core.model.Token;
import de.srsoftware.umbrella.core.model.UmbrellaUser; import de.srsoftware.umbrella.core.model.UmbrellaUser;
import de.srsoftware.umbrella.documents.model.Type;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import de.srsoftware.umbrella.documents.model.Type;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
public class DocumentApi extends BaseHandler { public class DocumentApi extends BaseHandler {
private final UserHelper users; private final UserService users;
private final Configuration config; private final Configuration config;
private final DocumentDb db; private final DocumentDb db;
public DocumentApi(DocumentDb documentDb, UserHelper userHelper, Configuration moduleConfig){ public DocumentApi(UserService userHelper, Configuration config) throws UmbrellaException {
config = moduleConfig; this.config = config;
db = documentDb; var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> new UmbrellaException(ERROR_MISSING_FIELD,CONFIG_DATABASE));
db = new SqliteDb(connect(dbFile));
users = userHelper; users = userHelper;
} }
@@ -69,7 +71,8 @@ public class DocumentApi extends BaseHandler {
var head = path.pop(); var head = path.pop();
return switch (head){ return switch (head){
case LIST -> listDocuments(ex,user.get(),token.orElse(null)); case LIST -> listDocuments(ex,user.get(),token.orElse(null));
case null, default -> super.doPost(path,ex); case null -> postDocument(ex,user.get());
default -> super.doPost(path,ex);
}; };
} catch (UmbrellaException e) { } catch (UmbrellaException e) {
return send(ex,e); return send(ex,e);
@@ -89,17 +92,17 @@ public class DocumentApi extends BaseHandler {
var map = types.values().stream().collect(Collectors.toMap(Type::id, Type::name)); var map = types.values().stream().collect(Collectors.toMap(Type::id, Type::name));
return sendContent(ex,map); return sendContent(ex,map);
} }
private HashMap<Long, Map<String, Object>> getLegacyCompanies(HttpExchange ex, UmbrellaUser umbrellaUser, Token token) throws IOException, UmbrellaException { private HashMap<Long, Map<String, Object>> getLegacyCompanies(HttpExchange ex, UmbrellaUser umbrellaUser, Token token) throws IOException, UmbrellaException {
var location = config.get("company.baseUrl").map(s -> s+"/json").orElseThrow(() -> new UmbrellaException(500,"umbrella.modules.company.baseUrl not configured!")); var location = config.get("umbrella.modules.company.baseUrl").map(s -> s+"/json").orElseThrow(() -> new UmbrellaException(500,"umbrella.modules.company.baseUrl not configured!"));
var resp = request(location, token.asMap(),MIME_FORM_URL,null); var resp = request(location, token.asMap(),MIME_FORM_URL,null);
if (!(resp instanceof JSONObject json)) throw new UmbrellaException(500,"{0} did not return JSON!",location); if (!(resp instanceof JSONObject json)) throw new UmbrellaException(500,"{0} did not return JSON!",location);
var result = new HashMap<Long, Map<String,Object>>(); var result = new HashMap<Long, Map<String,Object>>();
for (var key : json.keySet()) result.put(Long.parseLong(key),json.getJSONObject(key).toMap()); for (var key : json.keySet()) result.put(Long.parseLong(key),json.getJSONObject(key).toMap());
return result; return result;
} }
private JSONArray getLegacyContacts(HttpExchange ex, UmbrellaUser umbrellaUser, Token token) throws IOException, UmbrellaException { private JSONArray getLegacyContacts(HttpExchange ex, UmbrellaUser umbrellaUser, Token token) throws IOException, UmbrellaException {
var location = config.get("contact.baseUrl").map(s -> s+"/json").orElseThrow(() -> new UmbrellaException(500,"umbrella.modules.company.baseUrl not configured!")); var location = config.get("umbrella.modules.contact.baseUrl").map(s -> s+"/json").orElseThrow(() -> new UmbrellaException(500,"umbrella.modules.contact.baseUrl not configured!"));
var resp = request(location, token.asMap(),MIME_FORM_URL,null); var resp = request(location, token.asMap(),MIME_FORM_URL,null);
if (!(resp instanceof String s && s.startsWith("["))) throw new UmbrellaException(500,"{0} did not return JSON Array!",location); if (!(resp instanceof String s && s.startsWith("["))) throw new UmbrellaException(500,"{0} did not return JSON Array!",location);
return new JSONArray(s); return new JSONArray(s);
@@ -122,4 +125,18 @@ public class DocumentApi extends BaseHandler {
throw new UmbrellaException( 500,"Failed to parse JSON data from request").causedBy(e); throw new UmbrellaException( 500,"Failed to parse JSON data from request").causedBy(e);
} }
} }
private boolean postDocument(HttpExchange ex, UmbrellaUser umbrellaUser) throws IOException, UmbrellaException {
var json = json(ex);
if (!(json.has(COMPANY) && json.get(COMPANY) instanceof String cid) || cid.isBlank()) throw new UmbrellaException(HTTP_BAD_REQUEST,ERROR_MISSING_FIELD,COMPANY);
long companyId;
try {
companyId = Long.parseLong(cid);
} catch (NumberFormatException nfe){
throw new UmbrellaException(HTTP_BAD_REQUEST,nfe.getMessage());
}
LOG.log(DEBUG,json.toString(2));
return notImplemented(ex,"{0}.postDocument(…)",this);
}
} }

View File

@@ -19,11 +19,11 @@ import de.srsoftware.configuration.Configuration;
import de.srsoftware.tools.Path; import de.srsoftware.tools.Path;
import de.srsoftware.tools.SessionToken; import de.srsoftware.tools.SessionToken;
import de.srsoftware.umbrella.core.BaseHandler; import de.srsoftware.umbrella.core.BaseHandler;
import de.srsoftware.umbrella.core.Token;
import de.srsoftware.umbrella.core.UmbrellaException; import de.srsoftware.umbrella.core.UmbrellaException;
import de.srsoftware.umbrella.core.model.Session;
import de.srsoftware.umbrella.core.model.Token;
import de.srsoftware.umbrella.core.model.UmbrellaUser; import de.srsoftware.umbrella.core.model.UmbrellaUser;
import de.srsoftware.umbrella.user.model.Session; import de.srsoftware.umbrella.user.api.UserDb;
import de.srsoftware.umbrella.user.sqlite.SqliteDB;
import java.io.IOException; import java.io.IOException;
import java.time.Instant; import java.time.Instant;
import java.util.*; import java.util.*;
@@ -32,11 +32,11 @@ import org.json.JSONObject;
public class LegacyApi extends BaseHandler { public class LegacyApi extends BaseHandler {
private final SqliteDB users; private final UserDb users;
private final Configuration config; private final Configuration config;
private final String messageUrl; private final String messageUrl;
public LegacyApi(SqliteDB userDb, Configuration config) { public LegacyApi(UserDb userDb, Configuration config) {
users = userDb; users = userDb;
this.config = config.subset("umbrella.modules").orElseThrow(() -> new RuntimeException("Missing configuration: umbrella.modules")); this.config = config.subset("umbrella.modules").orElseThrow(() -> new RuntimeException("Missing configuration: umbrella.modules"));
this.messageUrl = null; this.messageUrl = null;

View File

@@ -3,6 +3,13 @@ package de.srsoftware.umbrella.message;
public class Constants { public class Constants {
public static final String AUTH = "mail.smtp.auth"; public static final String AUTH = "mail.smtp.auth";
public static final String CONFIG_DB = "umbrella.modules.message.database";
public static final String CONFIG_SMTP_HOST = "umbrella.modules.message.smtp.host";
public static final String CONFIG_SMTP_PASS = "umbrella.modules.message.smtp.pass";
public static final String CONFIG_SMTP_PORT = "umbrella.modules.message.smtp.port";
public static final String CONFIG_SMTP_USER = "umbrella.modules.message.smtp.user";
public static final String DEBUG_ADDREESS = "debug_addres"; public static final String DEBUG_ADDREESS = "debug_addres";
public static final String ENVELOPE_FROM = "mail.smtp.from"; public static final String ENVELOPE_FROM = "mail.smtp.from";
public static final String FIELD_MESSAGES = "messages"; public static final String FIELD_MESSAGES = "messages";
@@ -13,7 +20,6 @@ public class Constants {
public static final String JSONOBJECT = "json object"; public static final String JSONOBJECT = "json object";
public static final String PORT = "mail.smtp.port"; public static final String PORT = "mail.smtp.port";
public static final String RECEIVERS = "receivers"; public static final String RECEIVERS = "receivers";
public static final String SMTP = "smtp";
public static final String SSL = "mail.smtp.ssl.enable"; public static final String SSL = "mail.smtp.ssl.enable";
public static final String SUBMISSION = "submission"; public static final String SUBMISSION = "submission";

View File

@@ -2,6 +2,7 @@
package de.srsoftware.umbrella.message; package de.srsoftware.umbrella.message;
import static de.srsoftware.tools.PathHandler.CONTENT_TYPE; import static de.srsoftware.tools.PathHandler.CONTENT_TYPE;
import static de.srsoftware.umbrella.core.ConnectionProvider.connect;
import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.Constants.*;
import static de.srsoftware.umbrella.message.Constants.*; import static de.srsoftware.umbrella.message.Constants.*;
import static java.lang.System.Logger.Level.*; import static java.lang.System.Logger.Level.*;
@@ -68,15 +69,16 @@ public class MessageSystem implements PostBox {
private final HashMap<Receiver,List<Exception>> exceptions = new HashMap<>(); private final HashMap<Receiver,List<Exception>> exceptions = new HashMap<>();
private final Translator translator; private final Translator translator;
public MessageSystem(SqliteMessageDb messageDb, Translator translator, Configuration config) { public MessageSystem(Translator translator, Configuration config) throws UmbrellaException {
db = messageDb; var messageDbFile = config.get(CONFIG_DB).orElseThrow(() -> new UmbrellaException(500,ERROR_MISSING_CONFIG,CONFIG_DB));
db = new SqliteMessageDb(connect(messageDbFile));
this.translator = translator; this.translator = translator;
debugAddress = config.get(DEBUG_ADDREESS).map(Object::toString).orElse(null); debugAddress = config.get(DEBUG_ADDREESS).map(Object::toString).orElse(null);
config = config.subset(SMTP).orElseThrow(() -> new RuntimeException("umbrella.modules.message.smtp not configured!")); port = config.get(CONFIG_SMTP_PORT,587);
port = config.get(FIELD_PORT,587); host = config.get(CONFIG_SMTP_HOST).map(Object::toString).orElseThrow(() -> new RuntimeException("umbrella.modules.message.smtp.host not configured!"));
host = config.get(FIELD_HOST).map(Object::toString).orElseThrow(() -> new RuntimeException("umbrella.modules.message.smtp.host not configured!")); user = config.get(CONFIG_SMTP_USER).map(Object::toString).orElseThrow(() -> new RuntimeException("umbrella.modules.message.smtp.user not configured!"));
user = config.get(USER).map(Object::toString).orElseThrow(() -> new RuntimeException("umbrella.modules.message.smtp.user not configured!")); pass = config.get(CONFIG_SMTP_PASS).map(Object::toString).orElseThrow(() -> new RuntimeException("umbrella.modules.message.smtp.pass not configured!"));
pass = config.get(PASS).map(Object::toString).orElseThrow(() -> new RuntimeException("umbrella.modules.message.smtp.pass not configured!"));
from = user; from = user;
new SubmissionTask(8).schedule(); new SubmissionTask(8).schedule();
new SubmissionTask(10).schedule(); new SubmissionTask(10).schedule();

View File

@@ -2,10 +2,11 @@ rootProject.name = "Umbrella25"
include("backend") include("backend")
include("core") include("core")
include("documents")
include("legacy") include("legacy")
include("messages") include("messages")
include("translations") include("translations")
include("user") include("user")
include("web") include("web")
include("documents") include("company")

View File

@@ -10,7 +10,7 @@
"list_of": "Dokumente von {0}", "list_of": "Dokumente von {0}",
"number": "Nummer", "number": "Nummer",
"select_company" : "Wählen Sie eine ihrer Firmen:", "select_company" : "Wählen Sie eine ihrer Firmen:",
"select customer": "Kunde auswählen", "select_customer": "Kunde auswählen",
"sender": "Absender", "sender": "Absender",
"state": "Status", "state": "Status",
"state_declined": "abgelehnt", "state_declined": "abgelehnt",

View File

@@ -12,6 +12,7 @@ public class Constants {
public static final String CLIENT_ID = "client_id"; public static final String CLIENT_ID = "client_id";
public static final String CLIENT_SECRET = "client_secret"; public static final String CLIENT_SECRET = "client_secret";
public static final String CODE = "code"; public static final String CODE = "code";
public static final String CONFIG_DATABASE = "umbrella.modules.user.database";
public static final String DB_VERSION = "user_db_version"; public static final String DB_VERSION = "user_db_version";

View File

@@ -4,6 +4,7 @@ package de.srsoftware.umbrella.user;
import static de.srsoftware.tools.MimeType.MIME_FORM_URL; import static de.srsoftware.tools.MimeType.MIME_FORM_URL;
import static de.srsoftware.tools.Optionals.*; import static de.srsoftware.tools.Optionals.*;
import static de.srsoftware.tools.Strings.uuid; import static de.srsoftware.tools.Strings.uuid;
import static de.srsoftware.umbrella.core.ConnectionProvider.connect;
import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.Constants.*;
import static de.srsoftware.umbrella.core.Paths.LIST; import static de.srsoftware.umbrella.core.Paths.LIST;
import static de.srsoftware.umbrella.core.Paths.LOGOUT; import static de.srsoftware.umbrella.core.Paths.LOGOUT;
@@ -24,13 +25,14 @@ import static java.time.temporal.ChronoUnit.DAYS;
import static java.util.Optional.empty; import static java.util.Optional.empty;
import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpExchange;
import de.srsoftware.configuration.Configuration;
import de.srsoftware.tools.Path; import de.srsoftware.tools.Path;
import de.srsoftware.tools.SessionToken; import de.srsoftware.tools.SessionToken;
import de.srsoftware.umbrella.core.BaseHandler; import de.srsoftware.umbrella.core.BaseHandler;
import de.srsoftware.umbrella.core.Token;
import de.srsoftware.umbrella.core.UmbrellaException; import de.srsoftware.umbrella.core.UmbrellaException;
import de.srsoftware.umbrella.core.api.UserHelper; import de.srsoftware.umbrella.core.api.UserService;
import de.srsoftware.umbrella.core.model.EmailAddress; import de.srsoftware.umbrella.core.model.EmailAddress;
import de.srsoftware.umbrella.core.model.Token;
import de.srsoftware.umbrella.core.model.UmbrellaUser; import de.srsoftware.umbrella.core.model.UmbrellaUser;
import de.srsoftware.umbrella.message.MessageSystem; import de.srsoftware.umbrella.message.MessageSystem;
import de.srsoftware.umbrella.message.model.Envelope; import de.srsoftware.umbrella.message.model.Envelope;
@@ -38,6 +40,9 @@ import de.srsoftware.umbrella.message.model.Message;
import de.srsoftware.umbrella.user.api.LoginServiceDb; import de.srsoftware.umbrella.user.api.LoginServiceDb;
import de.srsoftware.umbrella.user.api.UserDb; import de.srsoftware.umbrella.user.api.UserDb;
import de.srsoftware.umbrella.user.model.*; import de.srsoftware.umbrella.user.model.*;
import de.srsoftware.umbrella.user.model.DbUser;
import de.srsoftware.umbrella.user.model.Password;
import de.srsoftware.umbrella.user.sqlite.SqliteDB;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.net.*; import java.net.*;
@@ -53,7 +58,7 @@ import org.jose4j.keys.resolvers.HttpsJwksVerificationKeyResolver;
import org.json.JSONObject; import org.json.JSONObject;
public class UserModule extends BaseHandler implements UserHelper { public class UserModule extends BaseHandler implements UserService {
private record State(LoginService loginService, JSONObject config){ private record State(LoginService loginService, JSONObject config){
@@ -78,13 +83,17 @@ public class UserModule extends BaseHandler implements UserHelper {
} }
} }
public UserModule(UserDb userDb, LoginServiceDb loginDb, MessageSystem messageSystem){ public UserModule(Configuration config, MessageSystem messageSystem) throws UmbrellaException {
logins = loginDb; var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> new UmbrellaException(ERROR_MISSING_CONFIG,CONFIG_DATABASE));
// may be splitted in separate db files later
logins = new SqliteDB(connect(dbFile));
messages = messageSystem; messages = messageSystem;
users = userDb; users = new SqliteDB(connect(dbFile));
} }
public UserDb userDb(){
return users;
}
private boolean deleteOIDC(HttpExchange ex, UmbrellaUser user, Path path) throws IOException { private boolean deleteOIDC(HttpExchange ex, UmbrellaUser user, Path path) throws IOException {
var head = path.pop(); var head = path.pop();
@@ -126,6 +135,11 @@ public class UserModule extends BaseHandler implements UserHelper {
} }
} }
@Override
public UmbrellaUser loadUser(long userId) throws UmbrellaException {
return users.load(userId);
}
public Optional<UmbrellaUser> loadUser(Optional<Token> sessionToken) throws UmbrellaException { public Optional<UmbrellaUser> loadUser(Optional<Token> sessionToken) throws UmbrellaException {
if (sessionToken.isEmpty()) return empty(); if (sessionToken.isEmpty()) return empty();
var session = users.load(sessionToken.get()); var session = users.load(sessionToken.get());

View File

@@ -1,13 +1,13 @@
/* © SRSoftware 2025 */ /* © SRSoftware 2025 */
package de.srsoftware.umbrella.user.api; package de.srsoftware.umbrella.user.api;
import de.srsoftware.umbrella.core.Token;
import de.srsoftware.umbrella.core.UmbrellaException; import de.srsoftware.umbrella.core.UmbrellaException;
import de.srsoftware.umbrella.core.model.EmailAddress; import de.srsoftware.umbrella.core.model.EmailAddress;
import de.srsoftware.umbrella.core.model.Session;
import de.srsoftware.umbrella.core.model.Token;
import de.srsoftware.umbrella.core.model.UmbrellaUser; import de.srsoftware.umbrella.core.model.UmbrellaUser;
import de.srsoftware.umbrella.user.model.DbUser; import de.srsoftware.umbrella.user.model.DbUser;
import de.srsoftware.umbrella.user.model.Password; import de.srsoftware.umbrella.user.model.Password;
import de.srsoftware.umbrella.user.model.Session;
import java.util.List; import java.util.List;
public interface UserDb { public interface UserDb {

View File

@@ -12,15 +12,17 @@ import static java.text.MessageFormat.format;
import de.srsoftware.tools.PasswordHasher; import de.srsoftware.tools.PasswordHasher;
import de.srsoftware.tools.jdbc.Query; import de.srsoftware.tools.jdbc.Query;
import de.srsoftware.umbrella.core.Token;
import de.srsoftware.umbrella.core.UmbrellaException; import de.srsoftware.umbrella.core.UmbrellaException;
import de.srsoftware.umbrella.core.model.EmailAddress; import de.srsoftware.umbrella.core.model.EmailAddress;
import de.srsoftware.umbrella.core.model.Session;
import de.srsoftware.umbrella.core.model.Token;
import de.srsoftware.umbrella.core.model.UmbrellaUser; import de.srsoftware.umbrella.core.model.UmbrellaUser;
import de.srsoftware.umbrella.user.BadHasher; import de.srsoftware.umbrella.user.BadHasher;
import de.srsoftware.umbrella.user.api.LoginServiceDb; import de.srsoftware.umbrella.user.api.LoginServiceDb;
import de.srsoftware.umbrella.user.api.UserDb; import de.srsoftware.umbrella.user.api.UserDb;
import de.srsoftware.umbrella.user.model.*; import de.srsoftware.umbrella.user.model.*;
import de.srsoftware.umbrella.user.model.Session; import de.srsoftware.umbrella.user.model.DbUser;
import de.srsoftware.umbrella.user.model.Password;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.sql.Connection; import java.sql.Connection;
import java.sql.ResultSet; import java.sql.ResultSet;