diff --git a/Svelte/Dockerfile b/Svelte/Dockerfile index 5be83cac..91916bf5 100644 --- a/Svelte/Dockerfile +++ b/Svelte/Dockerfile @@ -1,8 +1,11 @@ FROM alpine:3.22 LABEL Maintainer "Stephan Richter " +ARG UID=1000 +ARG GID=1000 RUN apk add bash npm -RUN adduser -Dh /home/svelte svelte +RUN set -x; addgroup -g $GID svelte +RUN adduser -u $UID -G svelte -Dh /home/svelte svelte ADD script /opt USER svelte WORKDIR /home/svelte -CMD /bin/bash \ No newline at end of file +CMD /bin/bash diff --git a/Svelte/Makefile b/Svelte/Makefile index a6320989..8fd486f6 100644 --- a/Svelte/Makefile +++ b/Svelte/Makefile @@ -1,16 +1,18 @@ default: devel build: image - docker run --name svelte-build \ + podman run --name svelte-build \ --rm \ + --userns=keep-id:uid=$$(id -u),gid=$$(id -g) \ -v ../frontend:/home/svelte/frontend \ -ti svelte /opt/svelte-build image: - docker build -t svelte . + podman build --build-arg UID=$$(id -u) --build-arg GID=$$(id -g) -t svelte . devel: image - -docker rm -f svelte - docker run --name svelte \ + -podman rm -f svelte + podman run --name svelte \ + --userns=keep-id:uid=$$(id -u),gid=$$(id -g) \ -v ../frontend:/home/svelte/frontend \ -p 5173:5173 \ -ti svelte /opt/svelte-init 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 a6379dd2..33342231 100644 --- a/backend/src/main/java/de/srsoftware/umbrella/backend/Application.java +++ b/backend/src/main/java/de/srsoftware/umbrella/backend/Application.java @@ -1,8 +1,8 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.backend; -import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.Util.mapLogLevel; +import static de.srsoftware.umbrella.core.constants.Constants.UMBRELLA; import static java.lang.System.Logger.Level.ERROR; import static java.lang.System.Logger.Level.INFO; diff --git a/bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/BookmarkApi.java b/bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/BookmarkApi.java index eea9fab5..2bc1f5db 100644 --- a/bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/BookmarkApi.java +++ b/bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/BookmarkApi.java @@ -3,11 +3,13 @@ package de.srsoftware.umbrella.bookmarks; import static de.srsoftware.umbrella.bookmarks.Constants.*; import static de.srsoftware.umbrella.core.ConnectionProvider.connect; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.Paths.LIST; -import static de.srsoftware.umbrella.core.Paths.SEARCH; import static de.srsoftware.umbrella.core.Util.mapValues; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Field.TAGS; +import static de.srsoftware.umbrella.core.constants.Module.BOOKMARK; +import static de.srsoftware.umbrella.core.constants.Path.LIST; +import static de.srsoftware.umbrella.core.constants.Path.SEARCH; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; import static java.net.HttpURLConnection.HTTP_BAD_REQUEST; import com.sun.net.httpserver.HttpExchange; @@ -32,9 +34,9 @@ public class BookmarkApi extends BaseHandler implements BookmarkService { public BookmarkApi(Configuration config) { super(); - var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE)); + var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingField(CONFIG_DATABASE)); db = new SqliteDb(connect(dbFile)); - ModuleRegistry.add(this); + ModuleRegistry.add(this); } @Override @@ -110,13 +112,13 @@ public class BookmarkApi extends BaseHandler implements BookmarkService { private boolean postBookmark(UmbrellaUser user, HttpExchange ex) throws IOException { var json = json(ex); - if (!(json.has(URL) && json.get(URL) instanceof String url)) throw missingFieldException(URL); - if (!(json.has(COMMENT) && json.get(COMMENT) instanceof String comment)) throw missingFieldException(COMMENT); + if (!(json.has(URL) && json.get(URL) instanceof String url)) throw missingField(URL); + if (!(json.has(COMMENT) && json.get(COMMENT) instanceof String comment)) throw missingField(COMMENT); var userList = new ArrayList(); userList.add(user.id()); if (json.has(SHARE) && json.get(SHARE) instanceof JSONArray arr){ for (Object o : arr.toList()) { - if (!(o instanceof Number uid)) throw UmbrellaException.invalidFieldException(SHARE,"Array of ids"); + if (!(o instanceof Number uid)) throw invalidField(SHARE,"Array of ids"); userList.add(uid.longValue()); } } @@ -131,7 +133,7 @@ public class BookmarkApi extends BaseHandler implements BookmarkService { private boolean postSearch(UmbrellaUser user, HttpExchange ex) throws IOException { var json = json(ex); - if (!(json.has(KEY) && json.get(KEY) instanceof String key)) throw missingFieldException(KEY); + if (!(json.has(KEY) && json.get(KEY) instanceof String key)) throw missingField(KEY); var keys = Arrays.asList(key.split(" ")); var fulltext = json.has(FULLTEXT) && json.get(FULLTEXT) instanceof Boolean val && val; var bookmarks = db.findUrls(user.id(),keys); diff --git a/bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/SqliteDb.java b/bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/SqliteDb.java index d6c471c2..d63f6d10 100644 --- a/bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/SqliteDb.java +++ b/bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/SqliteDb.java @@ -6,15 +6,16 @@ import static de.srsoftware.tools.jdbc.Condition.like; import static de.srsoftware.tools.jdbc.Query.*; import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL; import static de.srsoftware.umbrella.bookmarks.Constants.*; -import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.Errors.*; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseException; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.notFound; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Text.BOOKMARK; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; import static java.text.MessageFormat.format; import static java.time.ZoneOffset.UTC; import de.srsoftware.umbrella.core.BaseDb; import de.srsoftware.umbrella.core.model.Bookmark; +import de.srsoftware.umbrella.core.model.Translatable; import java.sql.Connection; import java.sql.SQLException; import java.time.LocalDateTime; @@ -48,7 +49,7 @@ CREATE TABLE IF NOT EXISTS {0} ( PRIMARY KEY (`{1}`,`{2}`) )"""; try { - var stmt = db.prepareStatement(format(sql,TABLE_URL_COMMENTS,URL_ID,USER_ID,COMMENT,TIMESTAMP)); + var stmt = db.prepareStatement(format(sql,TABLE_URL_COMMENTS,URL_ID, USER_ID, COMMENT,TIMESTAMP)); stmt.execute(); stmt.close(); } catch (SQLException e) { @@ -63,7 +64,7 @@ CREATE TABLE IF NOT EXISTS {0} ( stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_URLS).causedBy(e); + throw failedToCreateTable(TABLE_URLS).causedBy(e); } } @@ -76,7 +77,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close();; return map; } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_ENTITY,"bookmark list").causedBy(e); + throw failedToLoadObject("bookmark list").causedBy(e); } } @@ -84,7 +85,7 @@ CREATE TABLE IF NOT EXISTS {0} ( public Map findUrls(long userId, Collection keys) { try { var map = new HashMap(); - var query = select(ALL).from(TABLE_URL_COMMENTS).leftJoin(URL_ID,TABLE_URLS,ID) + var query = select(ALL).from(TABLE_URL_COMMENTS).leftJoin(URL_ID,TABLE_URLS, ID) .where(USER_ID, equal(userId)); for (var key : keys) query.where(COMMENT,like("%"+key+"%")); var rs = query.sort(format("{0} DESC",TIMESTAMP)).exec(db); @@ -95,7 +96,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close();; return map; } catch (SQLException e) { - throw databaseException(FAILED_TO_DROP_ENTITY,"bookmark list").causedBy(e); + throw failedToDropObject("bookmark list").causedBy(e); } } @@ -103,7 +104,7 @@ CREATE TABLE IF NOT EXISTS {0} ( public Map list(long userId, Long offset, Long limit) { try { var map = new HashMap(); - var rs = select(ALL).from(TABLE_URL_COMMENTS).leftJoin(URL_ID,TABLE_URLS,ID).where(USER_ID, equal(userId)).sort(format("{0} DESC",TIMESTAMP)).skip(offset).limit(limit).exec(db); + var rs = select(ALL).from(TABLE_URL_COMMENTS).leftJoin(URL_ID,TABLE_URLS, ID).where(USER_ID, equal(userId)).sort(format("{0} DESC",TIMESTAMP)).skip(offset).limit(limit).exec(db); while (rs.next()){ var bookmark = Bookmark.of(rs); map.put(bookmark.urlId(),bookmark); @@ -111,7 +112,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close();; return map; } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_ENTITY,"bookmark list").causedBy(e); + throw failedToLoadObject("bookmark list").causedBy(e); } } @@ -123,9 +124,9 @@ CREATE TABLE IF NOT EXISTS {0} ( if (rs.next()) result = Bookmark.of(rs); rs.close(); if (result != null) return result; - throw notFound(NO_BOOKMARK_FOR_URLID,id); + throw failedToLoadObject(Translatable.t(BOOKMARK),id); } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_ENTITY,"bookmark").causedBy(e); + throw failedToLoadObject(Translatable.t(BOOKMARK),id).causedBy(e); } } @@ -143,12 +144,12 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); stmt.close(); } - var query = replaceInto(TABLE_URL_COMMENTS,URL_ID,USER_ID,COMMENT, TIMESTAMP); + var query = replaceInto(TABLE_URL_COMMENTS,URL_ID, USER_ID, COMMENT, TIMESTAMP); for (long userId : userIds) query.values(urlId,userId,comment,timestamp.toEpochSecond(UTC)); query.execute(db).close(); return Bookmark.of(urlId,url,comment,timestamp); } catch (SQLException e) { - throw databaseException(FAILED_TO_STORE_ENTITY,"url").causedBy(e); + throw failedToStoreObject(this).causedBy(e); } } } diff --git a/bus/src/main/java/de/srsoftware/umbrella/messagebus/MessageApi.java b/bus/src/main/java/de/srsoftware/umbrella/messagebus/MessageApi.java index 4ff7291f..36b12119 100644 --- a/bus/src/main/java/de/srsoftware/umbrella/messagebus/MessageApi.java +++ b/bus/src/main/java/de/srsoftware/umbrella/messagebus/MessageApi.java @@ -1,8 +1,9 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.messagebus; -import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.ModuleRegistry.userService; +import static de.srsoftware.umbrella.core.constants.Constants.*; +import static de.srsoftware.umbrella.core.constants.Field.*; import static java.lang.System.Logger.Level.*; import static java.lang.Thread.sleep; import static java.net.HttpURLConnection.HTTP_OK; @@ -35,8 +36,8 @@ public class MessageApi extends BaseHandler{ var addr = ex.getRemoteAddress(); headers.add(CONTENT_TYPE, MimeType.MIME_EVENT_STREAM); - headers.add(CACHE_CONTROL,NO_CACHE); - headers.add(CONNECTION,KEEP_ALIVE); + headers.add(CACHE_CONTROL, NO_CACHE); + headers.add(CONNECTION, KEEP_ALIVE); headers.add(CONTENT_ENCODING,NONE); ex.sendResponseHeaders(HTTP_OK,0); try (var os = ex.getResponseBody(); var stream = new PrintWriter(os); var eventQueue = new EventQueue(addr)){ @@ -58,7 +59,7 @@ public class MessageApi extends BaseHandler{ LOG.log(INFO,"{0} disconnected from event stream.",addr); return true; } catch (InterruptedException e) { - throw new UmbrellaException("EventStream broken").causedBy(e); + throw UmbrellaException.serverError("EventStream broken").causedBy(e); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/bus/src/main/java/de/srsoftware/umbrella/messagebus/events/Event.java b/bus/src/main/java/de/srsoftware/umbrella/messagebus/events/Event.java index c7f7029f..47ea805f 100644 --- a/bus/src/main/java/de/srsoftware/umbrella/messagebus/events/Event.java +++ b/bus/src/main/java/de/srsoftware/umbrella/messagebus/events/Event.java @@ -1,7 +1,7 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.messagebus.events; -import static de.srsoftware.umbrella.core.Constants.USER; +import static de.srsoftware.umbrella.core.constants.Field.USER; import de.srsoftware.tools.Mappable; import de.srsoftware.umbrella.core.model.UmbrellaUser; @@ -18,12 +18,12 @@ public abstract class Event { } private UmbrellaUser initiator; - private String realm; + private String module; private Payload payload; private EventType eventType; - public Event(UmbrellaUser initiator, String realm, Payload payload, EventType type){ + public Event(UmbrellaUser initiator, String module, Payload payload, EventType type){ this.initiator = initiator; - this.realm = realm; + this.module = module; this.payload = payload; this.eventType = type; } diff --git a/bus/src/main/java/de/srsoftware/umbrella/messagebus/events/ProjectEvent.java b/bus/src/main/java/de/srsoftware/umbrella/messagebus/events/ProjectEvent.java index 6ef424b3..93b44049 100644 --- a/bus/src/main/java/de/srsoftware/umbrella/messagebus/events/ProjectEvent.java +++ b/bus/src/main/java/de/srsoftware/umbrella/messagebus/events/ProjectEvent.java @@ -1,7 +1,7 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.messagebus.events; -import static de.srsoftware.umbrella.core.Constants.PROJECT; +import static de.srsoftware.umbrella.core.constants.Module.PROJECT; import de.srsoftware.umbrella.core.model.Project; import de.srsoftware.umbrella.core.model.UmbrellaUser; diff --git a/bus/src/main/java/de/srsoftware/umbrella/messagebus/events/TaskEvent.java b/bus/src/main/java/de/srsoftware/umbrella/messagebus/events/TaskEvent.java index 8f5bf24d..b47c6de6 100644 --- a/bus/src/main/java/de/srsoftware/umbrella/messagebus/events/TaskEvent.java +++ b/bus/src/main/java/de/srsoftware/umbrella/messagebus/events/TaskEvent.java @@ -1,7 +1,8 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.messagebus.events; -import static de.srsoftware.umbrella.core.Constants.TASK; + +import static de.srsoftware.umbrella.core.constants.Module.TASK; import de.srsoftware.umbrella.core.model.Task; import de.srsoftware.umbrella.core.model.UmbrellaUser; diff --git a/company/src/main/java/de/srsoftware/umbrella/company/CompanyModule.java b/company/src/main/java/de/srsoftware/umbrella/company/CompanyModule.java index 17b6c356..19d519cf 100644 --- a/company/src/main/java/de/srsoftware/umbrella/company/CompanyModule.java +++ b/company/src/main/java/de/srsoftware/umbrella/company/CompanyModule.java @@ -4,12 +4,15 @@ package de.srsoftware.umbrella.company; import static de.srsoftware.umbrella.company.Constants.CONFIG_DATABASE; import static de.srsoftware.umbrella.company.Constants.NEXT_CUSTOMER_NUMBER; import static de.srsoftware.umbrella.core.ConnectionProvider.connect; -import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.ModuleRegistry.*; -import static de.srsoftware.umbrella.core.Paths.LIST; -import static de.srsoftware.umbrella.core.Paths.SEARCH; import static de.srsoftware.umbrella.core.Util.mapValues; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Path.LIST; +import static de.srsoftware.umbrella.core.constants.Path.SEARCH; +import static de.srsoftware.umbrella.core.constants.Text.COMPANY_WITH_ID; +import static de.srsoftware.umbrella.core.constants.Text.LONG; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; +import static de.srsoftware.umbrella.core.model.Translatable.t; import com.sun.net.httpserver.HttpExchange; import de.srsoftware.configuration.Configuration; @@ -30,17 +33,17 @@ public class CompanyModule extends BaseHandler implements CompanyService { public CompanyModule(Configuration config) throws UmbrellaException { super(); - var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE)); + var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingField(CONFIG_DATABASE)); companyDb = new SqliteDb(connect(dbFile)); ModuleRegistry.add(this); } private boolean deleteCompany(long companyId, UmbrellaUser user, HttpExchange ex) throws IOException { var company = get(companyId); - if (!membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name()); - if (!documentService().list(companyId).isEmpty()) throw forbidden("There are documents owned by {0}",company.name()); - if (!itemService().redefineMe(companyId).isEmpty()) throw forbidden("There are items owned by {0}",company.name()); - if (!projectService().listCompanyProjects(companyId,true).isEmpty()) throw forbidden("There are projects owned by {0}",company.name()); + if (!membership(companyId,user.id())) throw forbidden("You are mot a member of company {company}", COMPANY,company.name()); + if (!documentService().list(companyId).isEmpty()) throw forbidden("There are documents owned by {company}", COMPANY,company.name()); + if (!itemService().redefineMe(companyId).isEmpty()) throw forbidden("There are items owned by {company}", COMPANY,company.name()); + if (!projectService().listCompanyProjects(companyId,true).isEmpty()) throw forbidden("There are projects owned by {company}", COMPANY,company.name()); return sendContent(ex, companyDb.drop(companyId)); } @@ -57,7 +60,7 @@ public class CompanyModule extends BaseHandler implements CompanyService { default -> deleteCompany(Long.parseLong(head), user.get(), ex); }; } catch (NumberFormatException n) { - return send(ex,invalidFieldException(ID,"ID (Long)")); + return send(ex,invalidField(ID,t(LONG))); } catch (UmbrellaException e) { return send(ex,e); } @@ -99,7 +102,7 @@ public class CompanyModule extends BaseHandler implements CompanyService { default -> patchCompany(Long.parseLong(head), user.get(), ex); }; } catch (NumberFormatException n) { - return send(ex,invalidFieldException(ID,"ID (Long)")); + return send(ex,invalidField(ID,t(LONG))); } catch (UmbrellaException e) { return send(ex,e); } @@ -119,7 +122,7 @@ public class CompanyModule extends BaseHandler implements CompanyService { default -> super.doPost(path,ex); }; } catch (NumberFormatException n) { - return send(ex,invalidFieldException(ID,"ID (Long)")); + return send(ex,invalidField(ID,t(LONG))); } catch (UmbrellaException e) { return send(ex,e); } @@ -153,7 +156,7 @@ public class CompanyModule extends BaseHandler implements CompanyService { private boolean getNextCustomerNumber(UmbrellaUser user, long companyId, HttpExchange ex) throws IOException { var company = companyDb.load(companyId); - if (!membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name()); + if (!membership(companyId,user.id())) throw notAmember(t(COMPANY_WITH_ID,ID,company.name())); var nextCustomerNumber = companyDb.getNextCustomerNumber(companyId); return sendContent(ex,nextCustomerNumber); } @@ -186,7 +189,7 @@ public class CompanyModule extends BaseHandler implements CompanyService { private boolean patchCompany(long companyId, UmbrellaUser user, HttpExchange ex) throws IOException { var company = get(companyId); - if (!membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name()); + if (!membership(companyId,user.id())) throw notAmember(t(COMPANY_WITH_ID,ID,company.name())); var json = json(ex); company = companyDb.save(company.patch(json)); @@ -221,7 +224,7 @@ public class CompanyModule extends BaseHandler implements CompanyService { private boolean postSearch(UmbrellaUser user, HttpExchange ex) throws IOException { var json = json(ex); - if (!(json.has(KEY) && json.get(KEY) instanceof String key)) throw missingFieldException(KEY); + if (!(json.has(KEY) && json.get(KEY) instanceof String key)) throw missingField(KEY); var keys = Arrays.asList(key.split(" ")); var companies = companyDb.find(user,keys); return sendContent(ex,mapValues(companies)); diff --git a/company/src/main/java/de/srsoftware/umbrella/company/SqliteDb.java b/company/src/main/java/de/srsoftware/umbrella/company/SqliteDb.java index 62351560..55dc7942 100644 --- a/company/src/main/java/de/srsoftware/umbrella/company/SqliteDb.java +++ b/company/src/main/java/de/srsoftware/umbrella/company/SqliteDb.java @@ -7,17 +7,19 @@ import static de.srsoftware.tools.jdbc.Query.*; import static de.srsoftware.tools.jdbc.Query.Dialect.SQLITE; import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL; import static de.srsoftware.umbrella.company.Constants.*; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.Constants.COMPANY; import static de.srsoftware.umbrella.core.Errors.*; -import static de.srsoftware.umbrella.core.Field.*; -import static de.srsoftware.umbrella.core.Field.COMPANY_ID; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Field.COMPANY; +import static de.srsoftware.umbrella.core.constants.Field.NUMBER; +import static de.srsoftware.umbrella.core.constants.Field.TYPE; +import static de.srsoftware.umbrella.core.constants.Text.*; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; +import static de.srsoftware.umbrella.core.model.Translatable.t; import static java.text.MessageFormat.format; import de.srsoftware.umbrella.company.api.CompanyDb; import de.srsoftware.umbrella.core.BaseDb; -import de.srsoftware.umbrella.core.ModuleRegistry; +import de.srsoftware.umbrella.core.constants.Text; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.core.model.Company; import de.srsoftware.umbrella.core.model.UmbrellaUser; @@ -67,7 +69,7 @@ CREATE TABLE IF NOT EXISTS "companies" ( stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_COMPANIES).causedBy(e); + throw failedToCreateTable(TABLE_COMPANIES).causedBy(e); } } @@ -78,7 +80,7 @@ CREATE TABLE IF NOT EXISTS "companies" ( stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_COMPANIES).causedBy(e); + throw failedToCreateTable(TABLE_COMPANIES_USERS).causedBy(e); } } @@ -91,7 +93,7 @@ CREATE TABLE IF NOT EXISTS "companies" ( .execute(db) .close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_ASSIGN_USER_TO_COMPANY).causedBy(e); + throw databaseException(FAILED_TO_ASSIGN_A_TO_B,"a", t(USER_WITH_ID, ID,user_id),"b", t(COMPANY_WITH_ID, ID,company_id)).causedBy(e); } } @@ -102,7 +104,7 @@ CREATE TABLE IF NOT EXISTS "companies" ( delete().from(TABLE_COMPANIES).where(ID,equal(companyId)).execute(db); return companyId; } catch (SQLException e) { - throw databaseException(FAILED_TO_DROP_ENTITY,"company",companyId).causedBy(e); + throw failedToDropObject("company "+ companyId).causedBy(e); } } @@ -111,7 +113,7 @@ CREATE TABLE IF NOT EXISTS "companies" ( try { delete().from(TABLE_COMPANIES_USERS).where(COMPANY_ID,equal(companyId)).where(USER_ID,equal(userId)).execute(db); } catch (SQLException e) { - throw databaseException(FAILED_TO_DROP_ENTITY_OF_ENTITY,"user",userId,"company",companyId).causedBy(e); + throw failedToDropObjectFromObject("user",userId,"company",companyId).causedBy(e); } } @@ -124,14 +126,14 @@ CREATE TABLE IF NOT EXISTS "companies" ( rs.close(); return ids; } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_ENTITY_MEMBERS,COMPANY,companyId).causedBy(e); + throw failedToLoadMembers(t("company {company}", COMPANY,companyId)).causedBy(e); } } @Override public String getNextCustomerNumber(long companyId) { try { - var rs = select(LAST_CUSTOMER_NUMBER,CUSTOMER_NUMBER_PREFIX).from(TABLE_COMPANIES).where(ID,equal(companyId)).exec(db); + var rs = select(LAST_CUSTOMER_NUMBER, CUSTOMER_NUMBER_PREFIX).from(TABLE_COMPANIES).where(ID,equal(companyId)).exec(db); var last = 0L; String prefix = null; if (rs.next()){ @@ -142,7 +144,7 @@ CREATE TABLE IF NOT EXISTS "companies" ( var next = last+1; return prefix+next; // TODO: currently not taking growing number lengths into account, this should be resolved! } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_CUSTOMER_NUM_SETTINGS,companyId).causedBy(e); + throw failedToLoadObject(t("customer number settings for {company_id}",COMPANY_ID,companyId)).causedBy(e); } } @@ -152,7 +154,7 @@ CREATE TABLE IF NOT EXISTS "companies" ( var query = select(DISTINCT).from(TABLE_COMPANIES).leftJoin(ID,TABLE_COMPANIES_USERS,COMPANY_ID) .where(USER_ID,equal(user.id())); for (var key : keys){ - query.where(format("CONCAT({0},\" \",{1},\" \",{2},\" \",{3},\" \",{4})",NAME,ADDRESS,EMAIL,PHONE,BANK_ACCOUNT),like("%"+key+"%")); + query.where(format("CONCAT({0},\" \",{1},\" \",{2},\" \",{3},\" \",{4})", NAME, ADDRESS, EMAIL,PHONE,BANK_ACCOUNT),like("%"+key+"%")); } var rs = query.exec(db); var companies = new HashMap(); @@ -163,7 +165,8 @@ CREATE TABLE IF NOT EXISTS "companies" ( rs.close(); return companies; } catch (SQLException e){ - throw databaseException(FAILED_TO_SEARCH_DB, ModuleRegistry.translator().translate(user.language(),COMPANY)).causedBy(e); + throw failedToSearchDb(t(Text.COMPANY)).causedBy(e); + //throw databaseException(FAILED_TO_SEARCH_DB, ModuleRegistry.translator().translate(user.language(),COMPANY)).causedBy(e); } } @@ -179,7 +182,7 @@ CREATE TABLE IF NOT EXISTS "companies" ( rs.close(); return companies; } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER,"companies","user "+userId).causedBy(e); + throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER,TYPE,COMPANIES, OWNER, t(USER_WITH_ID, ID,userId)); } } @@ -190,10 +193,10 @@ CREATE TABLE IF NOT EXISTS "companies" ( Company company = null; if (rs.next()) company = Company.of(rs); rs.close(); - if (company == null) throw notFound(FAILED_TO_LOAD_ENTITY_BY_ID,"company",companyId); + if (company == null) throw notFound(FAILED_TO_LOAD_OBJECT_BY_ID, OBJECT, t(Text.COMPANY), ID,companyId); return company; } catch (SQLException e){ - throw databaseException(FAILED_TO_LOAD_ENTITY_BY_ID,"company",companyId).causedBy(e); + throw failedToLoadObject(t(Text.COMPANY),companyId).causedBy(e); } } @@ -202,7 +205,7 @@ CREATE TABLE IF NOT EXISTS "companies" ( try { if (company.id() == 0){ // new long id = 0; - var rs = insertInto(TABLE_COMPANIES,NAME, ADDRESS, EMAIL, PHONE, BANK_ACCOUNT, COURT, CURRENCY, TAX_NUMBER, DECIMALS, DECIMAL_SEPARATOR, THOUSANDS_SEPARATOR, LAST_CUSTOMER_NUMBER, CUSTOMER_NUMBER_PREFIX) + var rs = insertInto(TABLE_COMPANIES, NAME, ADDRESS, EMAIL, PHONE, BANK_ACCOUNT, COURT, CURRENCY, TAX_NUMBER, DECIMALS, DECIMAL_SEPARATOR, THOUSANDS_SEPARATOR, LAST_CUSTOMER_NUMBER, CUSTOMER_NUMBER_PREFIX) .values(company.name(),company.address(),company.email(),company.phone(),company.bankAccount(),company.court(),company.currency(),company.taxId(),company.decimals(),company.decimalSeparator(),company.thousandsSeparator(),0,company.customerNumberPrefix()) .execute(db) .getGeneratedKeys(); @@ -225,7 +228,7 @@ CREATE TABLE IF NOT EXISTS "companies" ( return company; } } catch (SQLException e){ - throw databaseException(FAILED_TO_STORE_ENTITY,company.name()).causedBy(e); + throw failedToStoreObject(company.name()).causedBy(e); } } @@ -233,13 +236,13 @@ CREATE TABLE IF NOT EXISTS "companies" ( public void saveNewCustomer(long companyId, String id) { var p = Pattern.compile("(?s)(.*?)(\\d+)$"); var m = p.matcher(id); - if (!m.matches()) throw unprocessable("{0} is not a valid customer id: it does not end with a number!"); + if (!m.matches()) throw unprocessable("{number} is not a valid customer id: it does not end with a number!", NUMBER,id); String prefix = m.group(1); // Prefix before last number long number = Long.parseLong(m.group(2)); // The last numeric part try { - update(TABLE_COMPANIES).set(LAST_CUSTOMER_NUMBER,CUSTOMER_NUMBER_PREFIX).where(ID,equal(companyId)).prepare(db).apply(number,prefix).close(); + update(TABLE_COMPANIES).set(LAST_CUSTOMER_NUMBER, CUSTOMER_NUMBER_PREFIX).where(ID,equal(companyId)).prepare(db).apply(number,prefix).close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_UPDATE_ENTITY, LAST_CUSTOMER_NUMBER).causedBy(e); + throw failedToStoreObject(LAST_CUSTOMER_NUMBER).causedBy(e); } } } diff --git a/contact/src/main/java/de/srsoftware/umbrella/contact/ContactModule.java b/contact/src/main/java/de/srsoftware/umbrella/contact/ContactModule.java index 03245eef..087e6980 100644 --- a/contact/src/main/java/de/srsoftware/umbrella/contact/ContactModule.java +++ b/contact/src/main/java/de/srsoftware/umbrella/contact/ContactModule.java @@ -4,9 +4,9 @@ package de.srsoftware.umbrella.contact; import static de.srsoftware.umbrella.contact.Constants.CONFIG_DATABASE; import static de.srsoftware.umbrella.core.ConnectionProvider.connect; import static de.srsoftware.umbrella.core.ModuleRegistry.userService; -import static de.srsoftware.umbrella.core.Paths.LIST; import static de.srsoftware.umbrella.core.Util.mapValues; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException; +import static de.srsoftware.umbrella.core.constants.Path.LIST; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingField; import com.sun.net.httpserver.HttpExchange; import de.srsoftware.configuration.Configuration; @@ -28,7 +28,7 @@ public class ContactModule extends BaseHandler implements ContactService { public ContactModule(Configuration config) throws UmbrellaException { super(); - var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE)); + var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingField(CONFIG_DATABASE)); contactDb = new SqliteDb(connect(dbFile)); ModuleRegistry.add(this); } diff --git a/contact/src/main/java/de/srsoftware/umbrella/contact/SqliteDb.java b/contact/src/main/java/de/srsoftware/umbrella/contact/SqliteDb.java index 9c8a35ba..70d27d0b 100644 --- a/contact/src/main/java/de/srsoftware/umbrella/contact/SqliteDb.java +++ b/contact/src/main/java/de/srsoftware/umbrella/contact/SqliteDb.java @@ -6,10 +6,12 @@ import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL; import static de.srsoftware.tools.jdbc.Query.insertInto; import static de.srsoftware.tools.jdbc.Query.select; import static de.srsoftware.umbrella.contact.Constants.*; -import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.Errors.*; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseException; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.notFound; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Field.TYPE; +import static de.srsoftware.umbrella.core.constants.Text.*; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; +import static de.srsoftware.umbrella.core.model.Translatable.t; import static java.text.MessageFormat.format; import de.srsoftware.tools.jdbc.Query; @@ -45,7 +47,7 @@ public class SqliteDb extends BaseDb implements ContactDb{ try { db.prepareStatement(sql).execute(); } catch (SQLException e) { - throw databaseException(ERROR_FAILED_CREATE_TABLE,TABLE_CONTACTS).causedBy(e); + throw failedToCreateTable(TABLE_CONTACTS).causedBy(e); } } @@ -55,7 +57,7 @@ public class SqliteDb extends BaseDb implements ContactDb{ try { db.prepareStatement(sql).execute(); } catch (SQLException e) { - throw databaseException(ERROR_FAILED_CREATE_TABLE,TABLE_CONTACTS_USERS).causedBy(e); + throw failedToCreateTable(TABLE_CONTACTS_USERS).causedBy(e); } } @@ -67,7 +69,7 @@ public class SqliteDb extends BaseDb implements ContactDb{ Query.delete().from(TABLE_CONTACTS_USERS).where(CONTACT_ID,equal(contact.id())).execute(db); db.setAutoCommit(true); } catch (SQLException e){ - throw databaseException(FAILED_TO_DROP_ENTITY,"contact",contact.id()).causedBy(e); + throw failedToDropObject(t(CONTACT_WITH_ID, ID,contact.id())).causedBy(e); } } @@ -83,7 +85,10 @@ public class SqliteDb extends BaseDb implements ContactDb{ rs.close(); return contacts; } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER,"contacts",userId).causedBy(e); + throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER, + TYPE, t(CONTACTS), + OWNER, t(USER_WITH_ID, ID,userId) + ).causedBy(e); } } @@ -95,9 +100,12 @@ public class SqliteDb extends BaseDb implements ContactDb{ if (rs.next()) contact = Contact.of(rs); rs.close(); if (contact != null) return contact; - throw notFound(FAILED_TO_LOAD_ENTITY_BY_ID, "contact", contactId); + throw failedToLoadObject(t(CONTACT), contactId); } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER,"contacts",userId).causedBy(e); + throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER, + TYPE, t(CONTACT), + OWNER, t(USER_WITH_ID, ID,userId) + ); } } @@ -105,19 +113,19 @@ public class SqliteDb extends BaseDb implements ContactDb{ public Contact save(Contact contact) { if (contact.id() == 0){ // new contact try { - var rs = insertInto(TABLE_CONTACTS,DATA).values(contact.vcard()).execute(db).getGeneratedKeys(); + var rs = insertInto(TABLE_CONTACTS, DATA).values(contact.vcard()).execute(db).getGeneratedKeys(); Long id = null; if (rs.next()) id = rs.getLong(1); rs.close(); if (id != null) return new Contact(id,contact.vcard()); - throw databaseException(FAILED_TO_STORE_ENTITY,"vcard"); + throw failedToStoreObject(VCARD); } catch (SQLException e) { - throw databaseException(FAILED_TO_STORE_ENTITY,"vcard").causedBy(e); + throw failedToStoreObject(VCARD).causedBy(e); } } else try { // update Query.update(TABLE_CONTACTS).set(DATA).where(ID,equal(contact.id())).prepare(db).apply(contact.vcard()).execute(); } catch (SQLException e) { - throw databaseException(FAILED_TO_UPDATE_ENTITY,"vcard").causedBy(e); + throw failedToStoreObject(VCARD).causedBy(e); } return contact; } @@ -125,9 +133,9 @@ public class SqliteDb extends BaseDb implements ContactDb{ @Override public void setOwner(long userId, Contact contact) { try { - Query.replaceInto(TABLE_CONTACTS_USERS,USER_ID,CONTACT_ID,ASSIGNED).values(userId,contact.id(),false).execute(db).close(); + Query.replaceInto(TABLE_CONTACTS_USERS, USER_ID,CONTACT_ID,ASSIGNED).values(userId,contact.id(),false).execute(db).close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_ASSIGN_CONTACT_TO_USER,contact.id(),userId).causedBy(e); + throw databaseException(FAILED_TO_ASSIGN_A_TO_B,"a", t(CONTACT_WITH_ID, ID,contact.id()),"b", t(USER_WITH_ID, ID,userId)).causedBy(e); } } } diff --git a/core/src/main/java/de/srsoftware/umbrella/core/BaseDb.java b/core/src/main/java/de/srsoftware/umbrella/core/BaseDb.java index 60d43e78..ebb38442 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/BaseDb.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/BaseDb.java @@ -4,9 +4,10 @@ package de.srsoftware.umbrella.core; import static de.srsoftware.tools.jdbc.Condition.equal; import static de.srsoftware.tools.jdbc.Query.replaceInto; import static de.srsoftware.tools.jdbc.Query.update; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.Constants.TABLE_SETTINGS; -import static java.lang.System.Logger.Level.ERROR; +import static de.srsoftware.umbrella.core.constants.Constants.TABLE_SETTINGS; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.failedToCreateTable; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.failedToReadFromTable; import static java.lang.System.Logger.Level.INFO; import static java.text.MessageFormat.format; @@ -37,8 +38,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255) stmt.execute(); stmt.close(); } catch (SQLException e) { - LOG.log(ERROR,ERROR_FAILED_CREATE_TABLE,TABLE_SETTINGS,e); - throw new RuntimeException(e); + throw failedToCreateTable(TABLE_SETTINGS).causedBy(e); } var version = 0; @@ -49,8 +49,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255) return version; } catch (SQLException e) { - LOG.log(ERROR,ERROR_READ_TABLE,DB_VERSION,TABLE_SETTINGS,e); - throw new RuntimeException(e); + throw failedToReadFromTable(DB_VERSION,TABLE_SETTINGS).causedBy(e); } } diff --git a/core/src/main/java/de/srsoftware/umbrella/core/BaseHandler.java b/core/src/main/java/de/srsoftware/umbrella/core/BaseHandler.java index 3aaaae8d..f1e67371 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/BaseHandler.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/BaseHandler.java @@ -2,10 +2,8 @@ package de.srsoftware.umbrella.core; import static de.srsoftware.tools.Optionals.nullable; -import static de.srsoftware.umbrella.core.ModuleRegistry.translator; import static java.lang.System.Logger.Level.*; import static java.net.HttpURLConnection.*; -import static java.text.MessageFormat.format; import com.sun.net.httpserver.HttpExchange; import de.srsoftware.tools.Path; @@ -74,13 +72,10 @@ public abstract class BaseHandler extends PathHandler { public boolean send(HttpExchange ex, UmbrellaException e) throws IOException { var cause = e.getCause(); - String lang = languages(ex).stream().findFirst().orElse(null); - var translatedMessage = translator().translate(lang,e.getMessage()); - if (cause != null){ - var msg = "en".equals(lang) ? translatedMessage : translator().translate("en",e.getMessage()); - LOG.log(ERROR,format(msg,e.fills()),cause); - } - return sendContent(ex,e.statusCode(),format(translatedMessage,e.fills())); + String lang = languages(ex).stream().findFirst().orElse("en"); + var translatedMessage = e.message().translate(lang); + if (cause != null) LOG.log(ERROR,translatedMessage,cause); + return sendContent(ex,e.statusCode(),translatedMessage); } public boolean unauthorized(HttpExchange ex) throws IOException { diff --git a/core/src/main/java/de/srsoftware/umbrella/core/Constants.java b/core/src/main/java/de/srsoftware/umbrella/core/Constants.java deleted file mode 100644 index 8c0ff1e8..00000000 --- a/core/src/main/java/de/srsoftware/umbrella/core/Constants.java +++ /dev/null @@ -1,166 +0,0 @@ -/* © SRSoftware 2025 */ -package de.srsoftware.umbrella.core; - - -import static java.nio.charset.StandardCharsets.UTF_8; - -public class Constants { - - private Constants(){} - - - - - - public static final String ADDRESS = "address"; - public static final String ALLOWED_STATES = "allowed_states"; - public static final String ATTACHMENTS = "attachments"; - public static final String AUTHORIZATION = "Authorization"; - - public static final String BODY = "body"; - public static final String BOOKMARK = "bookmark"; - - public static final String CACHE_CONTROL = "Cache-Control"; - public static final String CODE = "code"; - public static final String COMMENT = "comment"; - public static final String COMPANY = "company"; - public static final String COMPANY_ID = "company_id"; - public static final String CONNECTION = "Connection"; - public static final String CONTENT = "content"; - public static final String CONTENT_DISPOSITION = "Content-Disposition"; - public static final String CONTENT_ENCODING = "Content-Encoding"; - public static final String CONTENT_TYPE = "Content-Type"; - public static final String CUSTOMER_NUMBER_PREFIX = "customer_number_prefix"; - - public static final String DATA = "data"; - public static final String DB_VERSION = "db_version"; - public static final String DATE = "date"; - public static final String DECIMALS = "decimals"; - public static final String DECIMAL_SEPARATOR = "decimal_separator"; - public static final String DELETED = "deleted"; - public static final String DESCRIPTION = "description"; - public static final String DOMAIN = "domain"; - public static final String DROP_MEMBER = "drop_member"; - public static final String DUE_DATE = "due_date"; - public static final String DURATION = "duration"; - - public static final String EMAIL = "email"; - public static final String END_TIME = "end_time"; - public static final String ENTITY_ID = "entity_id"; - public static final String ERROR_FAILED_CREATE_TABLE = "Failed to create \"{0}\" table!"; - public static final String ERROR_INVALID_FIELD = "Expected {0} to be {1}!"; - public static final String ERROR_MISSING_CONFIG = "Config is missing value for {0}!"; - public static final String ERROR_MISSING_FIELD = "Json is missing {0} field!"; - public static final String ERROR_READ_TABLE = "Failed to read {0} from {1} table"; - public static final String EST_TIME = "est_time"; - public static final String ESTIMATED_TIME = "estimated_time"; - public static final String EXPIRATION = "expiration"; - - public static final String FALLBACK_LANG = "de"; - - public static final String FROM = "from"; - public static final String FULLTEXT = "fulltext"; - - public static final String GET = "GET"; - public static final String GUEST_ALLOWED = "guest_allowed"; - - public static final String HASH = "hash"; - - public static final String ID = "id"; - - public static final String JSONARRAY = "json array"; - public static final String JSONOBJECT = "json object"; - - public static final String KEEP_ALIVE = "keep-alive"; - public static final String KEY = "key"; - - public static final String LANGUAGE = "language"; - public static final String LAST_CUSTOMER_NUMBER = "last_customer_number"; - public static final String LIMIT = "limit"; - public static final String LOCATION = "location"; - public static final String LOCATION_ID = "location_id"; - public static final String LOGIN = "login"; - - public static final String MEMBERS = "members"; - public static final String MESSAGES = "messages"; - public static final String MODULE = "module"; - - public static final String NAME = "name"; - public static final String NEW_MEMBER = "new_member"; - public static final String MIME = "mime"; - public static final String NO_CACHE = "no-cache"; - public static final String NO_INDEX = "no_index"; - public static final String NONE = "none"; - public static final String NOTE = "note"; - public static final String NUMBER = "number"; - - public static final String OFFSET = "offset"; - public static final String OPTIONAL = "optional"; - public static final String OWNER = "owner"; - public static final String OWNER_NUMBER = "owner_number"; - - public static final String PARENT_LOCATION_ID = "parent_location_id"; - public static final String PARENT_TASK_ID = "parent_task_id"; - public static final String PASS = "pass"; - public static final String PASSWORD = "password"; - public static final String PATH = "path"; - public static final String PERMISSION = "permission"; - public static final String POST = "POST"; - public static final String PRIORITY = "priority"; - public static final String PROJECT = "project"; - public static final String PROJECT_ID = "project_id"; - public static final String PROPERTIES = "properties"; - public static final String PROPERTY = "property"; - - public static final String RECEIVERS = "receivers"; - public static final String REDIRECT = "redirect"; - public static final String RENDERED = "rendered"; - public static final String REQUIRED_TASKS_IDS = "required_tasks_ids"; - - public static final String SENDER = "sender"; - public static final String SETTINGS = "settings"; - public static final String SHOW_CLOSED = "show_closed"; - public static final String SOURCE = "source"; - public static final String START_DATE = "start_date"; - public static final String START_TIME = "start_time"; - public static final String STATE = "state"; - public static final String STATUS = "status"; - public static final String STATUS_CODE = "code"; - public static final String STRING = "string"; - public static final String SUBJECT = "subject"; - - public static final String TABLE_SETTINGS = "settings"; - public static final String TAGS = "tags"; - public static final String TAG_COLORS = "tag_colors"; - public static final String TASK = "task"; - public static final String TASK_IDS = "task_ids"; - public static final String TAX = "tax"; - public static final String TAX_RATE = "tax_rate"; - public static final String TEMPLATE = "template"; - public static final String TEXT = "text"; - public static final String THOUSANDS_SEPARATOR = "thousands_separator"; - public static final String THEME = "theme"; - public static final String TITLE = "title"; - public static final String TIMESTAMP = "timestamp"; - public static final String TO = "to"; - public static final String TOKEN = "token"; - public static final String TOTAL_PRIO = "total_prio"; - public static final String TYPE = "type"; - - public static final String UMBRELLA = "Umbrella"; - public static final String UNIT = "unit"; - public static final String URI = "uri"; - public static final String URL = "url"; - public static final String USER = "user"; - public static final String USERS = "users"; - public static final String USER_ID = "user_id"; - public static final String USER_LIST = "user_list"; - public static final String USES = "uses"; - public static final String UTF8 = UTF_8.displayName(); - - public static final String VALUE = "value"; - public static final String VCARD = "vcard"; - public static final String VERSION = "version"; - public static final String VERSIONS = "versions"; - -} diff --git a/core/src/main/java/de/srsoftware/umbrella/core/Errors.java b/core/src/main/java/de/srsoftware/umbrella/core/Errors.java index 09b1c594..21edfb67 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/Errors.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/Errors.java @@ -2,38 +2,42 @@ package de.srsoftware.umbrella.core; public class Errors { - public static final String FAILED_TO_ADD_COLUMN = "failed_to_add_column"; - public static final String FAILED_TO_ADD_PROPERTY_TO_ITEM = "failed_to_add_prop_to_item"; - public static final String FAILED_TO_ASSIGN_USER_TO_COMPANY = "failed_to_assign_user_to_company"; - public static final String FAILED_TO_ASSIGN_CONTACT_TO_USER = "failed_to_assign_contact_to_user"; - public static final String FAILED_TO_CHECK_ENTITY_AVAILABLE = "failed_to_check_entity_available"; - public static final String FAILED_TO_CHECK_FILE_PERMISSIONS = "failed_to_check_file_permissions"; - public static final String FAILED_TO_CREATE_STATE = "failed_to_create_state"; - public static final String FAILED_TO_CREATE_TABLE = "failed_to_create_table"; - public static final String FAILED_TO_DROP_ENTITY = "failed_to_drop_entity"; - public static final String FAILED_TO_DROP_ENTITY_OF_ENTITY = "failed_to_drop_entity_from_entity"; - public static final String FAILED_TO_DROP_NOTES = "failed_to_drop_notes"; - public static final String FAILED_TO_GET_FREE_ID = "failed_to_get_free_id"; - public static final String FAILED_TO_LIST_ENTITIES = "failed_to_list_entities"; - public static final String FAILED_TO_LOAD_CHILD_LOCATIONS = "failed_to_load_child_locations"; - public static final String FAILED_TO_LOAD_ENTITY_MEMBERS = "failed_to_load_entity_members"; - public static final String FAILED_TO_LOAD_ENTITIES_OF_OWNER = "failed_to_load_entities_of_owner"; - public static final String FAILED_TO_LOAD_CUSTOMER_NUM_SETTINGS = "failed_to_load_customer_number_settings"; - public static final String FAILED_TO_LOAD_CUSTOMER_PRICE = "failed_to_load_customer_price"; - public static final String FAILED_TO_LOAD_CUSTOMER_SETTINGS = "failed_to_load_customer_settings"; - public static final String FAILED_TO_LOAD_ENTITY = "failed_to_load_entity"; - public static final String FAILED_TO_LOAD_ENTITY_BY_ID = "failed_to_load_entity_by_id"; - public static final String FAILED_TO_LOAD_USER_SETTINGS = "failed_to_load_user_settings"; - public static final String FAILED_TO_MOVE = "failed_to_move"; - public static final String FAILED_TO_READ_LAST_DOCID = "failed_to_read_last_docId"; - public static final String FAILED_TO_SEARCH_DB = "failed_to_search_db"; - public static final String FAILED_TO_STORE_ENTITY = "failed_to_store_entity"; - public static final String FAILED_TO_SWITCH_POSITIONS = "failed_to_switch_positions"; - public static final String FAILED_TO_UPDATE_COLUMN = "failed_to_update_column"; - public static final String FAILED_TO_UPDATE_ENTITY = "failed_to_update_entity"; - public static final String FAILED_TO_UPDATE_TABLE = "failed_to_update_table"; - public static final String MISSING_NEW_ITEM_ID = "missing_new_item_id"; - public static final String NO_BOOKMARK_FOR_URLID = "no_bookmark_for_urlid"; - public static final String UNEXPECTED_ITEM_ID_FORMAT = "unexpected_item_id_format"; - public static final String UNKNOWN_ITEM_LOCATION = "unknown_item_location"; + public static final String ADDRESS_MISSING = "{object} address does not contain street address / post code / city"; + + public static final String FAILED_TO_ADD_COLUMN = "Failed to add {name} column to {table} table"; + public static final String FAILED_TO_ADD_PROPERTY_TO_ITEM = "Failed to add new property to item {object}"; + public static final String FAILED_TO_ASSIGN_A_TO_B = "Failed to assign {a} to {b}."; + public static final String FAILED_TO_CHECK_ENTITY_AVAILABLE = "Failed to check availability of {object}"; + public static final String FAILED_TO_CHECK_FILE_PERMISSIONS = "Failed to check file permissions!"; + public static final String FAILED_TO_CREATE_STATE = "Failed to create custom state!"; + public static final String FAILED_TO_CREATE_TABLE = "Failed to create table `{name}`"; + public static final String FAILED_TO_DROP_OBJECT = "Failed to drop {object}!"; + public static final String FAILED_TO_DROP_ENTITY_OF_ENTITY = "Failed to drop {dropped_type} {object} from {related_type} {related}!"; + public static final String FAILED_TO_DROP_NOTES = "Failed to delete notes of ({module} {id})"; + public static final String FAILED_TO_GET_FREE_ID = "Failed to query free ID"; + public static final String FAILED_TO_LIST_ENTITIES = "Failed to list {type}"; + public static final String FAILED_TO_LOAD_CHILD_LOCATIONS = "Failed to load child locations for {parent}"; + public static final String FAILED_TO_LOAD_OBJECT_MEMBERS = "Failed to load members of {object}"; + public static final String FAILED_TO_LOAD_ENTITIES_OF_OWNER = "Failed to load {type} of {owner}!"; + public static final String FAILED_TO_LOAD_CUSTOMER_PRICE = "Failed to load customer price (company: {company}, customer: {customer}, item: {item})"; + public static final String FAILED_TO_LOAD_CUSTOMER_SETTINGS = "Failed to load customer settings (company: {company}, document type: {type})"; + public static final String FAILED_TO_LOAD_OBJECT = "Failed to load {object}!"; + public static final String FAILED_TO_LOAD_OBJECT_BY_ID = "Failed to load {object} by id (id)!"; + public static final String FAILED_TO_MOVE = "Failed to move {old} to {new}!"; + public static final String FAILED_TO_READ_FROM_TABLE = "Failed to read {field} from {table}!"; + public static final String FAILED_TO_READ_LAST_DOCID = "Failed to read last document id"; + public static final String FAILED_TO_SEARCH_DB = "Failed to search in {module} db"; + public static final String FAILED_TO_STORE_OBJECT = "Failed to store {object}"; + public static final String FAILED_TO_SWITCH_POSITIONS = "Failed to switch positions {a} and {b} of document {document}"; + public static final String FAILED_TO_UPDATE_COLUMN = "Failed to update column {old} → {new} of {table}"; + public static final String FAILED_TO_UPDATE_OBJECT = "Failed to update {object} in database"; + public static final String INVALID_EMAIL = "\"{email}\" is not a valid email address!"; + public static final String INVALID_FIELD = "Expected {field} to be {expected}!"; + public static final String INVALID_URL = "\"{url}\" is not a valid URL!"; + public static final String MISSING_CONFIG = "Config is missing value for {key}!"; + public static final String MISSING_FIELD = "Json is missing {field} field!"; + public static final String MISSING_NEW_ITEM_ID = "Old item id ({id}) has no new counterpart!"; + public static final String NO_MEMBER = "You are not a member of {object}!"; + public static final String UNEXPECTED_ITEM_ID_FORMAT = "Expected old item ID to be of the form ss:dd:dd, encountered {object}!"; + public static final String UNKNOWN_ITEM_LOCATION = "Item {object} of {owner} refers to location {location}, which is unknown!"; } diff --git a/core/src/main/java/de/srsoftware/umbrella/core/Field.java b/core/src/main/java/de/srsoftware/umbrella/core/Field.java deleted file mode 100644 index d7756424..00000000 --- a/core/src/main/java/de/srsoftware/umbrella/core/Field.java +++ /dev/null @@ -1,51 +0,0 @@ -/* © SRSoftware 2025 */ -package de.srsoftware.umbrella.core; - -public class Field{ - public static final String AMOUNT = "amount"; - public static final String BANK_ACCOUNT = "bank_account"; - public static final String COMPANY = "company"; - public static final String COMPANY_ID = "company_id"; - public static final String COURT = "court"; - public static final String CURRENCY = "currency"; - public static final String CUSTOMER = "customer"; - public static final String CUSTOMER_EMAIL = "customer_email"; - public static final String CUSTOMER_NUMBER = "customer_number"; - public static final String CUSTOMER_TAX_NUMBER = "customer_tax_number"; - public static final String DEFAULT_HEADER = "default_header"; - public static final String DEFAULT_FOOTER = "default_footer"; - public static final String DEFAULT_MAIL = "type_mail_text"; - public static final String DELIVERY = "delivery"; - public static final String DELIVERY_DATE = "delivery_date"; - public static final String DOCUMENT = "document"; - public static final String DOCUMENT_ID = "document_id"; - public static final String DOC_TYPE_ID = "document_type_id"; - public static final String END_TIME = "end_time"; - public static final String FOOTER = "footer"; - public static final String GROSS_SUM = "gross_sum"; - public static final String HEAD = "head"; - public static final String ITEM = "item"; - public static final String ITEM_CODE = "item_code"; - public static final String NET_PRICE = "net_price"; - public static final String NET_SUM = "net_sum"; - public static final String NEXT_TYPE = "next_type_id"; - public static final String PHONE = "phone"; - public static final String POS = "pos"; - public static final String POSITIONS = "positions"; - public static final String PRICE = "single_price"; - public static final String PRICE_FORMAT = "price_format"; - public static final String START_TIME = "start_time"; - public static final String TASKS = "tasks"; - public static final String TAX_NUMBER = "tax_number"; - public static final String TAX = "tax"; - public static final String TAX_ID = "tax_id"; - public static final String TEMPLATE_ID = "template_id"; - public static final String TIME_ID = "time_id"; - public static final String TYPE = "type"; - public static final String TYPE_ID = "type_id"; - public static final String TYPE_NUMBER = "type_number"; - public static final String TYPE_PREFIX = "type_prefix"; - public static final String TYPE_SUFFIX = "type_suffix"; - public static final String UNIT = "unit"; - public static final String UNIT_PRICE = "unit_price"; -} \ No newline at end of file diff --git a/core/src/main/java/de/srsoftware/umbrella/core/Util.java b/core/src/main/java/de/srsoftware/umbrella/core/Util.java index 5f61b836..ee909fa1 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/Util.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/Util.java @@ -3,8 +3,12 @@ package de.srsoftware.umbrella.core; import static de.srsoftware.tools.MimeType.MIME_FORM_URL; import static de.srsoftware.tools.MimeType.MIME_JSON; +import static de.srsoftware.tools.PathHandler.GET; +import static de.srsoftware.tools.PathHandler.POST; import static de.srsoftware.tools.Strings.hex; -import static de.srsoftware.umbrella.core.Constants.*; +import static de.srsoftware.umbrella.core.Errors.INVALID_URL; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.serverError; import static java.lang.System.Logger.Level.*; import static java.lang.System.Logger.Level.WARNING; import static java.nio.charset.StandardCharsets.UTF_8; @@ -14,6 +18,7 @@ import de.srsoftware.tools.Mappable; import de.srsoftware.tools.Query; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.core.model.Hash; +import de.srsoftware.umbrella.core.model.Translatable; import java.io.*; import java.net.HttpURLConnection; import java.net.URI; @@ -117,7 +122,7 @@ public class Util { url = new URI(location).toURL(); } catch (Exception e) { LOG.log(WARNING,"{0} is not a valid url",location,e); - throw new UmbrellaException(500,"{0} is not a valid url",location).causedBy(e); + throw serverError(INVALID_URL,URL,location).causedBy(e); } return request(url,data,postMime,auth); } @@ -160,13 +165,13 @@ public class Util { var is = conn.getErrorStream(); is.transferTo(bos); is.close(); - throw new UmbrellaException(500, bos.toString(UTF_8)); + throw new UmbrellaException(500, Translatable.t(bos.toString(UTF_8))); } } catch (UmbrellaException e){ throw e; } catch (Exception e) { LOG.log(WARNING,"Request to {0} failed: {1}",target,e.getMessage()); - throw new UmbrellaException(500,"Request to {0} failed!",target).causedBy(e); + throw new UmbrellaException(500, Translatable.t("Request to {url} failed!",URL,target)).causedBy(e); } } diff --git a/core/src/main/java/de/srsoftware/umbrella/core/api/Owner.java b/core/src/main/java/de/srsoftware/umbrella/core/api/Owner.java index ee7bce89..c1490565 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/api/Owner.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/api/Owner.java @@ -1,8 +1,6 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.core.api; -import static de.srsoftware.umbrella.core.Constants.*; - import de.srsoftware.tools.Mappable; public interface Owner extends Mappable { diff --git a/core/src/main/java/de/srsoftware/umbrella/core/api/Translator.java b/core/src/main/java/de/srsoftware/umbrella/core/api/Translator.java index 9979c0ff..8e8dfcbc 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/api/Translator.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/api/Translator.java @@ -16,5 +16,6 @@ public interface Translator { } return translate(language, parts[0], fills); } + public String translate(String language, String text, Map fills); } diff --git a/core/src/main/java/de/srsoftware/umbrella/core/constants/Constants.java b/core/src/main/java/de/srsoftware/umbrella/core/constants/Constants.java new file mode 100644 index 00000000..9da2683b --- /dev/null +++ b/core/src/main/java/de/srsoftware/umbrella/core/constants/Constants.java @@ -0,0 +1,23 @@ +/* © SRSoftware 2025 */ +package de.srsoftware.umbrella.core.constants; + + +import static java.nio.charset.StandardCharsets.UTF_8; + +public class Constants { + + private Constants(){ + // prevent instantiation + } + public static final String FALLBACK_LANG = "de"; + public static final String HOME = "home"; + public static final String JSONARRAY = "json array"; + public static final String JSONOBJECT = "json object"; + public static final String KEEP_ALIVE = "keep-alive"; + public static final String NO_CACHE = "no-cache"; + public static final String NONE = "none"; + public static final String TABLE_SETTINGS = "settings"; + public static final String UMBRELLA = "Umbrella"; + public static final String UTF8 = UTF_8.displayName(); + +} diff --git a/core/src/main/java/de/srsoftware/umbrella/core/constants/Field.java b/core/src/main/java/de/srsoftware/umbrella/core/constants/Field.java new file mode 100644 index 00000000..fd128bb9 --- /dev/null +++ b/core/src/main/java/de/srsoftware/umbrella/core/constants/Field.java @@ -0,0 +1,171 @@ +/* © SRSoftware 2025 */ +package de.srsoftware.umbrella.core.constants; + +public class Field { + public static final String ADDRESS = "address"; + public static final String ALLOWED_STATES = "allowed_states"; + public static final String AMOUNT = "amount"; + public static final String ATTACHMENTS = "attachments"; + public static final String AUTHORIZATION = "Authorization"; + + public static final String BANK_ACCOUNT = "bank_account"; + public static final String BODY = "body"; + + public static final String CACHE_CONTROL = "Cache-Control"; + public static final String CODE = "code"; + public static final String COMMENT = "comment"; + public static final String COMPANY = "company"; + public static final String COMPANY_ID = "company_id"; + public static final String CONNECTION = "Connection"; + public static final String CONTENT = "content"; + public static final String CONTENT_DISPOSITION = "Content-Disposition"; + public static final String CONTENT_ENCODING = "Content-Encoding"; + public static final String CONTENT_TYPE = "Content-Type"; + public static final String COURT = "court"; + public static final String CURRENCY = "currency"; + public static final String CUSTOMER = "customer"; + public static final String CUSTOMER_EMAIL = "customer_email"; + public static final String CUSTOMER_NUMBER = "customer_number"; + public static final String CUSTOMER_NUMBER_PREFIX = "customer_number_prefix"; + public static final String CUSTOMER_TAX_NUMBER = "customer_tax_number"; + + public static final String DATA = "data"; + public static final String DB_VERSION = "db_version"; + public static final String DATE = "date"; + public static final String DECIMALS = "decimals"; + public static final String DECIMAL_SEPARATOR = "decimal_separator"; + public static final String DEFAULT_HEADER = "default_header"; + public static final String DEFAULT_FOOTER = "default_footer"; + public static final String DEFAULT_MAIL = "type_mail_text"; + public static final String DELETED = "deleted"; + public static final String DELIVERY = "delivery"; + public static final String DELIVERY_DATE = "delivery_date"; + public static final String DESCRIPTION = "description"; + public static final String DOCUMENT = "document"; + public static final String DOCUMENT_ID = "document_id"; + public static final String DOC_TYPE_ID = "document_type_id"; + public static final String DOMAIN = "domain"; + public static final String DROP_MEMBER = "drop_member"; + public static final String DUE_DATE = "due_date"; + public static final String DURATION = "duration"; + + public static final String EMAIL = "email"; + public static final String END_TIME = "end_time"; + public static final String ENTITY_ID = "entity_id"; + public static final String EST_TIME = "est_time"; + public static final String EXPECTED = "expected"; + public static final String EXPIRATION = "expiration"; + + public static final String FIELD = "field"; + public static final String FOOTER = "footer"; + public static final String FROM = "from"; + public static final String FULLTEXT = "fulltext"; + + public static final String GROSS_SUM = "gross_sum"; + public static final String GUEST_ALLOWED = "guest_allowed"; + + public static final String HASH = "hash"; + public static final String HEAD = "head"; + + public static final String ID = "id"; + public static final String ITEM = "item"; + public static final String ITEM_CODE = "item_code"; + + public static final String KEY = "key"; + + public static final String LANGUAGE = "language"; + public static final String LAST_CUSTOMER_NUMBER = "last_customer_number"; + public static final String LIMIT = "limit"; + public static final String LOCATION = "location"; + public static final String LOCATION_ID = "location_id"; + public static final String LOCATIONS = "locations"; + public static final String LOGIN = "login"; + public static final String MEMBERS = "members"; + public static final String MIME = "mime"; + public static final String MODULE = "module"; + + public static final String NAME = "name"; + public static final String NEW_MEMBER = "new_member"; + public static final String NET_PRICE = "net_price"; + public static final String NET_SUM = "net_sum"; + public static final String NEXT_TYPE = "next_type_id"; + public static final String NO_INDEX = "no_index"; + public static final String NOTE = "note"; + public static final String NUMBER = "number"; + + public static final String OBJECT = "object"; + public static final String OFFSET = "offset"; + public static final String OPTIONAL = "optional"; + public static final String OWNER = "owner"; + public static final String OWNER_NUMBER = "owner_number"; + + public static final String PARENT_LOCATION_ID = "parent_location_id"; + public static final String PARENT_TASK_ID = "parent_task_id"; + public static final String PASS = "pass"; + public static final String PASSWORD = "password"; + public static final String PATH = "path"; + public static final String PERMISSION = "permission"; + public static final String PHONE = "phone"; + public static final String POS = "pos"; + public static final String POSITIONS = "positions"; + public static final String PRICE = "single_price"; + public static final String PRICE_FORMAT = "price_format"; + public static final String PRIORITY = "priority"; + public static final String PROJECT_ID = "project_id"; + public static final String PROPERTIES = "properties"; + + public static final String RECEIVERS = "receivers"; + public static final String REDIRECT = "redirect"; + public static final String RENDERED = "rendered"; + public static final String REQUIRED_TASKS_IDS = "required_tasks_ids"; + + public static final String SENDER = "sender"; + public static final String SETTINGS = "settings"; + public static final String SHOW_CLOSED = "show_closed"; + public static final String SOURCE = "source"; + public static final String START_DATE = "start_date"; + public static final String START_TIME = "start_time"; + public static final String STATE = "state"; + public static final String STATUS = "status"; + public static final String STATUS_CODE = "code"; + public static final String SUBJECT = "subject"; + + public static final String TABLE = "table"; + public static final String TAGS = "tags"; + public static final String TAG_COLORS = "tag_colors"; + public static final String TASK = "task"; + public static final String TASK_IDS = "task_ids"; + public static final String TASKS = "tasks"; + public static final String TAX = "tax"; + public static final String TAX_ID = "tax_id"; + public static final String TAX_NUMBER = "tax_number"; + public static final String TAX_RATE = "tax_rate"; + public static final String TEMPLATE = "template"; + public static final String TEMPLATE_ID = "template_id"; + public static final String TEXT = "text"; + public static final String THOUSANDS_SEPARATOR = "thousands_separator"; + public static final String THEME = "theme"; + public static final String TIME_ID = "time_id"; + public static final String TIMESTAMP = "timestamp"; + public static final String TITLE = "title"; + public static final String TO = "to"; + public static final String TOKEN = "token"; + public static final String TOTAL_PRIO = "total_prio"; + public static final String TYPE = "type"; + public static final String TYPE_ID = "type_id"; + + public static final String UNIT = "unit"; + public static final String UNIT_PRICE = "unit_price"; + public static final String URI = "uri"; + public static final String URL = "url"; + public static final String USER = "user"; + public static final String USERS = "users"; + public static final String USER_ID = "user_id"; + public static final String USER_LIST = "user_list"; + + public static final String VALUE = "value"; + public static final String VCARD = "vcard"; + public static final String VERSION = "version"; + public static final String VERSIONS = "versions"; + +} diff --git a/core/src/main/java/de/srsoftware/umbrella/core/constants/Module.java b/core/src/main/java/de/srsoftware/umbrella/core/constants/Module.java new file mode 100644 index 00000000..9eac47a0 --- /dev/null +++ b/core/src/main/java/de/srsoftware/umbrella/core/constants/Module.java @@ -0,0 +1,11 @@ +/* © SRSoftware 2025 */ +package de.srsoftware.umbrella.core.constants; + +public class Module { + public static final String BOOKMARK = "bookmark"; + public static final String COMPANY = "company"; + public static final String PROJECT = "project"; + public static final String TASK = "task"; + public static final String USER = "user"; + +} diff --git a/core/src/main/java/de/srsoftware/umbrella/core/Paths.java b/core/src/main/java/de/srsoftware/umbrella/core/constants/Path.java similarity index 54% rename from core/src/main/java/de/srsoftware/umbrella/core/Paths.java rename to core/src/main/java/de/srsoftware/umbrella/core/constants/Path.java index 14cd80a7..211715f0 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/Paths.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/constants/Path.java @@ -1,26 +1,49 @@ /* © SRSoftware 2025 */ -package de.srsoftware.umbrella.core; +package de.srsoftware.umbrella.core.constants; -public class Paths { - private Paths(){}; +public class Path { + private Path(){}; public static final String ADD = "add"; public static final String AVAILABLE = "available"; public static final String CSS = "css"; public static final String COMMON_TEMPLATES = "common_templates"; + public static final String COMPANY = "company"; + public static final String CONNECTED = "connected"; + + public static final String ITEM = "item"; + public static final String JSON = "json"; + public static final String LEGACY = "legacy"; public static final String LIST = "list"; + public static final String LOCATION = "location"; + public static final String LOCATIONS = "locations"; + public static final String LOGIN = "login"; + public static final String LOGOUT = "logout"; public static final String PAGE = "page"; + public static final String PASSWORD = "password"; + public static final String PROJECT = "project"; + public static final String PROPERTIES = "properties"; + public static final String PROPERTY = "property"; + + public static final String REDIRECT = "redirect"; + public static final String SEARCH = "search"; public static final String SERVICE = "service"; public static final String SETTINGS = "settings"; public static final String STATES = "states"; public static final String STARTED = "started"; + public static final String STATE = "state"; public static final String STOP = "stop"; public static final String SUBMIT = "submit"; + public static final String TAGGED = "tagged"; public static final String TOKEN = "token"; + + public static final String USER = "user"; + public static final String USES = "uses"; public static final String VIEW = "view"; + } diff --git a/core/src/main/java/de/srsoftware/umbrella/core/constants/Text.java b/core/src/main/java/de/srsoftware/umbrella/core/constants/Text.java new file mode 100644 index 00000000..80f7a284 --- /dev/null +++ b/core/src/main/java/de/srsoftware/umbrella/core/constants/Text.java @@ -0,0 +1,56 @@ +/* © SRSoftware 2025 */ +package de.srsoftware.umbrella.core.constants; + +/** + * This is a collection of messages that appear throughout the project + */ +public class Text { + public static final String BOOLEAN = "Boolean"; + public static final String BOOKMARK = "bookmark"; + public static final String COMPANIES = "companies"; + public static final String COMPANY = "company"; + public static final String COMPANY_WITH_ID = "company ({id})"; + public static final String CONTACT = "Contact"; + public static final String CONTACTS = "contacts"; + public static final String CONTACT_WITH_ID = "contact ({id})"; + public static final String CUSTOMER = "customer"; + public static final String CUSTOMER_SETTINGS = "customer settings"; + public static final String DOCUMENT = "document"; + public static final String DOCUMENTS = "documents"; + public static final String DOCUMENT_TYPE_ID = "document type id"; + public static final String DOCUMENT_WITH_ID = "document ({id})"; + public static final String INVALID_DB_CODE = "Encountered invalid dbCode: {code}"; + public static final String ITEM = "item"; + public static final String ITEMS = "items"; + public static final String LOCATION = "location"; + public static final String LOCATIONS = "locations"; + public static final String LOGIN_SERVICE = "login service"; + public static final String LONG = "Long"; + public static final String NOTE = "note"; + public static final String NOTE_WITH_ID = "note ({id})"; + public static final String NUMBER = "number"; + public static final String PATH = "path"; + public static final String PROJECT = "project"; + public static final String PROPERTIES = "properties"; + public static final String PROJECT_WITH_ID = "project ({id})"; + public static final String PROPERTY = "property"; + public static final String SENDER = "sender"; + public static final String SESSION = "session"; + public static final String SERVICE_WITH_ID = "service ({id})"; + public static final String SETTINGS = "settings"; + public static final String STRING = "string"; + public static final String TABLE_WITH_NAME = "table {name}"; + public static final String TAGS = "tags"; + public static final String TASK = "task"; + public static final String TASKS = "tasks"; + public static final String TIME_WITH_ID = "time ({id})"; + public static final String TYPE = "type"; + public static final String USER_WITH_ID = "user ({id})"; + public static final String WIKI_PAGE = "wiki page"; + public static final String WIKI_PAGES = "wiki pages"; + public static final String UNIT = "unit"; + public static final String T_UNIT_PRICE = "unit price"; + public static final String USER = "user"; + public static final String USERS = "users"; + +} diff --git a/core/src/main/java/de/srsoftware/umbrella/core/exceptions/UmbrellaException.java b/core/src/main/java/de/srsoftware/umbrella/core/exceptions/UmbrellaException.java index a8bd997e..eeb1da41 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/exceptions/UmbrellaException.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/exceptions/UmbrellaException.java @@ -1,72 +1,125 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.core.exceptions; -import static de.srsoftware.umbrella.core.Constants.*; +import static de.srsoftware.umbrella.core.Errors.*; import static de.srsoftware.umbrella.core.ResponseCode.HTTP_SERVER_ERROR; import static de.srsoftware.umbrella.core.ResponseCode.HTTP_UNPROCESSABLE; -import static java.lang.System.Logger.Level.ERROR; -import static java.lang.System.Logger.Level.WARNING; -import static java.net.HttpURLConnection.HTTP_FORBIDDEN; -import static java.net.HttpURLConnection.HTTP_NOT_FOUND; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static java.net.HttpURLConnection.*; + +import de.srsoftware.umbrella.core.model.Translatable; + public class UmbrellaException extends RuntimeException{ private final int statusCode; - private Object[] fills; + private final Translatable message; - public UmbrellaException(String message, Object ... fills){ - this(HTTP_SERVER_ERROR,message,fills); - } - - public UmbrellaException(int statusCode, String message, Object ... fills){ - super(message); - this.fills = fills; + public UmbrellaException(int statusCode, Translatable message){ + super(message.toString()); this.statusCode = statusCode; + this.message = message; } + public UmbrellaException(int statusCode, String rawMessage, Object ... args){ + this(statusCode, Translatable.t(rawMessage,args)); + } + + public static final UmbrellaException badRequest(String rawMessage, Object ... args){ + return new UmbrellaException(HTTP_BAD_REQUEST,rawMessage,args); + } public UmbrellaException causedBy(Exception e) { initCause(e); return this; } - public static UmbrellaException databaseException(String message, Object... fills) { - System.getLogger("Configuration").log(WARNING,message,fills); - return new UmbrellaException(message,fills); + public static UmbrellaException databaseException(String rawMessage, Object ... args) { + return new UmbrellaException(HTTP_SERVER_ERROR,rawMessage,args); } - public Object[] fills(){ - return fills; + public static UmbrellaException failedToCreateTable(String tableName){ + return databaseException(FAILED_TO_CREATE_TABLE, NAME,tableName); } - public static UmbrellaException forbidden(String message, Object... fills) { - return new UmbrellaException(HTTP_FORBIDDEN,message,fills); + public static UmbrellaException failedToDropObject(Object object){ + return databaseException(FAILED_TO_DROP_OBJECT, OBJECT,object); } - public static UmbrellaException invalidFieldException(String field,String expected){ - return new UmbrellaException(HTTP_UNPROCESSABLE, ERROR_INVALID_FIELD, field, expected); + public static UmbrellaException failedToDropObjectFromObject(String typeOfDropped, Object dropped, Object typeOfRelated, Object related){ + return databaseException(FAILED_TO_DROP_ENTITY_OF_ENTITY, + "dropped_type",typeOfDropped, + OBJECT,dropped, + "related_type", typeOfRelated, + "related",related); + } + + public static UmbrellaException failedToLoadMembers(Object object){ + return databaseException(FAILED_TO_LOAD_OBJECT_MEMBERS, OBJECT,object); + } + + public static UmbrellaException failedToLoadObject(Object object){ + return databaseException(FAILED_TO_LOAD_OBJECT, OBJECT,object); + } + + public static UmbrellaException failedToLoadObject(Object object, Object id){ + return databaseException(FAILED_TO_LOAD_OBJECT_BY_ID, OBJECT,object, ID,id); + } + + public static UmbrellaException failedToStoreObject(Object object){ + return databaseException(FAILED_TO_STORE_OBJECT, OBJECT,object); + } + + public static UmbrellaException failedToReadFromTable(String field, String table){ + return databaseException(FAILED_TO_READ_FROM_TABLE, FIELD,field, TABLE,table); + } + + public static UmbrellaException failedToSearchDb(Translatable module){ + return databaseException(FAILED_TO_SEARCH_DB, MODULE, module); + } + + public static UmbrellaException forbidden(String rawMessage, Object ... args) { + return new UmbrellaException(HTTP_FORBIDDEN,rawMessage,args); + } + + public static UmbrellaException invalidField(String field, Object expected){ + return new UmbrellaException(HTTP_UNPROCESSABLE, INVALID_FIELD, FIELD, field, EXPECTED, expected); + } + + public Translatable message(){ + return message; + } + + public static UmbrellaException missingConfig(String key){ + return new UmbrellaException(HTTP_SERVER_ERROR,MISSING_CONFIG, KEY,key); } - public static UmbrellaException missingConfigException(String field){ - System.getLogger("Configuration").log(ERROR,ERROR_MISSING_CONFIG, field); - return new UmbrellaException(ERROR_MISSING_CONFIG, field); + public static UmbrellaException missingField(String field){ + return new UmbrellaException(HTTP_UNPROCESSABLE, MISSING_FIELD, FIELD,field); } - - public static UmbrellaException missingFieldException(String field){ - return new UmbrellaException(HTTP_UNPROCESSABLE, ERROR_MISSING_FIELD, field); + public static UmbrellaException notAmember(Object object){ + return forbidden(NO_MEMBER, OBJECT,object); } - public static UmbrellaException notFound(String message, Object... fills) { - return new UmbrellaException(HTTP_NOT_FOUND,message,fills); + public static UmbrellaException notFound(String rawMessage, Object ... args) { + return new UmbrellaException(HTTP_NOT_FOUND,rawMessage,args); + } + + public static UmbrellaException serverError(String rawMessage, Object ... args){ + return new UmbrellaException(HTTP_SERVER_ERROR,rawMessage,args); } public int statusCode(){ return statusCode; } - public static UmbrellaException unprocessable(String message, Object... fills) { - return new UmbrellaException(HTTP_UNPROCESSABLE,message,fills); + public static UmbrellaException unauthorized(String rawMessage, Object ... args) { + return new UmbrellaException(HTTP_UNAUTHORIZED,rawMessage,args); + } + + public static UmbrellaException unprocessable(String rawMessage, Object ... args) { + return new UmbrellaException(HTTP_UNPROCESSABLE,rawMessage, args); } } diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Attachment.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Attachment.java index dbf8e59c..bfd46e37 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Attachment.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Attachment.java @@ -1,9 +1,10 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.core.model; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.invalidFieldException; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Text.STRING; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; +import static de.srsoftware.umbrella.core.model.Translatable.t; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import java.util.Arrays; @@ -29,11 +30,11 @@ public record Attachment(String name, String mime, byte[] content) { public static Attachment of(JSONObject json) throws UmbrellaException { for (var key : Set.of(NAME, MIME, DATA)) { - if (!json.has(key)) throw missingFieldException(key); + if (!json.has(key)) throw missingField(key); } - if (!(json.get(NAME) instanceof String name)) throw invalidFieldException(NAME,STRING); - if (!(json.get(MIME) instanceof String mime)) throw invalidFieldException(MIME,STRING); - if (!(json.get(DATA) instanceof String data)) throw invalidFieldException(DATA,STRING); + if (!(json.get(NAME) instanceof String name)) throw invalidField(NAME,t(STRING)); + if (!(json.get(MIME) instanceof String mime)) throw invalidField(MIME,t(STRING)); + if (!(json.get(DATA) instanceof String data)) throw invalidField(DATA,t(STRING)); return new Attachment(name,mime, BASE64.decode(data)); } } diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Bookmark.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Bookmark.java index 9ffaf6d8..d5d63d00 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Bookmark.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Bookmark.java @@ -1,8 +1,8 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.core.model; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.Util.markdown; +import static de.srsoftware.umbrella.core.Util.mapMarkdown; +import static de.srsoftware.umbrella.core.constants.Field.*; import static java.time.ZoneOffset.UTC; import de.srsoftware.tools.Mappable; @@ -28,7 +28,7 @@ public record Bookmark(long urlId, String url, String comment, LocalDateTime tim return Map.of( ID, urlId, URL, url, - COMMENT, Map.of(SOURCE,comment,RENDERED,markdown(comment)), + COMMENT, mapMarkdown(comment), TAGS, tags, TIMESTAMP, timestamp.withNano(0) ); diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Company.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Company.java index 8045c999..b84c7529 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Company.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Company.java @@ -2,10 +2,8 @@ package de.srsoftware.umbrella.core.model; import static de.srsoftware.tools.Optionals.emptyIfNull; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.Constants.COMPANY; -import static de.srsoftware.umbrella.core.Field.*; -import static de.srsoftware.umbrella.core.Field.TYPE; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Module.COMPANY; import static java.util.Map.entry; import de.srsoftware.tools.Mappable; @@ -147,19 +145,19 @@ public class Company implements Mappable, Owner { public Company patch(JSONObject json) { for (var key : json.keySet()){ switch (key){ - case NAME: name = json.getString(NAME); break; - case ADDRESS: address = json.getString(ADDRESS); break; - case COURT: court = json.getString(COURT); break; - case TAX_NUMBER: taxId = json.getString(TAX_NUMBER); break; - case PHONE: phone = json.getString(PHONE); break; - case DECIMAL_SEPARATOR: decimalSeparator = json.getString(DECIMAL_SEPARATOR); break; - case THOUSANDS_SEPARATOR: thousandsSeparator = json.getString(THOUSANDS_SEPARATOR); break; - case LAST_CUSTOMER_NUMBER: lastCustomerNumber = json.getLong(LAST_CUSTOMER_NUMBER); break; - case DECIMALS: decimals = json.getInt(DECIMALS); break; - case CUSTOMER_NUMBER_PREFIX: customerNumberPrefix = json.getString(CUSTOMER_NUMBER_PREFIX); break; - case CURRENCY: currency = json.getString(CURRENCY); break; - case EMAIL: email = json.getString(EMAIL); break; - case BANK_ACCOUNT: bankAccount = json.getString(BANK_ACCOUNT); break; + case NAME: name = json.getString(key); break; + case ADDRESS: address = json.getString(key); break; + case COURT: court = json.getString(key); break; + case TAX_NUMBER: taxId = json.getString(key); break; + case PHONE: phone = json.getString(key); break; + case DECIMAL_SEPARATOR: decimalSeparator = json.getString(key); break; + case THOUSANDS_SEPARATOR: thousandsSeparator = json.getString(key); break; + case LAST_CUSTOMER_NUMBER: lastCustomerNumber = json.getLong(key); break; + case DECIMALS: decimals = json.getInt(key); break; + case CUSTOMER_NUMBER_PREFIX: customerNumberPrefix = json.getString(key); break; + case CURRENCY: currency = json.getString(key); break; + case EMAIL: email = json.getString(key); break; + case BANK_ACCOUNT: bankAccount = json.getString(key); break; default: key = null; } if (key != null) dirtyFields.add(key); diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Contact.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Contact.java index 28b3d0a8..564c8991 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Contact.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Contact.java @@ -1,8 +1,8 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.core.model; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; import static java.text.MessageFormat.format; import de.srsoftware.tools.Mappable; @@ -31,8 +31,8 @@ public class Contact implements Mappable{ } public Contact patch(JSONObject json) { - if (!(json.get(FROM) instanceof String from)) throw missingFieldException(FROM); - if (!(json.get(TO) instanceof String to)) throw missingFieldException(TO); + if (!(json.get(FROM) instanceof String from)) throw missingField(FROM); + if (!(json.get(TO) instanceof String to)) throw missingField(TO); return new Contact(id,vcard.replace(from, to)); } diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Customer.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Customer.java index b2b1e2b2..9f79eb7c 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Customer.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Customer.java @@ -2,9 +2,9 @@ package de.srsoftware.umbrella.core.model; import static de.srsoftware.tools.Optionals.emptyIfNull; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.Field.*; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException; +import static de.srsoftware.umbrella.core.constants.Constants.FALLBACK_LANG; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; import de.srsoftware.tools.Mappable; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; @@ -68,9 +68,9 @@ public final class Customer implements Mappable { } public static Customer of(JSONObject json) throws UmbrellaException { - if (!json.has(ID) || !(json.get(ID) instanceof String id)) throw missingFieldException(ID); - if (!json.has(NAME) || !(json.get(NAME) instanceof String name)) throw missingFieldException(NAME); - if (!json.has(EMAIL) || !(json.get(EMAIL) instanceof String email)) throw missingFieldException(EMAIL); + if (!json.has(ID) || !(json.get(ID) instanceof String id)) throw missingField(ID); + if (!json.has(NAME) || !(json.get(NAME) instanceof String name)) throw missingField(NAME); + if (!json.has(EMAIL) || !(json.get(EMAIL) instanceof String email)) throw missingField(EMAIL); var taxId = json.has(TAX_ID) && json.get(TAX_ID) instanceof String tid ? tid : null; var lang = json.has(LANGUAGE) && json.get(LANGUAGE) instanceof String l ? l : FALLBACK_LANG; return new Customer(id,name,email,taxId,lang); diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/DbLocation.java b/core/src/main/java/de/srsoftware/umbrella/core/model/DbLocation.java index 78e6c548..f046bbdc 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/DbLocation.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/DbLocation.java @@ -1,8 +1,8 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.core.model; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.Util.markdown; +import static de.srsoftware.umbrella.core.Util.mapMarkdown; +import static de.srsoftware.umbrella.core.constants.Field.*; import de.srsoftware.umbrella.core.api.Owner; import java.sql.ResultSet; @@ -69,10 +69,10 @@ public class DbLocation extends Location { parentLocationId = json.getLong(field); break; case NAME: - name = json.getString(NAME); + name = json.getString(field); break; case DESCRIPTION: - description = json.getString(DESCRIPTION); + description = json.getString(field); break; default: known = false; @@ -93,7 +93,7 @@ public class DbLocation extends Location { if (description == null) description = ""; map.put(OWNER,owner.toMap()); map.put(NAME,name); - map.put(DESCRIPTION,Map.of(SOURCE,description,RENDERED,markdown(description))); + map.put(DESCRIPTION,mapMarkdown(description)); if (parentLocationId != null) map.put(PARENT_LOCATION_ID,parentLocationId); return map; } diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Document.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Document.java index e444703b..d88ca370 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Document.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Document.java @@ -2,12 +2,9 @@ package de.srsoftware.umbrella.core.model; import static de.srsoftware.tools.Optionals.emptyIfNull; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.Field.*; -import static de.srsoftware.umbrella.core.Field.COMPANY; -import static de.srsoftware.umbrella.core.Field.TYPE; import static de.srsoftware.umbrella.core.ResponseCode.HTTP_UNPROCESSABLE; import static de.srsoftware.umbrella.core.Util.mapMarkdown; +import static de.srsoftware.umbrella.core.constants.Field.*; import static java.util.Optional.empty; import de.srsoftware.tools.Mappable; @@ -205,7 +202,7 @@ public final class Document implements Mappable { case HEAD: head = json.getString(key); break; case NUMBER: number = json.getString(key); break; case SENDER: if (json.get(key) instanceof JSONObject nested) sender.patch(nested); break; - case STATE: state = State.of(json.getInt(key)).orElseThrow(() -> new UmbrellaException(HTTP_UNPROCESSABLE,"Invalid state")); break; + case STATE: state = State.of(json.getInt(key)).orElseThrow(() -> new UmbrellaException(HTTP_UNPROCESSABLE, Translatable.t("Invalid state"))); break; case POS: if (json.get(key) instanceof JSONObject nested) positions.patch(nested); break; case TEMPLATE: if (json.get(key) instanceof String templateId) template = templateId; break; default: key = null; @@ -279,7 +276,7 @@ public final class Document implements Mappable { ID, id, NUMBER, number, "type", type.name(), - STATE, Map.of(NAME,state.toString(),ID,state.code), + STATE, Map.of(NAME,state.toString(), ID,state.code), DATE, date, CURRENCY, currency, CUSTOMER, customer.toMap(), diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/EmailAddress.java b/core/src/main/java/de/srsoftware/umbrella/core/model/EmailAddress.java index 9d662607..10fa5140 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/EmailAddress.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/EmailAddress.java @@ -2,7 +2,9 @@ package de.srsoftware.umbrella.core.model; import static de.srsoftware.tools.Optionals.allSet; -import static java.net.HttpURLConnection.HTTP_BAD_REQUEST; +import static de.srsoftware.umbrella.core.Errors.INVALID_EMAIL; +import static de.srsoftware.umbrella.core.constants.Field.EMAIL; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.badRequest; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import java.util.Objects; @@ -12,7 +14,7 @@ public class EmailAddress { public EmailAddress(String addr) throws UmbrellaException { var parts = addr.split("@"); - if (parts.length != 2 || !allSet(parts[0],parts[1])) throw new UmbrellaException(HTTP_BAD_REQUEST,"\"{0}\" is not a valid email address",addr); + if (parts.length != 2 || !allSet(parts[0],parts[1])) throw badRequest(INVALID_EMAIL, EMAIL,addr); email = addr; } diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Envelope.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Envelope.java index 8343118b..80460859 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Envelope.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Envelope.java @@ -1,9 +1,11 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.core.model; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.invalidFieldException; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException; +import static de.srsoftware.umbrella.core.constants.Constants.JSONARRAY; +import static de.srsoftware.umbrella.core.constants.Constants.JSONOBJECT; +import static de.srsoftware.umbrella.core.constants.Field.RECEIVERS; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; +import static de.srsoftware.umbrella.core.model.Translatable.t; import static java.text.MessageFormat.format; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; @@ -34,14 +36,14 @@ public class Envelope { * @throws UmbrellaException */ public static Envelope from(JSONObject json) throws UmbrellaException { - if (!json.has(RECEIVERS)) throw missingFieldException(RECEIVERS); + if (!json.has(RECEIVERS)) throw missingField(RECEIVERS); var message = Message.from(json); var obj = json.get(RECEIVERS); if (obj instanceof JSONObject) obj = new JSONArray(List.of(obj)); - if (!(obj instanceof JSONArray receiverList)) throw invalidFieldException(RECEIVERS, JSONARRAY); + if (!(obj instanceof JSONArray receiverList)) throw invalidField(RECEIVERS, t(JSONARRAY)); var receivers = new HashSet(); for (var o : receiverList){ - if (!(o instanceof JSONObject receiverData)) throw invalidFieldException("entries of "+ RECEIVERS, JSONOBJECT); + if (!(o instanceof JSONObject receiverData)) throw invalidField("entries of "+ RECEIVERS, t(JSONOBJECT)); receivers.add(User.of(receiverData)); } return new Envelope(message,receivers); diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Item.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Item.java index 70cd93e3..e7fbc43e 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Item.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Item.java @@ -1,11 +1,12 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.core.model; -import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.Util.mapMarkdown; +import static de.srsoftware.umbrella.core.constants.Field.*; import de.srsoftware.tools.Mappable; import de.srsoftware.umbrella.core.api.Owner; +import de.srsoftware.umbrella.core.constants.Field; import java.sql.ResultSet; import java.sql.SQLException; import java.util.*; @@ -75,7 +76,7 @@ public class Item implements Mappable { var owner = OwnerRef.of(rs); var ownerNumber = rs.getLong(OWNER_NUMBER); var location = Location.of(rs); - var code = rs.getString(CODE); + var code = rs.getString(Field.CODE); var name = rs.getString(NAME); var description = rs.getString(DESCRIPTION); return new Item(id, owner, ownerNumber, location, code, name, description); @@ -97,7 +98,7 @@ public class Item implements Mappable { for (var field : json.keySet()){ var known = true; switch (field) { - case CODE: + case Field.CODE: code = json.getString(field); break; case NAME: @@ -124,7 +125,7 @@ public class Item implements Mappable { map.put(OWNER,owner.toMap()); map.put(ID,id); map.put(LOCATION,location.toMap()); - map.put(CODE,code); + map.put(Field.CODE,code); map.put(NAME,name); map.put(DESCRIPTION,mapMarkdown(description)); map.put(OWNER_NUMBER,ownerNumber); diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Location.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Location.java index 8381da4e..44d31958 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Location.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Location.java @@ -1,9 +1,9 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.core.model; -import static de.srsoftware.umbrella.core.Constants.ID; -import static de.srsoftware.umbrella.core.Constants.LOCATION_ID; import static de.srsoftware.umbrella.core.ModuleRegistry.stockService; +import static de.srsoftware.umbrella.core.constants.Field.ID; +import static de.srsoftware.umbrella.core.constants.Field.LOCATION_ID; import static java.text.MessageFormat.format; import de.srsoftware.tools.Mappable; diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Member.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Member.java index 896d8018..d46fe82b 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Member.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Member.java @@ -2,7 +2,8 @@ package de.srsoftware.umbrella.core.model; -import static de.srsoftware.umbrella.core.Constants.*; +import static de.srsoftware.umbrella.core.constants.Field.PERMISSION; +import static de.srsoftware.umbrella.core.constants.Field.USER; import de.srsoftware.tools.Mappable; import java.util.HashMap; diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Message.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Message.java index 2ebf159a..f18a0677 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Message.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Message.java @@ -2,9 +2,11 @@ package de.srsoftware.umbrella.core.model; import static de.srsoftware.tools.Optionals.isSet; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.invalidFieldException; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException; +import static de.srsoftware.umbrella.core.constants.Constants.JSONOBJECT; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Text.STRING; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; +import static de.srsoftware.umbrella.core.model.Translatable.t; import static java.text.MessageFormat.format; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; @@ -21,21 +23,21 @@ public record Message(UmbrellaUser sender, String subject, String body, Map(); if (json.has(ATTACHMENTS)){ var jsonAttachments = json.get(ATTACHMENTS); if (jsonAttachments instanceof JSONObject obj) jsonAttachments = new JSONArray(List.of(obj)); if (jsonAttachments instanceof JSONArray arr){ for (var att : arr){ - if (!(att instanceof JSONObject o)) throw new UmbrellaException(400,"Attachments contains entry that is not an object: {}",att); + if (!(att instanceof JSONObject o)) throw new UmbrellaException(400, t("Attachments contains entry that is not an object: {entry}","entry",att)); var attachment = Attachment.of(o); attachments.add(attachment); } diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Note.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Note.java index adf28ab3..26410b12 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Note.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Note.java @@ -1,8 +1,8 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.core.model; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.Util.markdown; +import static de.srsoftware.umbrella.core.Util.mapMarkdown; +import static de.srsoftware.umbrella.core.constants.Field.*; import static java.time.ZoneOffset.UTC; import de.srsoftware.tools.Mappable; @@ -72,7 +72,7 @@ public class Note implements Mappable { MODULE,module, ENTITY_ID,entityId, USER_ID,authorId, - TEXT,Map.of(RENDERED,markdown(text),SOURCE,text), + TEXT,mapMarkdown(text), TIMESTAMP,timestamp.withNano(0) ); } diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/OwnerRef.java b/core/src/main/java/de/srsoftware/umbrella/core/model/OwnerRef.java index 1a64888f..962ff163 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/OwnerRef.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/OwnerRef.java @@ -1,13 +1,16 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.core.model; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.Constants.ID; +import static de.srsoftware.umbrella.core.constants.Module.COMPANY; import static de.srsoftware.umbrella.core.ModuleRegistry.companyService; import static de.srsoftware.umbrella.core.ModuleRegistry.userService; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.unprocessable; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Module.USER; +import static de.srsoftware.umbrella.core.constants.Text.INVALID_DB_CODE; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; import de.srsoftware.umbrella.core.api.Owner; +import de.srsoftware.umbrella.core.constants.Field; import java.sql.ResultSet; import java.sql.SQLException; import java.util.HashMap; @@ -20,12 +23,12 @@ public class OwnerRef implements Owner { public OwnerRef(String dbCode){ var parts = dbCode.split(":"); - if (parts.length != 2) throw unprocessable("Encountered invalid dbCode: {0}",dbCode); + if (parts.length != 2) throw unprocessable(INVALID_DB_CODE, Field.CODE,dbCode); type = parts[0]; try { id = Long.parseLong(parts[1]); } catch (NumberFormatException e) { - throw unprocessable("Encountered invalid dbCode: {0}",dbCode); + throw unprocessable(INVALID_DB_CODE, Field.CODE,dbCode); } } @@ -59,7 +62,7 @@ public class OwnerRef implements Owner { return switch (type){ case COMPANY -> companyService().get(id()); case USER -> userService().loadUser(id()); - case null, default -> throw unprocessable("Encountered invalid owner type: {0}",type); + case null, default -> throw unprocessable("Encountered invalid owner type: {type}", TYPE,type); }; } diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Permission.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Permission.java index 9e9506bc..5f0bd945 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Permission.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Permission.java @@ -1,11 +1,11 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.core.model; -import static de.srsoftware.umbrella.core.Constants.CODE; -import static de.srsoftware.umbrella.core.Constants.NAME; +import static de.srsoftware.umbrella.core.constants.Field.NAME; import static java.text.MessageFormat.format; import de.srsoftware.tools.Mappable; +import de.srsoftware.umbrella.core.constants.Field; import java.security.InvalidParameterException; import java.util.Map; @@ -36,7 +36,7 @@ public enum Permission implements Mappable { @Override public Map toMap() { - return Map.of(NAME,name(),CODE,code); + return Map.of(NAME,name(), Field.CODE,code); } public boolean mayWrite() { diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Position.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Position.java index 7acd4108..5a52a939 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Position.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Position.java @@ -2,11 +2,8 @@ package de.srsoftware.umbrella.core.model; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.Field.*; -import static de.srsoftware.umbrella.core.Field.TAX; -import static de.srsoftware.umbrella.core.Field.UNIT; import static de.srsoftware.umbrella.core.Util.mapMarkdown; +import static de.srsoftware.umbrella.core.constants.Field.*; import de.srsoftware.tools.Mappable; import java.util.*; diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/PositionList.java b/core/src/main/java/de/srsoftware/umbrella/core/model/PositionList.java index 623ca1a5..5eb168ce 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/PositionList.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/PositionList.java @@ -1,14 +1,10 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.core.model; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.Field.*; -import static de.srsoftware.umbrella.core.Field.END_TIME; -import static de.srsoftware.umbrella.core.Field.START_TIME; -import static de.srsoftware.umbrella.core.Field.TAX; -import static de.srsoftware.umbrella.core.Field.UNIT; +import static de.srsoftware.umbrella.core.constants.Field.*; import de.srsoftware.tools.Pair; +import de.srsoftware.umbrella.core.constants.Field; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import java.util.HashMap; import java.util.Map; @@ -24,7 +20,7 @@ public class PositionList extends HashMap { } public Position addItem(JSONObject item) { - var itemCode = item.getString(CODE); + var itemCode = item.getString(Field.CODE); var unit = item.getString(UNIT); var name = item.getString(NAME); var description = item.getString(DESCRIPTION); diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Project.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Project.java index 2525c073..106303e7 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Project.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Project.java @@ -2,11 +2,12 @@ package de.srsoftware.umbrella.core.model; import static de.srsoftware.tools.Optionals.nullable; -import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.Util.mapMarkdown; +import static de.srsoftware.umbrella.core.constants.Field.*; import static de.srsoftware.umbrella.core.model.Status.PREDEFINED; import de.srsoftware.tools.Mappable; +import de.srsoftware.umbrella.core.constants.Field; import java.sql.ResultSet; import java.sql.SQLException; import java.util.*; @@ -138,7 +139,7 @@ public class Project implements Mappable { map.put(MEMBERS,memberMap); var stateMap = new HashMap(); for (var state : allowedStates) stateMap.put(state.code(),state.name()); - map.put(ALLOWED_STATES,stateMap); + map.put(Field.ALLOWED_STATES,stateMap); map.put(TAG_COLORS,tagColors); return map; } diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Property.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Property.java index f0a6ad18..2082be82 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Property.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Property.java @@ -1,7 +1,7 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.core.model; -import static de.srsoftware.umbrella.core.Constants.*; +import static de.srsoftware.umbrella.core.constants.Field.*; import static java.text.MessageFormat.format; import de.srsoftware.tools.Mappable; diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Sender.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Sender.java index eab1a858..8dd1d4e9 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Sender.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Sender.java @@ -1,9 +1,8 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.core.model; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.Field.*; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; import de.srsoftware.tools.Mappable; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; @@ -65,10 +64,10 @@ public final class Sender implements Mappable { } public static Sender of(JSONObject json) throws UmbrellaException { - if (!json.has(NAME) || !(json.get(NAME) instanceof String name)) throw missingFieldException(NAME); - if (!json.has(BANK_ACCOUNT) || !(json.get(BANK_ACCOUNT) instanceof String bankAccount)) throw missingFieldException(BANK_ACCOUNT); - if (!json.has(TAX_ID) || !(json.get(TAX_ID) instanceof String taxId)) throw missingFieldException(TAX_ID); - if (!json.has(COURT) || !(json.get(COURT) instanceof String court)) throw missingFieldException(COURT); + if (!json.has(NAME) || !(json.get(NAME) instanceof String name)) throw missingField(NAME); + if (!json.has(BANK_ACCOUNT) || !(json.get(BANK_ACCOUNT) instanceof String bankAccount)) throw missingField(BANK_ACCOUNT); + if (!json.has(TAX_ID) || !(json.get(TAX_ID) instanceof String taxId)) throw missingField(TAX_ID); + if (!json.has(COURT) || !(json.get(COURT) instanceof String court)) throw missingField(COURT); return new Sender(name,bankAccount,taxId,court); } diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Status.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Status.java index 615d9a98..32e8b346 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Status.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Status.java @@ -1,10 +1,12 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.core.model; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.invalidFieldException; +import static de.srsoftware.umbrella.core.constants.Field.NAME; +import static de.srsoftware.umbrella.core.constants.Field.STATUS; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; import de.srsoftware.tools.Mappable; +import de.srsoftware.umbrella.core.constants.Field; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; @@ -26,7 +28,7 @@ public record Status(String name, int code) implements Mappable { case "started" -> STARTED; case "complete" -> COMPLETE; case "cancelled" -> CANCELLED; - case null, default -> throw invalidFieldException(STATUS,"one of: "+PREDEFINED.stream().map(Status::name).collect(Collectors.joining(", "))); + case null, default -> throw invalidField(STATUS,"one of: "+PREDEFINED.stream().map(Status::name).collect(Collectors.joining(", "))); }; } @@ -42,11 +44,11 @@ public record Status(String name, int code) implements Mappable { } public static Status of(ResultSet rs) throws SQLException { - return new Status(rs.getString(NAME),rs.getInt(CODE)); + return new Status(rs.getString(NAME),rs.getInt(Field.CODE)); } @Override public Map toMap() { - return Map.of(NAME,name,CODE,code); + return Map.of(NAME,name, Field.CODE,code); } } \ No newline at end of file diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Task.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Task.java index 0e770711..72b9acaf 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Task.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Task.java @@ -2,13 +2,13 @@ package de.srsoftware.umbrella.core.model; import static de.srsoftware.tools.Optionals.nullIfEmpty; -import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.Util.*; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.invalidFieldException; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; import static java.lang.System.Logger.Level.WARNING; import de.srsoftware.tools.Mappable; +import de.srsoftware.umbrella.core.constants.Field; import java.sql.ResultSet; import java.sql.SQLException; import java.time.LocalDate; @@ -130,25 +130,25 @@ public class Task implements Mappable { } public static Task of(JSONObject json){ - if (!(json.has(PROJECT_ID) && json.get(PROJECT_ID) instanceof Number prjId)) throw missingFieldException(PROJECT_ID); + if (!(json.has(PROJECT_ID) && json.get(PROJECT_ID) instanceof Number prjId)) throw missingField(PROJECT_ID); Long parentTaskId = json.has(PARENT_TASK_ID) && json.get(PARENT_TASK_ID) instanceof Number ptid ? ptid.longValue() : null; - if (!(json.has(NAME) && json.get(NAME) instanceof String name && !name.isBlank())) throw missingFieldException(NAME); - if (!json.has(DESCRIPTION)) throw missingFieldException(DESCRIPTION); + if (!(json.has(NAME) && json.get(NAME) instanceof String name && !name.isBlank())) throw missingField(NAME); + if (!json.has(DESCRIPTION)) throw missingField(DESCRIPTION); var description = switch (json.get(DESCRIPTION)){ case String d -> d; case JSONObject j -> j.getString(SOURCE); - default -> throw invalidFieldException(json.get(DESCRIPTION).getClass().getSimpleName(),"String or JSON"); + default -> throw invalidField(json.get(DESCRIPTION).getClass().getSimpleName(),"String or JSON"); }; var status = Status.OPEN.code(); if (json.has(STATUS) && json.get(STATUS) instanceof JSONObject state){ - if (state.get(CODE) instanceof Number code) status = code.intValue(); + if (state.get(Field.CODE) instanceof Number code) status = code.intValue(); } Double estimatedTime = null; - if (json.has(ESTIMATED_TIME)) { - if (json.get(ESTIMATED_TIME) instanceof Number est) estimatedTime = est.doubleValue(); - if (json.get(ESTIMATED_TIME) instanceof String est) try { + if (json.has(EST_TIME)) { + if (json.get(EST_TIME) instanceof Number est) estimatedTime = est.doubleValue(); + if (json.get(EST_TIME) instanceof String est) try { estimatedTime = Double.parseDouble(est); } catch (NumberFormatException ignored) { } @@ -158,7 +158,7 @@ public class Task implements Mappable { var showClosed = json.has(SHOW_CLOSED) && json.get(SHOW_CLOSED) instanceof Boolean sc ? sc : false; var noIndex = json.has(NO_INDEX) && json.get(NO_INDEX) instanceof Boolean ni ? ni : false; var priority = json.has(PRIORITY) && json.get(PRIORITY) instanceof Number pr ? prjId.intValue() : 0; - if (!(json.has(MEMBERS) && json.get(MEMBERS) instanceof JSONObject)) throw missingFieldException(MEMBERS); + if (!(json.has(MEMBERS) && json.get(MEMBERS) instanceof JSONObject)) throw missingField(MEMBERS); return new Task(0,prjId.longValue(),parentTaskId,name,description,status,estimatedTime,startDate,dueDate,showClosed,noIndex,new HashMap<>(),priority); } @@ -167,7 +167,7 @@ public class Task implements Mappable { switch (key){ case DESCRIPTION: description = json.getString(key); break; case DUE_DATE: dueDate = json.isNull(DUE_DATE) || json.getString(DUE_DATE).isBlank() ? null : LocalDate.parse(json.getString(DUE_DATE)); break; - case ESTIMATED_TIME: estimatedTime = json.isNull(ESTIMATED_TIME) ? null : json.getDouble(ESTIMATED_TIME); break; + case EST_TIME: estimatedTime = json.isNull(EST_TIME) ? null : json.getDouble(EST_TIME); break; case MEMBERS: continue; case NAME: name = json.getString(key); break; case NO_INDEX: noIndex = json.getBoolean(NO_INDEX); break; @@ -232,7 +232,7 @@ public class Task implements Mappable { map.put(NAME, name); map.put(DESCRIPTION, mapMarkdown(description)); map.put(STATUS, status); - map.put(ESTIMATED_TIME, estimatedTime); + map.put(EST_TIME, estimatedTime); map.put(START_DATE,start); map.put(DUE_DATE,dueDate); map.put(NO_INDEX,noIndex); diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Time.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Time.java index 43ec67f8..319fd3b0 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Time.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Time.java @@ -1,12 +1,13 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.core.model; -import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.Util.*; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.invalidFieldException; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.unprocessable; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; +import static de.srsoftware.umbrella.core.model.Translatable.t; import de.srsoftware.tools.Mappable; +import de.srsoftware.umbrella.core.constants.Field; import java.sql.ResultSet; import java.sql.SQLException; import java.time.LocalDateTime; @@ -127,13 +128,13 @@ public class Time implements Mappable{ if (json.has(START_TIME) && json.get(START_TIME) instanceof Number st) start = st.longValue(); if (json.has(END_TIME) && json.get(END_TIME) instanceof Number e) end = e.longValue(); if (end == 0) end = null; - if (end != null && end < start) throw invalidFieldException(END_TIME,"after start_time"); + if (end != null && end < start) throw invalidField(END_TIME,"after start_time"); if (json.has(STATE)) { var o = json.get(STATE); try { switch (o) { case JSONObject nested: - state = State.of(nested.getInt(CODE)); + state = State.of(nested.getInt(Field.CODE)); break; case String stateName: state = State.valueOf(stateName); @@ -142,10 +143,10 @@ public class Time implements Mappable{ state = State.of(stateCode.intValue()); break; default: - throw invalidFieldException(STATE, "state name or code"); + throw invalidField(STATE, t("state name or code")); } } catch (Exception e){ - throw unprocessable("\"{0}\" is not a valid state name or code!",o); + throw unprocessable("\"{value}\" is not a valid state name or code!",VALUE,o); } } return this; @@ -193,7 +194,7 @@ public class Time implements Mappable{ map.put(DESCRIPTION,mapMarkdown(description)); map.put(START_TIME,start); map.put(END_TIME,end); - map.put(STATE,Map.of(STATUS_CODE,state.code,NAME,state.name())); + map.put(STATE,Map.of(STATUS_CODE,state.code, NAME,state.name())); map.put(DURATION,end == null ? null : (end - start)/3600d); map.put(TASK_IDS,taskIds); return map; diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Token.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Token.java index ba29617a..9e8c422d 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Token.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Token.java @@ -1,7 +1,7 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.core.model; -import static de.srsoftware.umbrella.core.Constants.TOKEN; +import static de.srsoftware.umbrella.core.constants.Field.TOKEN; import de.srsoftware.tools.SessionToken; import de.srsoftware.umbrella.core.AddableMap; diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Translatable.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Translatable.java new file mode 100644 index 00000000..3c6049fe --- /dev/null +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Translatable.java @@ -0,0 +1,61 @@ +/* © SRSoftware 2025 */ +package de.srsoftware.umbrella.core.model; + +import de.srsoftware.umbrella.core.ModuleRegistry; +import java.util.HashMap; +import java.util.Map; + +public class Translatable { + private final String message; + private Map fills; + private final HashMap translated = new HashMap<>(); + + public Translatable(String message, Map fills){ + this.fills = fills; + this.message = message; + } + + public static Map argMap(Object ... args){ + var map = new HashMap(); + int i = 0; + while (i+1 args){ + return new Translatable(message,args); + } + + public String translate(String language){ + var translation = language != null ? translated.get(language) : null; + if (translation == null){ + var translatedFills = new HashMap(); + if (fills != null) { + for (var entry : fills.entrySet()) { + var o = entry.getValue(); + var val = switch (o) { + case Translatable tr -> tr.translate(language); + case String s -> s; + default -> o.toString(); + }; + translatedFills.put(entry.getKey(), val); + } + } + translation = ModuleRegistry.translator().translate(language,message,translatedFills); + if (translation != null) translated.put(language,translation); + } + return translation; + } +} diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/UmbrellaUser.java b/core/src/main/java/de/srsoftware/umbrella/core/model/UmbrellaUser.java index 8ee89970..653b9692 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/UmbrellaUser.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/UmbrellaUser.java @@ -2,10 +2,11 @@ package de.srsoftware.umbrella.core.model; -import static de.srsoftware.umbrella.core.Constants.*; +import static de.srsoftware.umbrella.core.constants.Field.*; import de.srsoftware.tools.Mappable; import de.srsoftware.umbrella.core.api.Owner; +import de.srsoftware.umbrella.core.constants.Module; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -63,6 +64,6 @@ public class UmbrellaUser extends User implements Mappable, Owner { @Override public String type() { - return USER; + return Module.USER; } } diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/User.java b/core/src/main/java/de/srsoftware/umbrella/core/model/User.java index e6ca36bb..35c08ef7 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/User.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/User.java @@ -1,12 +1,8 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.core.model; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.Constants.EMAIL; -import static de.srsoftware.umbrella.core.Constants.LANGUAGE; -import static de.srsoftware.umbrella.core.Constants.NAME; -import static de.srsoftware.umbrella.core.Constants.THEME; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; import static java.text.MessageFormat.format; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; @@ -38,9 +34,9 @@ public class User { public static User of(JSONObject json) throws UmbrellaException { if (json.has(USER)) json = json.getJSONObject(USER); - if (!(json.has(NAME) && json.get(NAME) instanceof String name)) throw missingFieldException(NAME); - if (!(json.has(EMAIL) && json.get(EMAIL) instanceof String email)) throw missingFieldException(EMAIL); - if (!(json.has(LANGUAGE) && json.get(LANGUAGE) instanceof String lang)) throw missingFieldException(LANGUAGE); + if (!(json.has(NAME) && json.get(NAME) instanceof String name)) throw missingField(NAME); + if (!(json.has(EMAIL) && json.get(EMAIL) instanceof String email)) throw missingField(EMAIL); + if (!(json.has(LANGUAGE) && json.get(LANGUAGE) instanceof String lang)) throw missingField(LANGUAGE); var addr = new EmailAddress(email); if (json.has(ID) && json.get(ID) instanceof Number id) { diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/WikiPage.java b/core/src/main/java/de/srsoftware/umbrella/core/model/WikiPage.java index 5cfaf187..3327c636 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/WikiPage.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/WikiPage.java @@ -1,10 +1,14 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.core.model; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.Util.markdown; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.invalidFieldException; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.unprocessable; +import static de.srsoftware.umbrella.core.Util.mapMarkdown; +import static de.srsoftware.umbrella.core.constants.Constants.JSONOBJECT; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Text.BOOLEAN; +import static de.srsoftware.umbrella.core.constants.Text.STRING; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; +import static de.srsoftware.umbrella.core.model.Translatable.t; +import static java.lang.String.join; import de.srsoftware.tools.Mappable; import de.srsoftware.umbrella.core.api.UserService; @@ -77,29 +81,29 @@ public class WikiPage implements Mappable { var val = json.get(key); switch (key){ case ID: - throw unprocessable("{0} cannot be altered!",ID); + throw unprocessable("{field} cannot be altered!", FIELD, ID); case CONTENT: - if (!(val instanceof String s)) throw invalidFieldException(CONTENT,"String"); + if (!(val instanceof String s)) throw invalidField(CONTENT,t(STRING)); content(s); break; case GUEST_ALLOWED: - if (!(val instanceof Boolean b)) throw invalidFieldException(GUEST_ALLOWED,"Boolean"); + if (!(val instanceof Boolean b)) throw invalidField(GUEST_ALLOWED, t(BOOLEAN)); guestAllowed(b); break; case MEMBERS: - if (!(val instanceof JSONObject membersJson)) throw invalidFieldException(MEMBERS,"Json"); + if (!(val instanceof JSONObject membersJson)) throw invalidField(MEMBERS,t(JSONOBJECT)); for (var uid : membersJson.keySet()){ var userId = Long.parseLong(uid); var user = users.loadUser(userId); - if (!(membersJson.get(uid) instanceof JSONObject memberJSON)) throw invalidFieldException(MEMBERS+"."+uid,"Json"); + if (!(membersJson.get(uid) instanceof JSONObject memberJSON)) throw invalidField(MEMBERS +"."+uid,t(JSONOBJECT)); var p = memberJSON.get(PERMISSION); if (p == JSONObject.NULL){ members.remove(userId); dirtyFields.add(MEMBERS); break; } - if (!(p instanceof JSONObject perm)) throw invalidFieldException(String.join(".",MEMBERS,uid,PERMISSION),"Json"); - if (!(perm.get(NAME) instanceof String permName)) throw invalidFieldException(String.join(".",MEMBERS,uid,PERMISSION,NAME),"String"); + if (!(p instanceof JSONObject perm)) throw invalidField(join(".", MEMBERS,uid, PERMISSION),t(JSONOBJECT)); + if (!(perm.get(NAME) instanceof String permName)) throw invalidField(join(".", MEMBERS,uid, PERMISSION, NAME),t(STRING)); var permission = Permission.valueOf(permName); var member = new Member(user,permission); var existing = members.get(userId); @@ -110,7 +114,7 @@ public class WikiPage implements Mappable { } break; case TITLE: - if (!(val instanceof String t)) throw invalidFieldException(TITLE,"String"); + if (!(val instanceof String t)) throw invalidField(TITLE,t(STRING)); title(t); break; } @@ -144,7 +148,7 @@ public class WikiPage implements Mappable { return Map.of( ID,id, - CONTENT,Map.of(SOURCE,content,RENDERED,markdown(content)), + CONTENT,mapMarkdown(content), GUEST_ALLOWED,guestAllowed, MEMBERS,memberMap, TITLE,title, diff --git a/documents/src/main/java/de/srsoftware/umbrella/documents/Constants.java b/documents/src/main/java/de/srsoftware/umbrella/documents/Constants.java index 426196f8..5bfa18b6 100644 --- a/documents/src/main/java/de/srsoftware/umbrella/documents/Constants.java +++ b/documents/src/main/java/de/srsoftware/umbrella/documents/Constants.java @@ -18,7 +18,6 @@ public class Constants { public static final String CONTACTS = "contacts"; public static final String CUSTOMERS = "customers"; - public static final String ERROR_ADDRESS_MISSING = "{0} address does not contain street address / post code / city"; public static final String MOVE = "move"; diff --git a/documents/src/main/java/de/srsoftware/umbrella/documents/DocumentApi.java b/documents/src/main/java/de/srsoftware/umbrella/documents/DocumentApi.java index 93e95553..ed4e3438 100644 --- a/documents/src/main/java/de/srsoftware/umbrella/documents/DocumentApi.java +++ b/documents/src/main/java/de/srsoftware/umbrella/documents/DocumentApi.java @@ -11,19 +11,26 @@ import static de.srsoftware.tools.MimeType.MIME_PDF; import static de.srsoftware.tools.Optionals.isSet; import static de.srsoftware.tools.Strings.escapeHtmlEntities; import static de.srsoftware.umbrella.core.ConnectionProvider.connect; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.Field.*; -import static de.srsoftware.umbrella.core.Field.COMPANY; -import static de.srsoftware.umbrella.core.Field.TAX; -import static de.srsoftware.umbrella.core.Field.TYPE; -import static de.srsoftware.umbrella.core.Field.UNIT; +import static de.srsoftware.umbrella.core.Errors.ADDRESS_MISSING; import static de.srsoftware.umbrella.core.ModuleRegistry.*; -import static de.srsoftware.umbrella.core.Paths.*; import static de.srsoftware.umbrella.core.ResponseCode.HTTP_UNPROCESSABLE; import static de.srsoftware.umbrella.core.Util.mapValues; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Field.COMPANY; +import static de.srsoftware.umbrella.core.constants.Field.CUSTOMER; +import static de.srsoftware.umbrella.core.constants.Field.DOCUMENT; +import static de.srsoftware.umbrella.core.constants.Field.NUMBER; +import static de.srsoftware.umbrella.core.constants.Field.SENDER; +import static de.srsoftware.umbrella.core.constants.Field.STATE; +import static de.srsoftware.umbrella.core.constants.Field.TYPE; +import static de.srsoftware.umbrella.core.constants.Field.UNIT; +import static de.srsoftware.umbrella.core.constants.Field.USER; +import static de.srsoftware.umbrella.core.constants.Path.*; +import static de.srsoftware.umbrella.core.constants.Text.*; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; import static de.srsoftware.umbrella.core.model.Document.State.NEW; import static de.srsoftware.umbrella.core.model.Document.State.SENT; +import static de.srsoftware.umbrella.core.model.Translatable.t; import static de.srsoftware.umbrella.documents.Constants.*; import static java.lang.System.Logger.Level.DEBUG; import static java.lang.System.Logger.Level.WARNING; @@ -45,8 +52,9 @@ import de.srsoftware.document.zugferd.data.Currency; import de.srsoftware.tools.*; import de.srsoftware.umbrella.core.BaseHandler; import de.srsoftware.umbrella.core.ModuleRegistry; -import de.srsoftware.umbrella.core.Paths; import de.srsoftware.umbrella.core.api.*; +import de.srsoftware.umbrella.core.constants.Path; +import de.srsoftware.umbrella.core.constants.Text; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.core.model.*; import de.srsoftware.umbrella.core.model.Customer; @@ -71,12 +79,12 @@ public class DocumentApi extends BaseHandler implements DocumentService { public DocumentApi(Configuration config) throws UmbrellaException { super(); this.config = config; - var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE)); + var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingField(CONFIG_DATABASE)); db = new SqliteDb(connect(dbFile)); ModuleRegistry.add(this); Optional templates = config.get(CONFIG_TEMPLATES); - if (templates.isEmpty()) throw missingFieldException(CONFIG_TEMPLATES); + if (templates.isEmpty()) throw missingField(CONFIG_TEMPLATES); this.registry.add(new DocumentDirectory(new File(templates.get()))); this.registry.add(new TemplateProcessor(), new LatexFactory(), new WeasyFactory(), new ZugferdFactory()); @@ -87,28 +95,28 @@ public class DocumentApi extends BaseHandler implements DocumentService { var currency = switch (document.currency()){ case "€" -> Currency.EUR; case "$" -> Currency.USD; - default -> throw unprocessable("Unsupported currency: ",document.currency()); + default -> throw unprocessable("Unsupported currency: {currency}",CURRENCY,document.currency()); }; var typeCode = switch (document.type().name()){ case "invoice" -> TypeCode.HANDELSRECHNUNG; - default -> throw unprocessable("Unsupported document type: ",document.type().name()); + default -> throw unprocessable("Unsupported document type: {type}",TYPE,document.type().name()); }; var countryID = CountryCode.DE; LOG.log(WARNING,"countryID is hardcoded to be \"DE\", should be field of company!"); var sender = document.sender(); var match = POST_CODE.matcher(sender.name()); - if (!match.find()) throw unprocessable(ERROR_ADDRESS_MISSING, SENDER); + if (!match.find()) throw unprocessable(ADDRESS_MISSING, OBJECT, t(Text.SENDER)); var name = match.group(1).trim(); var streetAddress = match.group(2).trim(); var postCode = match.group(3); var city = match.group(4).trim(); var taxNumber = sender.taxNumber(); - if (!taxNumber.startsWith("DE")) throw unprocessable("Invalid sender tax number ({0})!",taxNumber); + if (!taxNumber.startsWith("DE")) throw unprocessable("Invalid sender tax number ({number})!", NUMBER,taxNumber); var author = new Author(name,countryID,postCode,city,streetAddress,taxNumber); match = POST_CODE.matcher(document.customer().name()); - if (!match.find()) throw unprocessable(ERROR_ADDRESS_MISSING,CUSTOMER); + if (!match.find()) throw unprocessable(ADDRESS_MISSING, OBJECT,t(Text.CUSTOMER)); name = escapeHtmlEntities(match.group(1).trim()); streetAddress = escapeHtmlEntities(match.group(2).trim()); postCode = match.group(3); @@ -124,7 +132,7 @@ public class DocumentApi extends BaseHandler implements DocumentService { try { deliveryDate = LocalDate.parse(document.delivery()); } catch (RuntimeException ex) { - throw unprocessable("\"{0}\" is not a valid delivery date (cannot be parsed)!",document.delivery()); + throw unprocessable("\"{date}\" is not a valid delivery date (cannot be parsed)!", DATE,document.delivery()); } var lineItems = new ArrayList(); for (var entry : document.positions().entrySet()){ @@ -137,7 +145,7 @@ public class DocumentApi extends BaseHandler implements DocumentService { case "jährlich" -> per_year; case "pauschal" -> fixed; case "Stück" -> pieces; - default -> throw unprocessable("No unit code defined for {0}",pos.unit()); + default -> throw unprocessable("No unit code defined for {unit}",UNIT,pos.unit()); }; var percent = pos.tax(); var taxType = percent == 0 ? TaxType.Z : TaxType.S; @@ -157,7 +165,7 @@ public class DocumentApi extends BaseHandler implements DocumentService { private boolean deleteDocument(HttpExchange ex, long docId, UmbrellaUser user) throws IOException, UmbrellaException { var doc = db.loadDoc(docId); var companyId = doc.companyId(); - if (!companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",doc.companyId()); + if (!companyService().membership(companyId,user.id())) throw notAmember(Translatable.t(COMPANY_WITH_ID, ID,doc.companyId())); if (doc.state() != NEW) throw new UmbrellaException(HTTP_BAD_REQUEST,"This document has already been sent"); return sendContent(ex,db.deleteDoc(docId)); } @@ -165,10 +173,10 @@ public class DocumentApi extends BaseHandler implements DocumentService { private boolean deletePosition(HttpExchange ex, long docId, UmbrellaUser user) throws UmbrellaException, IOException { var doc = db.loadDoc(docId); var companyId = doc.companyId(); - if (!companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",doc.companyId()); + if (!companyService().membership(companyId,user.id())) throw notAmember(Translatable.t(COMPANY_WITH_ID, ID,doc.companyId())); if (doc.state() != NEW) throw new UmbrellaException(HTTP_BAD_REQUEST,"This document has already been sent"); var json = json(ex); - if (!(json.has(POSITION) && json.get(POSITION) instanceof Number number)) throw missingFieldException(POSITION); + if (!(json.has(POSITION) && json.get(POSITION) instanceof Number number)) throw missingField(POSITION); db.dropPosition(docId,number.longValue()); return send(ex,db.loadDoc(docId).positions()); } @@ -179,7 +187,7 @@ public class DocumentApi extends BaseHandler implements DocumentService { } @Override - public boolean doDelete(Path path, HttpExchange ex) throws IOException { + public boolean doDelete(de.srsoftware.tools.Path path, HttpExchange ex) throws IOException { addCors(ex); try { Optional token = SessionToken.from(ex).map(Token::of); @@ -200,7 +208,7 @@ public class DocumentApi extends BaseHandler implements DocumentService { } @Override - public boolean doGet(Path path, HttpExchange ex) throws IOException { + public boolean doGet(de.srsoftware.tools.Path path, HttpExchange ex) throws IOException { addCors(ex); try { Optional token = SessionToken.from(ex).map(Token::of); @@ -217,7 +225,7 @@ public class DocumentApi extends BaseHandler implements DocumentService { yield switch (head){ case null -> getDocument(ex,docId,user.get()); case PATH_PDF -> getRenderedDocument(ex,docId,user.get()); - case Paths.SETTINGS -> getDocumentSettings(ex,docId,user.get()); + case Path.SETTINGS -> getDocumentSettings(ex,docId,user.get()); default -> super.doGet(path,ex); }; } @@ -230,7 +238,7 @@ public class DocumentApi extends BaseHandler implements DocumentService { } @Override - public boolean doPatch(Path path, HttpExchange ex) throws IOException { + public boolean doPatch(de.srsoftware.tools.Path path, HttpExchange ex) throws IOException { addCors(ex); try { Optional token = SessionToken.from(ex).map(Token::of); @@ -252,7 +260,7 @@ public class DocumentApi extends BaseHandler implements DocumentService { } @Override - public boolean doPost(Path path, HttpExchange ex) throws IOException { + public boolean doPost(de.srsoftware.tools.Path path, HttpExchange ex) throws IOException { addCors(ex); try { Optional token = SessionToken.from(ex).map(Token::of); @@ -293,7 +301,7 @@ public class DocumentApi extends BaseHandler implements DocumentService { var doc = db.loadDoc(docId); var companyId = doc.companyId(); var company = companyService().get(companyId); - if (!companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name()); + if (!companyService().membership(companyId,user.id())) throw notAmember(Translatable.t(COMPANY_WITH_ID,ID,company.name())); return Tuple.of(doc,company); } @@ -333,10 +341,10 @@ public class DocumentApi extends BaseHandler implements DocumentService { private boolean listCompaniesDocuments(HttpExchange ex, UmbrellaUser user) throws UmbrellaException { try { var json = json(ex); - if (!json.has(COMPANY)) throw missingFieldException(COMPANY); + if (!json.has(COMPANY)) throw missingField(COMPANY); long companyId = json.getLong(COMPANY); var company = companyService().get(companyId); - if (!companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company); + if (!companyService().membership(companyId,user.id())) throw notAmember(Translatable.t(COMPANY_WITH_ID,ID,company.name())); var docs = list(companyId); var map = new HashMap(); for (var entry : docs.entrySet()) map.put(entry.getKey(),entry.getValue().summary()); @@ -371,7 +379,7 @@ public class DocumentApi extends BaseHandler implements DocumentService { var optDoc = registry.documents() .filter(filter) .findAny(); - if (optDoc.isEmpty()) throw UmbrellaException.notFound("Cannot render {0} {1}: Missing template \"{2}\"",type,document.number(),template); + if (optDoc.isEmpty()) throw UmbrellaException.notFound("Cannot render {type} {id}: Missing template \"{template}\"",TYPE,type, ID,document.number(),TEMPLATE,template); Function translate = text -> translator().translate(user.language(),text); var pdfData = new HashMap(); pdfData.put(DOCUMENT,document.renderToMap()); @@ -427,7 +435,7 @@ public class DocumentApi extends BaseHandler implements DocumentService { try { docType = db.getType(Integer.parseInt(body(ex))); } catch (NumberFormatException nfe){ - throw UmbrellaException.invalidFieldException(BODY,"document type id"); + throw invalidField(BODY,DOCUMENT_TYPE_ID); } Document doc = getDocument(docId, user).a; @@ -458,14 +466,14 @@ public class DocumentApi extends BaseHandler implements DocumentService { private boolean postDocument(HttpExchange ex, UmbrellaUser user) throws IOException, UmbrellaException { var json = json(ex); - if (!(json.has(SENDER) && json.get(SENDER) instanceof JSONObject senderData)) throw missingFieldException(SENDER); - if (!senderData.has(COMPANY) || !(senderData.get(COMPANY) instanceof Number rawCompId)) throw missingFieldException(COMPANY); + if (!(json.has(SENDER) && json.get(SENDER) instanceof JSONObject senderData)) throw missingField(SENDER); + if (!senderData.has(COMPANY) || !(senderData.get(COMPANY) instanceof Number rawCompId)) throw missingField(COMPANY); var companyId = rawCompId.longValue(); var company = companyService().get(companyId); - if (!companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company); + if (!companyService().membership(companyId,user.id())) throw notAmember(Translatable.t(COMPANY_WITH_ID,ID,company.name())); - if (!json.has(CUSTOMER) || !(json.get(CUSTOMER) instanceof JSONObject customerData)) throw missingFieldException(CUSTOMER); - if (!json.has(TYPE) || !(json.get(TYPE) instanceof Number docTypeId)) throw missingFieldException(TYPE); + if (!json.has(CUSTOMER) || !(json.get(CUSTOMER) instanceof JSONObject customerData)) throw missingField(CUSTOMER); + if (!json.has(TYPE) || !(json.get(TYPE) instanceof Number docTypeId)) throw missingField(TYPE); var type = db.getType(docTypeId.intValue()); var customer = Customer.of(customerData); String currency = company.currency(); @@ -495,11 +503,11 @@ public class DocumentApi extends BaseHandler implements DocumentService { var doc = getDocument(docId,user).a; var json = json(ex); - if (!(json.has(AMOUNT) && json.get(AMOUNT) instanceof Number amount)) throw missingFieldException(AMOUNT); - if (!(json.has(DESCRIPTION) && json.get(DESCRIPTION) instanceof String description)) throw missingFieldException(DESCRIPTION); - if (!(json.has(ITEM_CODE) && json.get(ITEM_CODE) instanceof String itemCode)) throw missingFieldException(ITEM_CODE); - if (!(json.has(TITLE) && json.get(TITLE) instanceof String title)) throw missingFieldException(TITLE); - if (!(json.has(UNIT) && json.get(UNIT) instanceof String unit)) throw missingFieldException(UNIT); + if (!(json.has(AMOUNT) && json.get(AMOUNT) instanceof Number amount)) throw missingField(AMOUNT); + if (!(json.has(DESCRIPTION) && json.get(DESCRIPTION) instanceof String description)) throw missingField(DESCRIPTION); + if (!(json.has(ITEM_CODE) && json.get(ITEM_CODE) instanceof String itemCode)) throw missingField(ITEM_CODE); + if (!(json.has(TITLE) && json.get(TITLE) instanceof String title)) throw missingField(TITLE); + if (!(json.has(UNIT) && json.get(UNIT) instanceof String unit)) throw missingField(UNIT); var unitPrice = json.has(UNIT_PRICE) && json.get(UNIT_PRICE) instanceof Number num ? num : 0L; try { unitPrice = db.getCustomerPrice(doc.companyId(),doc.customer().id(),itemCode); @@ -514,9 +522,9 @@ public class DocumentApi extends BaseHandler implements DocumentService { private boolean postTemplateList(HttpExchange ex, UmbrellaUser user) throws UmbrellaException, IOException { var json = json(ex); - if (!(json.has(COMPANY) && json.get(COMPANY) instanceof Number companyId)) throw missingFieldException(COMPANY); + if (!(json.has(COMPANY) && json.get(COMPANY) instanceof Number companyId)) throw missingField(COMPANY); var company = companyService().get(companyId.longValue()); - if (!companyService().membership(companyId.longValue(),user.id())) throw forbidden("You are not a member of {0}",company.name()); + if (!companyService().membership(companyId.longValue(),user.id())) throw notAmember(Translatable.t(COMPANY_WITH_ID,ID,company.name())); var templates = registry.documents() .filter(d -> d.name().endsWith(".template")) .map(d -> d.name().replaceAll("(\\.[^.]+)?\\.template$","")); @@ -525,7 +533,7 @@ public class DocumentApi extends BaseHandler implements DocumentService { private boolean postSearch(HttpExchange ex, UmbrellaUser user) throws IOException { var json = json(ex); - if (!(json.has(KEY) && json.get(KEY) instanceof String key)) throw missingFieldException(KEY); + if (!(json.has(KEY) && json.get(KEY) instanceof String key)) throw missingField(KEY); var keys = Arrays.asList(key.split(" ")); var fulltext = json.has(FULLTEXT) && json.get(FULLTEXT) instanceof Boolean val && val; @@ -535,7 +543,7 @@ public class DocumentApi extends BaseHandler implements DocumentService { return sendContent(ex,mapValues(documents)); } - private boolean postToDocument(HttpExchange ex, Path path, UmbrellaUser user, long docId) throws IOException, UmbrellaException { + private boolean postToDocument(HttpExchange ex, de.srsoftware.tools.Path path, UmbrellaUser user, long docId) throws IOException, UmbrellaException { var head = path.pop(); return switch (head){ case CLONE -> postCloneDoc(docId,ex,user); @@ -554,13 +562,13 @@ public class DocumentApi extends BaseHandler implements DocumentService { return val -> message.format(new Object[]{val/100d}); } - private boolean sendDocument(HttpExchange ex, Path path, UmbrellaUser user, long docId) throws IOException, UmbrellaException { + private boolean sendDocument(HttpExchange ex, de.srsoftware.tools.Path path, UmbrellaUser user, long docId) throws IOException, UmbrellaException { var doc = getDocumentWithCompanyData(docId,user); var rendered = renderDocument(doc,user); var json = json(ex); - if (!(json.has(EMAIL) && json.get(EMAIL) instanceof String email)) throw missingFieldException(EMAIL); - if (!(json.has(SUBJECT) && json.get(SUBJECT) instanceof String subject)) throw missingFieldException(SUBJECT); - if (!(json.has(CONTENT) && json.get(CONTENT) instanceof String content)) throw missingFieldException(CONTENT); + if (!(json.has(EMAIL) && json.get(EMAIL) instanceof String email)) throw missingField(EMAIL); + if (!(json.has(SUBJECT) && json.get(SUBJECT) instanceof String subject)) throw missingField(SUBJECT); + if (!(json.has(CONTENT) && json.get(CONTENT) instanceof String content)) throw missingField(CONTENT); var settings = new CustomerSettings(doc.head(),doc.footer(),content); try { db.save(settings,doc); diff --git a/documents/src/main/java/de/srsoftware/umbrella/documents/SqliteDb.java b/documents/src/main/java/de/srsoftware/umbrella/documents/SqliteDb.java index 2f9c36d1..7fcbd97f 100644 --- a/documents/src/main/java/de/srsoftware/umbrella/documents/SqliteDb.java +++ b/documents/src/main/java/de/srsoftware/umbrella/documents/SqliteDb.java @@ -5,25 +5,29 @@ package de.srsoftware.umbrella.documents; import static de.srsoftware.tools.jdbc.Condition.*; import static de.srsoftware.tools.jdbc.Query.*; import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL; -import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.Errors.*; -import static de.srsoftware.umbrella.core.Field.*; -import static de.srsoftware.umbrella.core.Field.COMPANY_ID; -import static de.srsoftware.umbrella.core.Field.TAX; -import static de.srsoftware.umbrella.core.Field.UNIT; import static de.srsoftware.umbrella.core.ModuleRegistry.translator; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseException; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.notFound; +import static de.srsoftware.umbrella.core.constants.Constants.FALLBACK_LANG; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Field.COMPANY; +import static de.srsoftware.umbrella.core.constants.Field.CUSTOMER; +import static de.srsoftware.umbrella.core.constants.Field.NUMBER; +import static de.srsoftware.umbrella.core.constants.Field.SENDER; +import static de.srsoftware.umbrella.core.constants.Field.TYPE; +import static de.srsoftware.umbrella.core.constants.Field.UNIT; +import static de.srsoftware.umbrella.core.constants.Text.*; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; import static de.srsoftware.umbrella.core.model.Document.DEFAULT_THOUSANDS_SEPARATOR; import static de.srsoftware.umbrella.core.model.Document.State; +import static de.srsoftware.umbrella.core.model.Translatable.t; import static de.srsoftware.umbrella.documents.Constants.*; -import static java.lang.System.Logger.Level.*; import static java.text.MessageFormat.format; import static java.time.ZoneOffset.UTC; import de.srsoftware.tools.Pair; import de.srsoftware.tools.jdbc.Query; import de.srsoftware.umbrella.core.BaseDb; +import de.srsoftware.umbrella.core.constants.Text; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.core.model.*; import de.srsoftware.umbrella.documents.model.*; @@ -49,7 +53,7 @@ public class SqliteDb extends BaseDb implements DocumentDb{ var sql = format("ALTER TABLE {0} ADD COLUMN {1} VARCHAR(255)",TABLE_DOCUMENTS,TEMPLATE); db.prepareStatement(sql).execute(); } catch (SQLException e) { - throw databaseException(FAILED_TO_UPDATE_COLUMN,TEMPLATE_ID,TEMPLATE,TABLE_DOCUMENTS).causedBy(e); + throw databaseException(FAILED_TO_UPDATE_COLUMN,"old",TEMPLATE_ID,"new",TEMPLATE, TABLE,TABLE_DOCUMENTS).causedBy(e); } } @@ -79,7 +83,7 @@ public class SqliteDb extends BaseDb implements DocumentDb{ stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_PRICES).causedBy(e); + throw failedToCreateTable(TABLE_PRICES).causedBy(e); } } @@ -90,7 +94,7 @@ public class SqliteDb extends BaseDb implements DocumentDb{ stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_CUSTOMER_SETTINGS).causedBy(e); + throw failedToCreateTable(TABLE_CUSTOMER_SETTINGS).causedBy(e); } } @@ -118,13 +122,13 @@ CREATE TABLE IF NOT EXISTS {0} ( {18} VARCHAR(255), {19} VARCHAR(255) )"""; - createTable = format(createTable,TABLE_DOCUMENTS, ID, TYPE_ID, COMPANY_ID, NUMBER, DATE, STATE, TEMPLATE_ID, DELIVERY_DATE,HEAD,FOOTER,CURRENCY, SENDER,TAX_NUMBER,BANK_ACCOUNT,COURT,CUSTOMER,CUSTOMER_NUMBER,CUSTOMER_TAX_NUMBER,CUSTOMER_EMAIL); + createTable = format(createTable,TABLE_DOCUMENTS, ID, TYPE_ID, COMPANY_ID, NUMBER, DATE, STATE, TEMPLATE_ID, DELIVERY_DATE,HEAD,FOOTER,CURRENCY, SENDER,TAX_NUMBER,BANK_ACCOUNT,COURT, CUSTOMER,CUSTOMER_NUMBER,CUSTOMER_TAX_NUMBER,CUSTOMER_EMAIL); try { var stmt = db.prepareStatement(createTable); stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_DOCUMENTS).causedBy(e); + throw failedToCreateTable(TABLE_DOCUMENTS).causedBy(e); } } @@ -134,14 +138,14 @@ CREATE TABLE IF NOT EXISTS {0} ( var stmt = db.prepareStatement(format(createTable,TABLE_DOCUMENT_TYPES, ID,NEXT_TYPE, NAME)); stmt.execute(); stmt.close(); - insertInto(TABLE_DOCUMENT_TYPES,ID,NEXT_TYPE,NAME) + insertInto(TABLE_DOCUMENT_TYPES, ID,NEXT_TYPE, NAME) .values(1,2,TYPE_OFFER) .values(2,3,TYPE_CONFIRMATION) .values(3,4,TYPE_INVOICE) .values(4,4,TYPE_REMINDER) .execute(db); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_DOCUMENT_TYPES).causedBy(e); + throw failedToCreateTable(TABLE_DOCUMENT_TYPES).causedBy(e); } } @@ -167,7 +171,7 @@ CREATE TABLE IF NOT EXISTS {0} ( stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_POSITIONS).causedBy(e); + throw failedToCreateTable(TABLE_POSITIONS).causedBy(e); } } @@ -178,7 +182,7 @@ CREATE TABLE IF NOT EXISTS {0} ( stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_TEMPLATES).causedBy(e); + throw failedToCreateTable(TABLE_TEMPLATES).causedBy(e); } } @@ -194,9 +198,9 @@ CREATE TABLE IF NOT EXISTS {0} ( delete().from(TABLE_DOCUMENTS).where(ID,equal(docId)).execute(db); db.setAutoCommit(true); if (number != null) return number; - throw databaseException(FAILED_TO_DROP_ENTITY,"document",docId); + throw failedToDropObject(t(DOCUMENT_WITH_ID, ID,docId)); } catch (SQLException e){ - throw databaseException(FAILED_TO_DROP_ENTITY,"document",docId).causedBy(e); + throw failedToDropObject(t(DOCUMENT_WITH_ID, ID,docId)).causedBy(e); } } @@ -214,7 +218,7 @@ CREATE TABLE IF NOT EXISTS {0} ( db.setAutoCommit(true); return pos; } catch (SQLException e) { - throw databaseException(FAILED_TO_DROP_ENTITY_OF_ENTITY,"position",pos,"document",docId).causedBy(e); + throw failedToDropObjectFromObject(POSITION,pos,t(Text.DOCUMENT),docId).causedBy(e); } } @@ -224,7 +228,7 @@ CREATE TABLE IF NOT EXISTS {0} ( var sql = format("ALTER TABLE {0} DROP COLUMN {1}",TABLE_DOCUMENTS,TEMPLATE_ID); db.prepareStatement(sql).execute(); } catch (SQLException e) { - throw databaseException(FAILED_TO_UPDATE_COLUMN,TEMPLATE_ID,TEMPLATE,TABLE_DOCUMENTS).causedBy(e); + throw databaseException(FAILED_TO_UPDATE_COLUMN,"old",TEMPLATE_ID,"new",TEMPLATE, TABLE,TABLE_DOCUMENTS).causedBy(e); } } @@ -233,7 +237,7 @@ CREATE TABLE IF NOT EXISTS {0} ( var sql = format("DROP TABLE IF EXISTS {0};",TABLE_TEMPLATES); db.prepareStatement(sql).execute(); } catch (SQLException e) { - throw databaseException(FAILED_TO_DROP_ENTITY,"table",TABLE_TEMPLATES).causedBy(e); + throw failedToDropObject(t(TABLE_WITH_NAME,NAME,TABLE_TEMPLATES)).causedBy(e); } } @@ -245,9 +249,9 @@ CREATE TABLE IF NOT EXISTS {0} ( if (rs.next()) price = rs.getLong(PRICE); rs.close(); if (price != null) return price; - throw notFound(FAILED_TO_LOAD_CUSTOMER_PRICE,company,customer,itemCode); + throw notFound(FAILED_TO_LOAD_CUSTOMER_PRICE,COMPANY,company, CUSTOMER,customer,t(Text.ITEM),itemCode); } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_CUSTOMER_PRICE,company,customer,itemCode).causedBy(e); + throw databaseException(FAILED_TO_LOAD_CUSTOMER_PRICE,COMPANY,company, CUSTOMER,customer,t(Text.ITEM),itemCode).causedBy(e); } } @@ -260,7 +264,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return settings; } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_CUSTOMER_SETTINGS,companyId, docType.name()).causedBy(e); + throw databaseException(FAILED_TO_LOAD_CUSTOMER_SETTINGS,COMPANY,companyId,TYPE, docType.name()).causedBy(e); } } @@ -272,9 +276,9 @@ CREATE TABLE IF NOT EXISTS {0} ( if (rs.next()) type = toType(rs); rs.close(); if (type != null) return type; - throw notFound(FAILED_TO_LOAD_ENTITY_BY_ID,"type",typeId); + throw notFound(FAILED_TO_LOAD_OBJECT_BY_ID, OBJECT, Text.TYPE, ID,typeId); } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_ENTITY_BY_ID,"type",typeId).causedBy(e); + throw databaseException(FAILED_TO_LOAD_OBJECT_BY_ID, OBJECT, Text.TYPE, ID,typeId).causedBy(e); } } @@ -283,7 +287,7 @@ CREATE TABLE IF NOT EXISTS {0} ( public Map> docReferencedByTimes(Set timeIds) throws UmbrellaException { try { var map = new HashMap>(); // Map ( timeId → Map ( docId → name )) - var rs = select(TIME_ID,DOCUMENT_ID,NUMBER).from(TABLE_POSITIONS).leftJoin(DOCUMENT_ID,TABLE_DOCUMENTS,ID).where(TIME_ID,in(timeIds.toArray())).exec(db); + var rs = select(TIME_ID,DOCUMENT_ID, NUMBER).from(TABLE_POSITIONS).leftJoin(DOCUMENT_ID,TABLE_DOCUMENTS, ID).where(TIME_ID,in(timeIds.toArray())).exec(db); while (rs.next()) { var timeId = rs.getLong(TIME_ID); var docId = rs.getLong(DOCUMENT_ID); @@ -293,7 +297,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return map; } catch (SQLException e) { - throw databaseException(FAILED_TO_LIST_ENTITIES,"documents").causedBy(e); + throw databaseException(FAILED_TO_LIST_ENTITIES,TYPE, t(Text.DOCUMENTS)).causedBy(e); } } @@ -307,9 +311,9 @@ CREATE TABLE IF NOT EXISTS {0} ( var query = Query.select(ALL).from(TABLE_DOCUMENTS).where(COMPANY_ID,in(companyIds.toArray())); if (fulltext) { - for (var key : keys) query.where(format("CONCAT({0},\" \",{1},\" \",{2},\" \",{3},\" \",{4},\" \",{5},\" \",{6},\" \",{7},\" \",{8},\" \",{9})",NUMBER,HEAD,FOOTER,SENDER,TAX_NUMBER,BANK_ACCOUNT,CUSTOMER,CUSTOMER_NUMBER,CUSTOMER_TAX_NUMBER,CUSTOMER_EMAIL),like("%"+key+"%")); + for (var key : keys) query.where(format("CONCAT({0},\" \",{1},\" \",{2},\" \",{3},\" \",{4},\" \",{5},\" \",{6},\" \",{7},\" \",{8},\" \",{9})", NUMBER,HEAD,FOOTER, SENDER,TAX_NUMBER,BANK_ACCOUNT, CUSTOMER,CUSTOMER_NUMBER,CUSTOMER_TAX_NUMBER,CUSTOMER_EMAIL),like("%"+key+"%")); } else { - for (var key : keys) query.where(format("CONCAT({0},\" \",{1},\" \",{2},\" \",{3},\" \",{4})",NUMBER,HEAD,FOOTER,SENDER,CUSTOMER),like("%"+key+"%")); + for (var key : keys) query.where(format("CONCAT({0},\" \",{1},\" \",{2},\" \",{3},\" \",{4})", NUMBER,HEAD,FOOTER, SENDER, CUSTOMER),like("%"+key+"%")); } rs = query.exec(db); var map = new HashMap(); @@ -318,8 +322,8 @@ CREATE TABLE IF NOT EXISTS {0} ( if (fulltext){ var additionalDocIds = new HashSet(); - query = select(DOCUMENT_ID).from(TABLE_POSITIONS).leftJoin(DOCUMENT_ID,TABLE_DOCUMENTS,ID).where(COMPANY_ID,in(companyIds.toArray())); - for (var key : keys) query.where(format("CONCAT({0},\" \",{1},\" \",{2},\" \",{3})",ITEM_CODE,UNIT,TITLE,DESCRIPTION),like("%"+key+"%")); + query = select(DOCUMENT_ID).from(TABLE_POSITIONS).leftJoin(DOCUMENT_ID,TABLE_DOCUMENTS, ID).where(COMPANY_ID,in(companyIds.toArray())); + for (var key : keys) query.where(format("CONCAT({0},\" \",{1},\" \",{2},\" \",{3})",ITEM_CODE,UNIT,TITLE, DESCRIPTION),like("%"+key+"%")); rs = query.exec(db); while (rs.next()) additionalDocIds.add(rs.getLong(DOCUMENT_ID)); rs.close(); @@ -342,7 +346,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return map; } catch (SQLException e) { - throw databaseException(FAILED_TO_SEARCH_DB,"documents").causedBy(e); + throw failedToSearchDb(t(Text.DOCUMENTS)).causedBy(e); } } @@ -369,7 +373,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return map; } catch (SQLException e) { - throw databaseException(FAILED_TO_LIST_ENTITIES,"documents").causedBy(e); + throw databaseException(FAILED_TO_LIST_ENTITIES,TYPE,t(Text.DOCUMENTS)).causedBy(e); } } @@ -382,7 +386,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return types; } catch (SQLException e) { - throw databaseException(FAILED_TO_LIST_ENTITIES,"document types").causedBy(e); + throw databaseException(FAILED_TO_LIST_ENTITIES,TYPE,"document types").causedBy(e); } } @@ -410,9 +414,9 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return doc; } - throw notFound(FAILED_TO_LOAD_ENTITY_BY_ID,"document",docId); + throw notFound(FAILED_TO_LOAD_OBJECT_BY_ID, OBJECT,t(Text.DOCUMENT), ID,docId); } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_ENTITY_BY_ID,"document",docId).causedBy(e); + throw failedToLoadObject(t(Text.DOCUMENT),docId).causedBy(e); } } @@ -422,14 +426,14 @@ CREATE TABLE IF NOT EXISTS {0} ( var sql = format("UPDATE {0} SET template = (SELECT name FROM templates WHERE templates.id = documents.template_id);",TABLE_DOCUMENTS); db.prepareStatement(sql).execute(); } catch (SQLException e) { - throw databaseException(FAILED_TO_MOVE,"template.names","document.templates").causedBy(e); + throw databaseException(FAILED_TO_MOVE,"old","template.names","new","document.templates").causedBy(e); } } @Override public String nextDocId(String language, long companyId, Type type) { try { - var rs = select(NUMBER).from(TABLE_DOCUMENTS).where(COMPANY_ID,equal(companyId)).where(TYPE_ID,equal(type.id())).sort(ID+" DESC").limit(1).exec(db); + var rs = select(NUMBER).from(TABLE_DOCUMENTS).where(COMPANY_ID,equal(companyId)).where(TYPE_ID,equal(type.id())).sort(ID +" DESC").limit(1).exec(db); String lastId = null; if (rs.next()) lastId = rs.getString(1); rs.close(); @@ -463,7 +467,7 @@ CREATE TABLE IF NOT EXISTS {0} ( .execute(db); return settings; } catch (SQLException e){ - throw databaseException(FAILED_TO_UPDATE_ENTITY,"customer settings").causedBy(e); + throw databaseException(FAILED_TO_UPDATE_OBJECT, OBJECT,t(CUSTOMER_SETTINGS)).causedBy(e); } } @@ -473,7 +477,7 @@ CREATE TABLE IF NOT EXISTS {0} ( var timestamp = doc.date().atStartOfDay(UTC).toInstant().getEpochSecond(); var sender = doc.sender(); var custom = doc.customer(); - var stmt = insertInto(TABLE_DOCUMENTS,TYPE_ID,COMPANY_ID, DATE, DELIVERY_DATE,FOOTER,HEAD, NUMBER, STATE, SENDER,TAX_NUMBER,BANK_ACCOUNT,COURT,CUSTOMER,CUSTOMER_EMAIL,CUSTOMER_NUMBER,CUSTOMER_TAX_NUMBER,TEMPLATE,CURRENCY) + var stmt = insertInto(TABLE_DOCUMENTS,TYPE_ID,COMPANY_ID, DATE, DELIVERY_DATE,FOOTER,HEAD, NUMBER, STATE, SENDER,TAX_NUMBER,BANK_ACCOUNT,COURT, CUSTOMER,CUSTOMER_EMAIL,CUSTOMER_NUMBER,CUSTOMER_TAX_NUMBER,TEMPLATE,CURRENCY) .values(doc.type().id(),doc.companyId(),timestamp,doc.delivery(),doc.footer(),doc.head(),doc.number(),doc.state().code(),sender.name(),sender.taxNumber(),sender.bankAccount(),sender.court(),custom.name(),custom.email(),custom.id(),custom.taxNumber(),doc.template(), doc.currency()) .execute(db); var rs = stmt.getGeneratedKeys(); @@ -485,10 +489,10 @@ CREATE TABLE IF NOT EXISTS {0} ( sender.clean(); custom.clean(); doc.clean(); - if (newId == null) throw databaseException(FAILED_TO_STORE_ENTITY,"document"); + if (newId == null) throw failedToStoreObject(doc); return loadDoc(newId); } catch (Exception e) { - throw databaseException(FAILED_TO_UPDATE_ENTITY,"document",doc.number()).causedBy(e); + throw databaseException(FAILED_TO_UPDATE_OBJECT, OBJECT, t(DOCUMENT_WITH_ID,ID,doc.number())).causedBy(e); } if (doc.isDirty()) try { @@ -496,7 +500,7 @@ CREATE TABLE IF NOT EXISTS {0} ( var sender = doc.sender(); var custom = doc.customer(); update(TABLE_DOCUMENTS) - .set(DATE, DELIVERY_DATE,FOOTER,HEAD, NUMBER, STATE, SENDER,TAX_NUMBER,BANK_ACCOUNT,COURT,CUSTOMER,CUSTOMER_EMAIL,CUSTOMER_NUMBER,CUSTOMER_TAX_NUMBER,TEMPLATE) + .set(DATE, DELIVERY_DATE,FOOTER,HEAD, NUMBER, STATE, SENDER,TAX_NUMBER,BANK_ACCOUNT,COURT, CUSTOMER,CUSTOMER_EMAIL,CUSTOMER_NUMBER,CUSTOMER_TAX_NUMBER,TEMPLATE) .where(ID,equal(doc.id())) .prepare(db) .apply(timestamp,doc.delivery(),doc.footer(),doc.head(),doc.number(),doc.state().code(),sender.name(),sender.taxNumber(),sender.bankAccount(),sender.court(),custom.name(),custom.email(),custom.id(),custom.taxNumber(),doc.template()) @@ -505,7 +509,7 @@ CREATE TABLE IF NOT EXISTS {0} ( custom.clean(); doc.clean(); } catch (Exception e) { - throw databaseException(FAILED_TO_UPDATE_ENTITY,"document").causedBy(e); + throw databaseException(FAILED_TO_UPDATE_OBJECT,doc).causedBy(e); } if (doc.positions().isDirty()) try { @@ -532,7 +536,7 @@ CREATE TABLE IF NOT EXISTS {0} ( } } } catch (Exception e) { - throw databaseException(FAILED_TO_STORE_ENTITY,"positions of document").causedBy(e); + throw failedToStoreObject(t("positions of document")).causedBy(e); } return doc; } @@ -547,7 +551,7 @@ CREATE TABLE IF NOT EXISTS {0} ( .close(); return settings; } catch (SQLException e){ - throw databaseException(FAILED_TO_UPDATE_ENTITY,"customer settings").causedBy(e); + throw databaseException(FAILED_TO_UPDATE_OBJECT, OBJECT, t(CUSTOMER_SETTINGS)).causedBy(e); } } @@ -565,7 +569,7 @@ CREATE TABLE IF NOT EXISTS {0} ( .set(PRICE).prepare(db).apply(price).close(); } } catch (SQLException e) { - throw databaseException(FAILED_TO_STORE_ENTITY,"customer_price").causedBy(e); + throw failedToStoreObject(t("customer price")).causedBy(e); } } @@ -578,7 +582,7 @@ CREATE TABLE IF NOT EXISTS {0} ( update(TABLE_POSITIONS).set(POS).where(DOCUMENT_ID,equal(docId)).where(POS,equal(-pair.right())).prepare(db).apply(pair.right()).close(); db.setAutoCommit(true); } catch (SQLException e) { - throw databaseException(FAILED_TO_SWITCH_POSITIONS,pair.left(),pair.right(),docId).causedBy(e); + throw databaseException(FAILED_TO_SWITCH_POSITIONS,"a",pair.left(),"b",pair.right(),docId).causedBy(e); } return pair; } @@ -605,7 +609,7 @@ CREATE TABLE IF NOT EXISTS {0} ( var customerId = rs.getString(CUSTOMER_NUMBER); var customerTaxNumber = rs.getString(CUSTOMER_TAX_NUMBER); var customerEmail = rs.getString(CUSTOMER_EMAIL); - var customer = new Customer(customerId, customerName, customerEmail, customerTaxNumber,FALLBACK_LANG); + var customer = new Customer(customerId, customerName, customerEmail, customerTaxNumber, FALLBACK_LANG); var sender = new Sender(senderName,bankAccount,taxNumber,court); var template = rs.getString(TEMPLATE); return new Document(id,company,number,type,date, Document.State.of(state).orElse(State.ERROR),template,delivery,head,footer,currency, DEFAULT_THOUSANDS_SEPARATOR,sender,customer,new PositionList()); diff --git a/documents/src/main/java/de/srsoftware/umbrella/documents/TemplateDoc.java b/documents/src/main/java/de/srsoftware/umbrella/documents/TemplateDoc.java index 6d43118d..5fd3a269 100644 --- a/documents/src/main/java/de/srsoftware/umbrella/documents/TemplateDoc.java +++ b/documents/src/main/java/de/srsoftware/umbrella/documents/TemplateDoc.java @@ -2,9 +2,9 @@ package de.srsoftware.umbrella.documents; import static de.srsoftware.tools.MimeType.*; -import static de.srsoftware.umbrella.core.Constants.ERROR_MISSING_FIELD; -import static de.srsoftware.umbrella.core.Constants.USER; -import static de.srsoftware.umbrella.core.Field.PRICE_FORMAT; +import static de.srsoftware.umbrella.core.Errors.MISSING_FIELD; +import static de.srsoftware.umbrella.core.constants.Field.PRICE_FORMAT; +import static de.srsoftware.umbrella.core.constants.Field.USER; import static java.lang.System.Logger.Level.TRACE; import static java.nio.charset.StandardCharsets.UTF_8; import static java.text.MessageFormat.format; @@ -55,7 +55,7 @@ public abstract class TemplateDoc implements Document { @Override public RenderResult render(Map data) { data = new HashMap<>(data); - if (!(data.get(PRICE_FORMAT) instanceof PriceFormat price)) return RenderError.of(ERROR_MISSING_FIELD,PRICE_FORMAT); + if (!(data.get(PRICE_FORMAT) instanceof PriceFormat price)) return RenderError.of(MISSING_FIELD,PRICE_FORMAT); if (data.get(USER) instanceof UmbrellaUser user) data.put(USER,user.toMap()); var precursor = source().render(data); if (precursor instanceof Content content){ diff --git a/documents/src/main/java/de/srsoftware/umbrella/documents/model/CustomerSettings.java b/documents/src/main/java/de/srsoftware/umbrella/documents/model/CustomerSettings.java index 23806da2..a296e409 100644 --- a/documents/src/main/java/de/srsoftware/umbrella/documents/model/CustomerSettings.java +++ b/documents/src/main/java/de/srsoftware/umbrella/documents/model/CustomerSettings.java @@ -2,8 +2,7 @@ package de.srsoftware.umbrella.documents.model; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.Field.*; +import static de.srsoftware.umbrella.core.constants.Field.*; import de.srsoftware.tools.Mappable; import java.sql.ResultSet; @@ -56,7 +55,7 @@ public class CustomerSettings implements Mappable { @Override public Map toMap() { - return Map.of(FOOTER,footer,HEAD,header,CONTENT,mailText); + return Map.of(FOOTER,footer,HEAD,header, CONTENT,mailText); } public CustomerSettings patch(JSONObject json) { diff --git a/files/src/main/java/de/srsoftware/umbrella/files/FileModule.java b/files/src/main/java/de/srsoftware/umbrella/files/FileModule.java index 160f99b6..eb854863 100644 --- a/files/src/main/java/de/srsoftware/umbrella/files/FileModule.java +++ b/files/src/main/java/de/srsoftware/umbrella/files/FileModule.java @@ -2,23 +2,25 @@ package de.srsoftware.umbrella.files; import static de.srsoftware.umbrella.core.ConnectionProvider.connect; -import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.ModuleRegistry.*; import static de.srsoftware.umbrella.core.ResponseCode.HTTP_SERVER_ERROR; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Path.PROJECT; +import static de.srsoftware.umbrella.core.constants.Text.LONG; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; -import static de.srsoftware.umbrella.files.Constants.CONFIG_DATABASE; -import static de.srsoftware.umbrella.files.Constants.CONFIG_FILESTORE; +import static de.srsoftware.umbrella.core.model.Translatable.t; +import static de.srsoftware.umbrella.files.Constants.*; import static java.net.HttpURLConnection.HTTP_OK; import static java.nio.charset.StandardCharsets.UTF_8; import static java.text.MessageFormat.format; import com.sun.net.httpserver.HttpExchange; import de.srsoftware.configuration.Configuration; -import de.srsoftware.tools.Path; import de.srsoftware.tools.SessionToken; import de.srsoftware.umbrella.core.BaseHandler; import de.srsoftware.umbrella.core.ModuleRegistry; import de.srsoftware.umbrella.core.api.FileService; +import de.srsoftware.umbrella.core.constants.Path; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.core.model.Company; import de.srsoftware.umbrella.core.model.Project; @@ -39,21 +41,21 @@ public class FileModule extends BaseHandler implements FileService { public FileModule(Configuration config) throws UmbrellaException { super(); - var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE)); - var filestore = config.get(CONFIG_FILESTORE).orElseThrow(() -> missingFieldException(CONFIG_FILESTORE)); + var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingField(CONFIG_DATABASE)); + var filestore = config.get(CONFIG_FILESTORE).orElseThrow(() -> missingField(CONFIG_FILESTORE)); baseDir = new File(filestore.toString()); if (!baseDir.exists()) try { Files.createDirectories(baseDir.toPath()); } catch (IOException e) { - throw unprocessable("Failed to create {0}",baseDir); + throw unprocessable("Failed to create {location}", LOCATION,baseDir); } - if (!baseDir.isDirectory()) throw unprocessable("{0} is not a directory!"); + if (!baseDir.isDirectory()) throw unprocessable("{location} is not a directory!", LOCATION,baseDir); fileDb = new SqliteDb(connect(dbFile)); ModuleRegistry.add(this); } @Override - public boolean doDelete(Path path, HttpExchange ex) throws IOException { + public boolean doDelete(de.srsoftware.tools.Path path, HttpExchange ex) throws IOException { addCors(ex); try { Optional token = SessionToken.from(ex).map(Token::of); @@ -61,17 +63,17 @@ public class FileModule extends BaseHandler implements FileService { if (user.isEmpty()) return unauthorized(ex); var head = path.pop(); return switch (head){ - case COMPANY -> deleteCompanyFile(path, ex, user.get()); + case Path.COMPANY -> deleteCompanyFile(path, ex, user.get()); case PROJECT -> deleteProjectFile(path, ex, user.get()); - case USER -> deleteUserFile(path, ex, user.get()); - case null, default -> throw UmbrellaException.notFound("invalid location: {0}", head); + case Path.USER -> deleteUserFile(path, ex, user.get()); + case null, default -> throw UmbrellaException.notFound("invalid location: {location}", LOCATION, head); }; } catch (UmbrellaException e) { return send(ex,e); } } - private boolean deleteCompanyFile(Path path, HttpExchange ex, UmbrellaUser user) throws IOException { + private boolean deleteCompanyFile(de.srsoftware.tools.Path path, HttpExchange ex, UmbrellaUser user) throws IOException { var cpId = path.pop(); var companies = companyService(); Map companyList; @@ -85,17 +87,17 @@ public class FileModule extends BaseHandler implements FileService { try { cid = Long.parseLong(cpId); } catch (NumberFormatException e) { - throw invalidFieldException(COMPANY_ID,"Long"); + throw invalidField(COMPANY_ID,LONG); } var company = companies.get(cid); var filename = "/company/"+cid; if (!path.empty()) filename += "/"+URLDecoder.decode(path.toString(),UTF_8); - if (!companies.membership(cid,user.id()) && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {0}",filename); + if (!companies.membership(cid,user.id()) && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {file}",FILE,filename); return deleteFile(ex, new File(baseDir+filename)); } - private boolean deleteProjectFile(Path path, HttpExchange ex, UmbrellaUser user) throws IOException { + private boolean deleteProjectFile(de.srsoftware.tools.Path path, HttpExchange ex, UmbrellaUser user) throws IOException { var prjId = path.pop(); var projects = projectService(); if (prjId == null){ @@ -108,12 +110,12 @@ public class FileModule extends BaseHandler implements FileService { try { pid = Long.parseLong(prjId); } catch (NumberFormatException e) { - throw invalidFieldException(PROJECT_ID,"Long"); + throw invalidField(PROJECT_ID,t(LONG)); } var project = projects.loadMembers(projects.load(pid)); var filename = "/project/"+pid; if (!path.empty()) filename += "/"+URLDecoder.decode(path.toString(),UTF_8); - if (!project.hasMember(user) && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {0}",filename); + if (!project.hasMember(user) && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {file}",FILE,filename); return deleteFile(ex, new File(baseDir+filename)); } @@ -128,7 +130,7 @@ public class FileModule extends BaseHandler implements FileService { } private boolean deleteFile(HttpExchange ex, File file) throws IOException { - if (!file.exists()) throw unprocessable("{0} does not exist!",file.getName()); + if (!file.exists()) throw unprocessable("{file} does not exist!",FILE,file.getName()); if (!dropDir(file)) return sendContent(ex,HTTP_SERVER_ERROR,format("Failed to delete {0}",file.getName())); Map map = getDirectory(file.getParentFile()); map.put("title",file.getName()); @@ -137,23 +139,23 @@ public class FileModule extends BaseHandler implements FileService { } - private boolean deleteUserFile(Path path, HttpExchange ex, UmbrellaUser user) throws IOException { + private boolean deleteUserFile(de.srsoftware.tools.Path path, HttpExchange ex, UmbrellaUser user) throws IOException { var userId = path.pop(); - if (userId == null) throw missingFieldException(USER_ID); + if (userId == null) throw missingField(USER_ID); long uid; try { uid = Long.parseLong(userId); } catch (NumberFormatException e) { - throw invalidFieldException(PROJECT_ID,"Long"); + throw invalidField(PROJECT_ID,t(LONG)); } var filename = "/user/"+uid; if (!path.empty()) filename += "/"+URLDecoder.decode(path.toString(),UTF_8); - if (uid != user.id() && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {0}",filename); + if (uid != user.id() && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {file}",FILE,filename); return deleteFile(ex, new File(baseDir+filename)); } @Override - public boolean doGet(Path path, HttpExchange ex) throws IOException { + public boolean doGet(de.srsoftware.tools.Path path, HttpExchange ex) throws IOException { addCors(ex); try { Optional token = SessionToken.from(ex).map(Token::of); @@ -161,10 +163,10 @@ public class FileModule extends BaseHandler implements FileService { if (user.isEmpty()) return unauthorized(ex); var head = path.pop(); return switch (head){ - case COMPANY -> getCompanyFiles(path, ex, user.get()); + case Path.COMPANY -> getCompanyFiles(path, ex, user.get()); case PROJECT -> getProjectFiles(path, ex, user.get()); - case USER -> getUserFiles(path, ex, user.get()); - case null, default -> throw UmbrellaException.notFound("invalid location: {0}", head); + case Path.USER -> getUserFiles(path, ex, user.get()); + case null, default -> throw UmbrellaException.notFound("invalid location: {location}", LOCATION, head); }; } catch (UmbrellaException e) { return send(ex,e); @@ -172,7 +174,7 @@ public class FileModule extends BaseHandler implements FileService { } @Override - public boolean doPost(Path path, HttpExchange ex) throws IOException { + public boolean doPost(de.srsoftware.tools.Path path, HttpExchange ex) throws IOException { addCors(ex); try { Optional token = SessionToken.from(ex).map(Token::of); @@ -180,10 +182,10 @@ public class FileModule extends BaseHandler implements FileService { if (user.isEmpty()) return unauthorized(ex); var head = path.pop(); return switch (head){ - case COMPANY -> postCompanyDirectory(path, ex, user.get()); + case Path.COMPANY -> postCompanyDirectory(path, ex, user.get()); case PROJECT -> postProjectDirectory(path, ex, user.get()); - case USER -> postUserDirectory(path, ex, user.get()); - case null, default -> throw UmbrellaException.notFound("invalid location: {0}", head); + case Path.USER -> postUserDirectory(path, ex, user.get()); + case null, default -> throw UmbrellaException.notFound("invalid location: {location}", LOCATION, head); }; } catch (UmbrellaException e) { return send(ex,e); @@ -199,11 +201,11 @@ public class FileModule extends BaseHandler implements FileService { body.close(); out.close(); } else { - if (file.exists()) throw unprocessable("{0} already exists!", filename); + if (file.exists()) throw unprocessable("{file} already exists!",FILE, filename); try { file.mkdirs(); } catch (Exception e) { - throw unprocessable("Failed to create {0}", filename); + throw unprocessable("Failed to create {file}", FILE, filename); } } Map map = getDirectory(file.getParentFile()); @@ -211,7 +213,7 @@ public class FileModule extends BaseHandler implements FileService { return sendContent(ex,map); } - private boolean getCompanyFiles(Path path, HttpExchange ex, UmbrellaUser user) throws IOException { + private boolean getCompanyFiles(de.srsoftware.tools.Path path, HttpExchange ex, UmbrellaUser user) throws IOException { var cpId = path.pop(); var companies = companyService(); Map companyList; @@ -225,17 +227,17 @@ public class FileModule extends BaseHandler implements FileService { try { cid = Long.parseLong(cpId); } catch (NumberFormatException e) { - throw invalidFieldException(COMPANY_ID,"Long"); + throw invalidField(COMPANY_ID,LONG); } var company = companies.get(cid); var companyDir = "/company/"+cid; var filename = path.empty() ? companyDir : companyDir + "/"+URLDecoder.decode(path.toString(),UTF_8); - if (!companies.membership(cid,user.id()) && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {0}",filename); + if (!companies.membership(cid,user.id()) && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {file}", FILE, filename); var file = new File(baseDir+filename); if (!file.exists()){ - if (!filename.equals(companyDir)) throw unprocessable("{0} does not exist!",filename); - if (!file.mkdirs()) throw unprocessable("Failed to create directory {0}!",filename); + if (!filename.equals(companyDir)) throw unprocessable("{file} does not exist!", FILE, filename); + if (!file.mkdirs()) throw unprocessable("Failed to create directory {name}!", NAME,filename); } if (file.isDirectory()){ Map map = getDirectory(file); @@ -273,7 +275,7 @@ public class FileModule extends BaseHandler implements FileService { } - private boolean getProjectFiles(Path path, HttpExchange ex, UmbrellaUser user) throws IOException { + private boolean getProjectFiles(de.srsoftware.tools.Path path, HttpExchange ex, UmbrellaUser user) throws IOException { var prjId = path.pop(); var projects = projectService(); if (prjId == null){ @@ -286,16 +288,16 @@ public class FileModule extends BaseHandler implements FileService { try { pid = Long.parseLong(prjId); } catch (NumberFormatException e) { - throw invalidFieldException(PROJECT_ID,"Long"); + throw invalidField(PROJECT_ID,t(LONG)); } var project = projects.loadMembers(projects.load(pid)); var projectDir = "/project/"+pid; var filename = path.empty() ? projectDir : projectDir+"/"+URLDecoder.decode(path.toString(),UTF_8); - if (!project.hasMember(user) && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {0}",filename); + if (!project.hasMember(user) && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {file}", FILE,filename); var file = new File(baseDir+filename); if (!file.exists()){ - if (!filename.equals(projectDir)) throw unprocessable("{0} does not exist!",filename); - if (!file.mkdirs()) throw unprocessable("Failed to create directory {0}!",filename); + if (!filename.equals(projectDir)) throw unprocessable("{file} does not exist!",FILE,filename); + if (!file.mkdirs()) throw unprocessable("Failed to create directory {name}!", NAME,filename); } if (file.isDirectory()){ Map map = getDirectory(file); @@ -306,23 +308,23 @@ public class FileModule extends BaseHandler implements FileService { return getFile(ex, file); } - private boolean getUserFiles(Path path, HttpExchange ex, UmbrellaUser user) throws IOException { + private boolean getUserFiles(de.srsoftware.tools.Path path, HttpExchange ex, UmbrellaUser user) throws IOException { var userId = path.pop(); - if (userId == null) throw missingFieldException(USER_ID); + if (userId == null) throw missingField(USER_ID); long uid; try { uid = Long.parseLong(userId); } catch (NumberFormatException e) { - throw invalidFieldException(PROJECT_ID,"Long"); + throw invalidField(PROJECT_ID,t(LONG)); } var userDir = "/user/"+uid; var filename = path.empty() ? userDir : userDir+"/"+URLDecoder.decode(path.toString(),UTF_8); if (!path.empty()) filename += "/"+URLDecoder.decode(path.toString(),UTF_8); - if (uid != user.id() && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {0}",filename); + if (uid != user.id() && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {file}",FILE,filename); var file = new File(baseDir+filename); if (!file.exists()){ - if (!filename.equals(userDir)) throw unprocessable("{0} does not exist!",filename); - if (!file.mkdirs()) throw unprocessable("Failed to create directory {0}!",filename); + if (!filename.equals(userDir)) throw unprocessable("{file} does not exist!",FILE,filename); + if (!file.mkdirs()) throw unprocessable("Failed to create directory {name}!", NAME,filename); } if (file.isDirectory()){ Map map = getDirectory(file); map.put("title",filename); @@ -332,7 +334,7 @@ public class FileModule extends BaseHandler implements FileService { return getFile(ex, file); } - private boolean postCompanyDirectory(Path path, HttpExchange ex, UmbrellaUser user) throws IOException { + private boolean postCompanyDirectory(de.srsoftware.tools.Path path, HttpExchange ex, UmbrellaUser user) throws IOException { var cpId = path.pop(); var companies = companyService(); Map companyList; @@ -346,16 +348,16 @@ public class FileModule extends BaseHandler implements FileService { try { cid = Long.parseLong(cpId); } catch (NumberFormatException e) { - throw invalidFieldException(COMPANY_ID,"Long"); + throw invalidField(COMPANY_ID,LONG); } var filename = "/company/"+cid; if (!path.empty()) filename += "/"+URLDecoder.decode(path.toString(),UTF_8); - if (!companies.membership(cid,user.id()) && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {0}",filename); + if (!companies.membership(cid,user.id()) && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {file}",FILE,filename); return doPost(ex,filename); } - private boolean postProjectDirectory(Path path, HttpExchange ex, UmbrellaUser user) throws IOException { + private boolean postProjectDirectory(de.srsoftware.tools.Path path, HttpExchange ex, UmbrellaUser user) throws IOException { var prjId = path.pop(); var projects = projectService(); if (prjId == null){ @@ -368,27 +370,27 @@ public class FileModule extends BaseHandler implements FileService { try { pid = Long.parseLong(prjId); } catch (NumberFormatException e) { - throw invalidFieldException(PROJECT_ID,"Long"); + throw invalidField(PROJECT_ID,t(LONG)); } var project = projects.loadMembers(projects.load(pid)); var filename = "/project/"+pid; if (!path.empty()) filename += "/"+URLDecoder.decode(path.toString(),UTF_8); - if (!project.hasMember(user) && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {0}",filename); + if (!project.hasMember(user) && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {file}",FILE,filename); return doPost(ex,filename); } - private boolean postUserDirectory(Path path, HttpExchange ex, UmbrellaUser user) throws IOException { + private boolean postUserDirectory(de.srsoftware.tools.Path path, HttpExchange ex, UmbrellaUser user) throws IOException { var userId = path.pop(); - if (userId == null) throw missingFieldException(USER_ID); + if (userId == null) throw missingField(USER_ID); long uid; try { uid = Long.parseLong(userId); } catch (NumberFormatException e) { - throw invalidFieldException(PROJECT_ID,"Long"); + throw invalidField(PROJECT_ID,t(LONG)); } var filename = "/user/"+uid; if (!path.empty()) filename += "/"+URLDecoder.decode(path.toString(),UTF_8); - if (uid != user.id() && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {0}",filename); + if (uid != user.id() && !fileDb.isPermitted(user,filename)) throw forbidden("You are not allowed to access {file}",FILE,filename); return doPost(ex,filename); } } diff --git a/files/src/main/java/de/srsoftware/umbrella/files/SqliteDb.java b/files/src/main/java/de/srsoftware/umbrella/files/SqliteDb.java index 6f1fa138..b8ce90ca 100644 --- a/files/src/main/java/de/srsoftware/umbrella/files/SqliteDb.java +++ b/files/src/main/java/de/srsoftware/umbrella/files/SqliteDb.java @@ -4,10 +4,10 @@ package de.srsoftware.umbrella.files; import static de.srsoftware.tools.jdbc.Condition.equal; import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL; import static de.srsoftware.tools.jdbc.Query.select; -import static de.srsoftware.umbrella.core.Constants.USER_ID; import static de.srsoftware.umbrella.core.Errors.FAILED_TO_CHECK_FILE_PERMISSIONS; -import static de.srsoftware.umbrella.core.Errors.FAILED_TO_CREATE_TABLE; +import static de.srsoftware.umbrella.core.constants.Field.USER_ID; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseException; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.failedToCreateTable; import static de.srsoftware.umbrella.files.Constants.FILE; import static de.srsoftware.umbrella.files.Constants.TABLE_FILE_SHARES; import static java.text.MessageFormat.format; @@ -37,9 +37,9 @@ public class SqliteDb extends BaseDb implements FileDb { private void createShareTable() { var sql = "CREATE TABLE IF NOT EXISTS {0} ({1} VARCHAR(2048) NOT NULL, {2} INT NOT NULL, PRIMARY KEY({1}, {2}))"; try { - db.prepareStatement(format(sql, TABLE_FILE_SHARES,FILE,USER_ID)).execute(); + db.prepareStatement(format(sql, TABLE_FILE_SHARES,FILE, USER_ID)).execute(); } catch (SQLException e){ - throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_FILE_SHARES).causedBy(e); + throw failedToCreateTable(TABLE_FILE_SHARES).causedBy(e); } } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index f837b81f..84bb4c3a 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -27,6 +27,278 @@ "node": ">=6.0.0" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", + "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz", + "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz", + "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz", + "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz", + "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz", + "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz", + "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz", + "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz", + "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz", + "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz", + "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz", + "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz", + "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz", + "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz", + "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz", + "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/linux-x64": { "version": "0.25.5", "cpu": [ @@ -42,6 +314,142 @@ "node": ">=18" } }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz", + "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz", + "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz", + "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz", + "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz", + "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz", + "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz", + "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz", + "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.8", "license": "MIT", @@ -80,6 +488,216 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.1.tgz", + "integrity": "sha512-JAcBr1+fgqx20m7Fwe1DxPUl/hPkee6jA6Pl7n1v2EFiktAHenTaXl5aIFjUIEsfn9w3HE4gK1lEgNGMzBDs1w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.1.tgz", + "integrity": "sha512-RurZetXqTu4p+G0ChbnkwBuAtwAbIwJkycw1n6GvlGlBuS4u5qlr5opix8cBAYFJgaY05TWtM+LaoFggUmbZEQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.1.tgz", + "integrity": "sha512-fM/xPesi7g2M7chk37LOnmnSTHLG/v2ggWqKj3CCA1rMA4mm5KVBT1fNoswbo1JhPuNNZrVwpTvlCVggv8A2zg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.1.tgz", + "integrity": "sha512-gDnWk57urJrkrHQ2WVx9TSVTH7lSlU7E3AFqiko+bgjlh78aJ88/3nycMax52VIVjIm3ObXnDL2H00e/xzoipw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.1.tgz", + "integrity": "sha512-wnFQmJ/zPThM5zEGcnDcCJeYJgtSLjh1d//WuHzhf6zT3Md1BvvhJnWoy+HECKu2bMxaIcfWiu3bJgx6z4g2XA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.1.tgz", + "integrity": "sha512-uBmIxoJ4493YATvU2c0upGz87f99e3wop7TJgOA/bXMFd2SvKCI7xkxY/5k50bv7J6dw1SXT4MQBQSLn8Bb/Uw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.1.tgz", + "integrity": "sha512-n0edDmSHlXFhrlmTK7XBuwKlG5MbS7yleS1cQ9nn4kIeW+dJH+ExqNgQ0RrFRew8Y+0V/x6C5IjsHrJmiHtkxQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.1.tgz", + "integrity": "sha512-8WVUPy3FtAsKSpyk21kV52HCxB+me6YkbkFHATzC2Yd3yuqHwy2lbFL4alJOLXKljoRw08Zk8/xEj89cLQ/4Nw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.1.tgz", + "integrity": "sha512-yuktAOaeOgorWDeFJggjuCkMGeITfqvPgkIXhDqsfKX8J3jGyxdDZgBV/2kj/2DyPaLiX6bPdjJDTu9RB8lUPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.1.tgz", + "integrity": "sha512-W+GBM4ifET1Plw8pdVaecwUgxmiH23CfAUj32u8knq0JPFyK4weRy6H7ooxYFD19YxBulL0Ktsflg5XS7+7u9g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.1.tgz", + "integrity": "sha512-1zqnUEMWp9WrGVuVak6jWTl4fEtrVKfZY7CvcBmUUpxAJ7WcSowPSAWIKa/0o5mBL/Ij50SIf9tuirGx63Ovew==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.1.tgz", + "integrity": "sha512-Rl3JKaRu0LHIx7ExBAAnf0JcOQetQffaw34T8vLlg9b1IhzcBgaIdnvEbbsZq9uZp3uAH+JkHd20Nwn0h9zPjA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.1.tgz", + "integrity": "sha512-j5akelU3snyL6K3N/iX7otLBIl347fGwmd95U5gS/7z6T4ftK288jKq3A5lcFKcx7wwzb5rgNvAg3ZbV4BqUSw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.1.tgz", + "integrity": "sha512-ppn5llVGgrZw7yxbIm8TTvtj1EoPgYUAbfw0uDjIOzzoqlZlZrLJ/KuiE7uf5EpTpCTrNt1EdtzF0naMm0wGYg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.1.tgz", + "integrity": "sha512-Hu6hEdix0oxtUma99jSP7xbvjkUM/ycke/AQQ4EC5g7jNRLLIwjcNwaUy95ZKBJJwg1ZowsclNnjYqzN4zwkAw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.44.1", "cpu": [ @@ -104,6 +722,48 @@ "linux" ] }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.1.tgz", + "integrity": "sha512-NtSJVKcXwcqozOl+FwI41OH3OApDyLk3kqTJgx8+gp6On9ZEt5mYhIsKNPGuaZr3p9T6NWPKGU/03Vw4CNU9qg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.1.tgz", + "integrity": "sha512-JYA3qvCOLXSsnTR3oiyGws1Dm0YTuxAAeaYGVlGpUsHqloPcFjPg+X0Fj2qODGLNwQOAcCiQmHub/V007kiH5A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.44.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.1.tgz", + "integrity": "sha512-J8o22LuF0kTe7m+8PvW9wk3/bRq5+mRo5Dqo6+vXb7otCm3TPhYOJqOaQtGU9YMWQSL3krMnoOxMr0+9E6F3Ug==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@sveltejs/acorn-typescript": { "version": "1.0.5", "license": "MIT", @@ -269,6 +929,21 @@ } } }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/is-reference": { "version": "3.0.3", "license": "MIT", diff --git a/frontend/src/Components/EstimatedTask.svelte b/frontend/src/Components/EstimatedTask.svelte index 7853960f..ad2a1673 100644 --- a/frontend/src/Components/EstimatedTask.svelte +++ b/frontend/src/Components/EstimatedTask.svelte @@ -9,9 +9,9 @@
- {#if task.estimated_time} + {#if task.est_time} onSelect(task)}> - {task.estimated_time} {t(task.estimated_time != 1 ? 'hours' : 'hour')} + {task.est_time} {t(task.est_time != 1 ? 'hours' : 'hour')} {/if} {task.name} diff --git a/frontend/src/routes/document/PositionSelector.svelte b/frontend/src/routes/document/PositionSelector.svelte index 256dd345..e8a479a7 100644 --- a/frontend/src/routes/document/PositionSelector.svelte +++ b/frontend/src/routes/document/PositionSelector.svelte @@ -23,7 +23,7 @@ item_code : t('estimated_time'), title : estimate.name, description : estimate.description.source, - amount : estimate.estimated_time, + amount : estimate.est_time, unit : t('hours') }); } diff --git a/frontend/src/routes/project/KanbanCard.svelte b/frontend/src/routes/project/KanbanCard.svelte index 5ffbac37..3301a626 100644 --- a/frontend/src/routes/project/KanbanCard.svelte +++ b/frontend/src/routes/project/KanbanCard.svelte @@ -21,9 +21,9 @@ title={task.description.source} > {task.name} - {#if task.estimated_time} + {#if task.est_time} - ({task.estimated_time} h) + ({task.est_time} h) {/if} {#if task.tags} diff --git a/frontend/src/routes/project/View.svelte b/frontend/src/routes/project/View.svelte index 32112a23..c65ce803 100644 --- a/frontend/src/routes/project/View.svelte +++ b/frontend/src/routes/project/View.svelte @@ -17,7 +17,7 @@ let eventSource = $state(null); let { id } = $props(); let lastEvent = $state(null); - let estimated_time = $state({sum:0}); + let est_time = $state({sum:0}); let project = $state(null); let router = useTinyRouter(); let showSettings = $state(false); @@ -135,7 +135,7 @@ }); if (resp.ok){ tasks = {}; - estimated_time.sum = 0; + est_time.sum = 0; tasks = await resp.json(); yikes(); } else { @@ -283,9 +283,9 @@ {/each} {/if} - {#if estimated_time.sum} + {#if est_time.sum}
{t('estimated_time')}
-
{estimated_time.sum} h
+
{est_time.sum} h
{/if}
{t('description')}
@@ -304,7 +304,7 @@
{#if tasks} - + {/if}
diff --git a/frontend/src/routes/task/Add.svelte b/frontend/src/routes/task/Add.svelte index 3afd1f7f..f493ac37 100644 --- a/frontend/src/routes/task/Add.svelte +++ b/frontend/src/routes/task/Add.svelte @@ -19,7 +19,7 @@ name : '', description : { source : '', rendered : '' }, due_date : null, - estimated_time : null, + est_time : null, no_index : false, show_closed : false, start_date : null, @@ -191,7 +191,7 @@ {t('estimated_time')} - {t('hours')} + {t('hours')} diff --git a/frontend/src/routes/task/ListTask.svelte b/frontend/src/routes/task/ListTask.svelte index d55c0bc9..5173f323 100644 --- a/frontend/src/routes/task/ListTask.svelte +++ b/frontend/src/routes/task/ListTask.svelte @@ -13,7 +13,7 @@ import LineEditor from '../../Components/LineEditor.svelte'; let { - estimated_time, + est_time, lastEvent, show_closed, siblings, @@ -137,8 +137,8 @@ return {state:0}; } - if (task.estimated_time){ - estimated_time.sum += task.estimated_time; + if (task.est_time){ + est_time.sum += task.est_time; } $effect(() => { @@ -157,8 +157,8 @@ {#if !deleted}
  • e.preventDefault()} {ondragstart} class="task {states[task.status]?.toLowerCase()}"> - {#if task.estimated_time} - ({+task.estimated_time} h) + {#if task.est_time} + ({+task.est_time} h) {/if} {#if states[task.status] != 'PENDING'} @@ -180,7 +180,7 @@ {#if children} - + {/if}
  • {/if} diff --git a/frontend/src/routes/task/TaskList.svelte b/frontend/src/routes/task/TaskList.svelte index bb688418..d13d2afc 100644 --- a/frontend/src/routes/task/TaskList.svelte +++ b/frontend/src/routes/task/TaskList.svelte @@ -2,13 +2,13 @@ import { t } from '../../translations.svelte.js'; import ListTask from './ListTask.svelte'; - let { estimated_time, lastEvent, show_closed, states = {}, tasks } = $props(); + let { est_time, lastEvent, show_closed, states = {}, tasks } = $props(); let sortedTasks = $derived.by(() => Object.values(tasks).sort((a, b) => a.name.localeCompare(b.name)));
      {#each sortedTasks as task} - + {/each}
    diff --git a/frontend/src/routes/task/View.svelte b/frontend/src/routes/task/View.svelte index 4a1feb3f..dce5c0f6 100644 --- a/frontend/src/routes/task/View.svelte +++ b/frontend/src/routes/task/View.svelte @@ -21,7 +21,7 @@ let { id } = $props(); let children = $state(null); let dummy = $derived(updateOn(id)); - let estimated_time = $state({sum:0}); + let est_time = $state({sum:0}); let project = $state(null); const router = useTinyRouter(); let showSettings = $state(router.fullPath.endsWith('/edit')); @@ -251,9 +251,9 @@
    {t('due_date')}
    {task.due_date}
    {/if} - {#if task.estimated_time} + {#if task.est_time}
    {t('estimated_time')}
    -
    {task.estimated_time} h
    +
    {task.est_time} h
    {/if} {#if showSettings}
    {t('extended_settings')}
    @@ -284,7 +284,7 @@
    {t('estimated_time')}
    - update({estimated_time:task.estimated_time})} /> h + update({est_time:task.est_time})} /> h
    {t('priority')}
    @@ -320,7 +320,7 @@
    {#if children} - + {/if}
    diff --git a/legacy/src/main/java/de/srsoftware/umbrella/legacy/CompanyLegacy.java b/legacy/src/main/java/de/srsoftware/umbrella/legacy/CompanyLegacy.java index 8217099f..78826217 100644 --- a/legacy/src/main/java/de/srsoftware/umbrella/legacy/CompanyLegacy.java +++ b/legacy/src/main/java/de/srsoftware/umbrella/legacy/CompanyLegacy.java @@ -3,11 +3,11 @@ package de.srsoftware.umbrella.legacy; import static de.srsoftware.tools.Optionals.nullable; -import static de.srsoftware.umbrella.core.Constants.TOKEN; import static de.srsoftware.umbrella.core.ModuleRegistry.companyService; import static de.srsoftware.umbrella.core.ModuleRegistry.userService; -import static de.srsoftware.umbrella.core.Paths.JSON; import static de.srsoftware.umbrella.core.Util.mapValues; +import static de.srsoftware.umbrella.core.constants.Field.TOKEN; +import static de.srsoftware.umbrella.core.constants.Path.JSON; import com.sun.net.httpserver.HttpExchange; import de.srsoftware.configuration.Configuration; diff --git a/legacy/src/main/java/de/srsoftware/umbrella/legacy/NotesLegacy.java b/legacy/src/main/java/de/srsoftware/umbrella/legacy/NotesLegacy.java index 497650d4..b9ec4cf3 100644 --- a/legacy/src/main/java/de/srsoftware/umbrella/legacy/NotesLegacy.java +++ b/legacy/src/main/java/de/srsoftware/umbrella/legacy/NotesLegacy.java @@ -3,12 +3,12 @@ package de.srsoftware.umbrella.legacy; import static de.srsoftware.tools.Optionals.nullable; -import static de.srsoftware.umbrella.core.Constants.TOKEN; -import static de.srsoftware.umbrella.core.Constants.URI; import static de.srsoftware.umbrella.core.ModuleRegistry.noteService; import static de.srsoftware.umbrella.core.ModuleRegistry.userService; import static de.srsoftware.umbrella.core.Util.markdown; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.invalidFieldException; +import static de.srsoftware.umbrella.core.constants.Field.TOKEN; +import static de.srsoftware.umbrella.core.constants.Field.URI; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.invalidField; import com.sun.net.httpserver.HttpExchange; import de.srsoftware.configuration.Configuration; @@ -53,9 +53,9 @@ public class NotesLegacy extends BaseHandler { } private boolean postNotesHtml(HttpExchange ex, Map params) throws IOException { - if (!(params.get(URI) instanceof String uri)) throw invalidFieldException(URI,"URI of the form \"module:entry-id\""); + if (!(params.get(URI) instanceof String uri)) throw invalidField(URI,"URI of the form \"module:entry-id\""); var parts = uri.split(":",2); - if (parts.length<2) throw invalidFieldException(URI,"URI of the form \"module:entry-id\""); + if (parts.length<2) throw invalidField(URI,"URI of the form \"module:entry-id\""); var module = parts[0]; var entryId = parts[1]; var notes = noteService().getNotes(module,entryId); diff --git a/legacy/src/main/java/de/srsoftware/umbrella/legacy/ProjectLegacy.java b/legacy/src/main/java/de/srsoftware/umbrella/legacy/ProjectLegacy.java index aec94ba9..1c2242c2 100644 --- a/legacy/src/main/java/de/srsoftware/umbrella/legacy/ProjectLegacy.java +++ b/legacy/src/main/java/de/srsoftware/umbrella/legacy/ProjectLegacy.java @@ -3,11 +3,12 @@ package de.srsoftware.umbrella.legacy; import static de.srsoftware.tools.Optionals.nullable; -import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.ModuleRegistry.projectService; import static de.srsoftware.umbrella.core.ModuleRegistry.userService; -import static de.srsoftware.umbrella.core.Paths.JSON; import static de.srsoftware.umbrella.core.Util.mapValues; +import static de.srsoftware.umbrella.core.constants.Field.TOKEN; +import static de.srsoftware.umbrella.core.constants.Field.USERS; +import static de.srsoftware.umbrella.core.constants.Path.JSON; import com.sun.net.httpserver.HttpExchange; import de.srsoftware.configuration.Configuration; diff --git a/legacy/src/main/java/de/srsoftware/umbrella/legacy/TaskLegacy.java b/legacy/src/main/java/de/srsoftware/umbrella/legacy/TaskLegacy.java index ec3d1667..772489d0 100644 --- a/legacy/src/main/java/de/srsoftware/umbrella/legacy/TaskLegacy.java +++ b/legacy/src/main/java/de/srsoftware/umbrella/legacy/TaskLegacy.java @@ -4,12 +4,11 @@ package de.srsoftware.umbrella.legacy; import static de.srsoftware.tools.Optionals.nullable; -import static de.srsoftware.umbrella.core.Constants.DESCRIPTION; -import static de.srsoftware.umbrella.core.Constants.TOKEN; import static de.srsoftware.umbrella.core.ModuleRegistry.taskService; import static de.srsoftware.umbrella.core.ModuleRegistry.userService; -import static de.srsoftware.umbrella.core.Paths.JSON; import static de.srsoftware.umbrella.core.Util.mapValues; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Path.JSON; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.unprocessable; import com.sun.net.httpserver.HttpExchange; @@ -63,6 +62,6 @@ public class TaskLegacy extends BaseHandler { var taskIds = taskIdMap.values().stream().map(Object::toString).map(Long::parseLong).toList(); return sendContent(ex,mapValues(taskService().load(taskIds))); } - throw unprocessable("Invalid request"); + throw unprocessable("Invalid request"); } } diff --git a/legacy/src/main/java/de/srsoftware/umbrella/legacy/UserLegacy.java b/legacy/src/main/java/de/srsoftware/umbrella/legacy/UserLegacy.java index 445cc5e6..c78824f1 100644 --- a/legacy/src/main/java/de/srsoftware/umbrella/legacy/UserLegacy.java +++ b/legacy/src/main/java/de/srsoftware/umbrella/legacy/UserLegacy.java @@ -3,11 +3,13 @@ package de.srsoftware.umbrella.legacy; import static de.srsoftware.tools.MimeType.MIME_FORM_URL; import static de.srsoftware.tools.Query.decode; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.Constants.TOKEN; import static de.srsoftware.umbrella.core.ModuleRegistry.userService; -import static de.srsoftware.umbrella.core.Paths.*; import static de.srsoftware.umbrella.core.Util.request; +import static de.srsoftware.umbrella.core.constants.Constants.HOME; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Field.REDIRECT; +import static de.srsoftware.umbrella.core.constants.Field.TOKEN; +import static de.srsoftware.umbrella.core.constants.Path.*; import static de.srsoftware.umbrella.user.Paths.*; import static java.lang.Long.parseLong; import static java.lang.System.Logger.Level.*; @@ -17,9 +19,9 @@ import static java.time.temporal.ChronoUnit.DAYS; import com.sun.net.httpserver.HttpExchange; import de.srsoftware.configuration.Configuration; -import de.srsoftware.tools.Path; import de.srsoftware.tools.SessionToken; import de.srsoftware.umbrella.core.BaseHandler; +import de.srsoftware.umbrella.core.constants.Path; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.core.model.Session; import de.srsoftware.umbrella.core.model.Token; @@ -41,7 +43,7 @@ public class UserLegacy extends BaseHandler { } @Override - public boolean doGet(Path path, HttpExchange ex) throws IOException { + public boolean doGet(de.srsoftware.tools.Path path, HttpExchange ex) throws IOException { var head = path.pop(); return switch (head){ case null -> sendRedirect(ex, url(ex).replaceAll("/legacy/.*","")); @@ -49,7 +51,7 @@ public class UserLegacy extends BaseHandler { allowOrigin(ex, "*"); // add CORS header yield load(path,ex); } - case LOGIN -> getLogin(ex); + case Path.LOGIN -> getLogin(ex); case LOGOUT-> logout(ex); case MODULES -> getModules(ex); case SEARCH -> sendRedirect(ex,url(ex).replaceAll("/legacy/","/")); @@ -58,7 +60,7 @@ public class UserLegacy extends BaseHandler { } @Override - public boolean doPost(Path path, HttpExchange ex) throws IOException { + public boolean doPost(de.srsoftware.tools.Path path, HttpExchange ex) throws IOException { try { return switch (path.pop()) { case JSON -> jsonUser(ex); @@ -136,7 +138,7 @@ public class UserLegacy extends BaseHandler { for (var entry : userMap.entrySet()){ return sendContent(ex,entry.getValue()); } - throw UmbrellaException.notFound("Failed to load user(s) for id(s): {0}",ids); + throw UmbrellaException.notFound("Failed to load user(s) for id(s): {id}", ID,ids); } private boolean legacyNotify(HttpExchange ex) throws UmbrellaException, IOException { @@ -206,12 +208,12 @@ public class UserLegacy extends BaseHandler { var expiredToken = new SessionToken(token.toString(),"/", Instant.now().minus(1, DAYS),true); expiredToken.addTo(ex); if (returnTo instanceof String location) return sendRedirect(ex,location); - return sendContent(ex, Map.of(REDIRECT,"home")); + return sendContent(ex, Map.of(REDIRECT,HOME)); } catch (UmbrellaException e) { return send(ex,e); } if (returnTo instanceof String location) return sendRedirect(ex,location); - return sendContent(ex,Map.of(REDIRECT,"home")); + return sendContent(ex,Map.of(REDIRECT,HOME)); } private boolean postSearch(HttpExchange ex) throws IOException, UmbrellaException { @@ -282,7 +284,7 @@ public class UserLegacy extends BaseHandler { var session = userService().load(Token.of(token)); var user = userService().load(session); var userMap = user.toMap(); - userMap.put(TOKEN,Map.of(TOKEN,token,EXPIRATION,session.expiration().getEpochSecond())); + userMap.put(TOKEN,Map.of(TOKEN,token, EXPIRATION,session.expiration().getEpochSecond())); return sendContent(ex,userMap); } } diff --git a/messages/src/main/java/de/srsoftware/umbrella/message/MessageSystem.java b/messages/src/main/java/de/srsoftware/umbrella/message/MessageSystem.java index 6df9e4eb..d70e3865 100644 --- a/messages/src/main/java/de/srsoftware/umbrella/message/MessageSystem.java +++ b/messages/src/main/java/de/srsoftware/umbrella/message/MessageSystem.java @@ -3,8 +3,8 @@ package de.srsoftware.umbrella.message; 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.exceptions.UmbrellaException.missingConfigException; +import static de.srsoftware.umbrella.core.constants.Constants.UTF8; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingConfig; import static de.srsoftware.umbrella.message.Constants.*; import static java.lang.System.Logger.Level.*; @@ -72,7 +72,7 @@ public class MessageSystem implements PostBox { private final HashMap> exceptions = new HashMap<>(); public MessageSystem(Configuration config) throws UmbrellaException { - var dbFile = config.get(CONFIG_DB).orElseThrow(() -> missingConfigException(CONFIG_DB)); + var dbFile = config.get(CONFIG_DB).orElseThrow(() -> missingConfig(CONFIG_DB)); db = new SqliteMessageDb(connect(dbFile)); debugAddress = config.get(DEBUG_ADDREESS).map(Object::toString).orElse(null); port = config.get(CONFIG_SMTP_PORT,587); diff --git a/messages/src/main/java/de/srsoftware/umbrella/message/SqliteMessageDb.java b/messages/src/main/java/de/srsoftware/umbrella/message/SqliteMessageDb.java index b21460ef..deeba630 100644 --- a/messages/src/main/java/de/srsoftware/umbrella/message/SqliteMessageDb.java +++ b/messages/src/main/java/de/srsoftware/umbrella/message/SqliteMessageDb.java @@ -3,13 +3,16 @@ package de.srsoftware.umbrella.message; import static de.srsoftware.tools.jdbc.Condition.equal; import static de.srsoftware.tools.jdbc.Query.*; -import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.Errors.*; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseException; +import static de.srsoftware.umbrella.core.constants.Constants.TABLE_SETTINGS; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; +import static de.srsoftware.umbrella.core.model.Translatable.t; import static de.srsoftware.umbrella.message.model.Settings.Times; import static java.lang.System.Logger.Level.WARNING; import static java.text.MessageFormat.format; +import de.srsoftware.umbrella.core.constants.Text; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.core.model.UmbrellaUser; import de.srsoftware.umbrella.message.model.Settings; @@ -40,7 +43,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} Integer PRIMARY KEY, {2} VARCHAR(255) NOT N stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_SUBMISSIONS).causedBy(e); + throw failedToCreateTable(TABLE_SUBMISSIONS).causedBy(e); } } @@ -54,7 +57,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255) stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_SETTINGS).causedBy(e); + throw failedToCreateTable(TABLE_SETTINGS).causedBy(e); } Integer version = null; @@ -68,7 +71,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255) } return version; } catch (SQLException e) { - throw databaseException(FAILED_TO_UPDATE_ENTITY,DB_VERSION).causedBy(e); + throw databaseException(FAILED_TO_UPDATE_OBJECT, OBJECT,DB_VERSION).causedBy(e); } } @@ -87,7 +90,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255) if (settings != null) return settings; throw new UmbrellaException(500,"No submission settings stored for {0}",user); } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_USER_SETTINGS,user).causedBy(e); + throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER, TYPE,t(Text.SETTINGS), OWNER,user).causedBy(e); } } @@ -114,7 +117,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255) replaceInto(TABLE_SUBMISSIONS, USER_ID, VALUE).values(user.id(),times).execute(db).close(); return settings; } catch (SQLException e) { - throw databaseException(FAILED_TO_STORE_ENTITY,"submission data").causedBy(e); + throw failedToStoreObject("submission data").causedBy(e); } } } diff --git a/notes/src/main/java/de/srsoftware/umbrella/notes/NoteModule.java b/notes/src/main/java/de/srsoftware/umbrella/notes/NoteModule.java index 6ad54848..ab85ce45 100644 --- a/notes/src/main/java/de/srsoftware/umbrella/notes/NoteModule.java +++ b/notes/src/main/java/de/srsoftware/umbrella/notes/NoteModule.java @@ -2,12 +2,11 @@ package de.srsoftware.umbrella.notes; import static de.srsoftware.umbrella.core.ConnectionProvider.connect; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.Constants.FULLTEXT; import static de.srsoftware.umbrella.core.ModuleRegistry.userService; -import static de.srsoftware.umbrella.core.Paths.SEARCH; import static de.srsoftware.umbrella.core.ResponseCode.HTTP_UNPROCESSABLE; import static de.srsoftware.umbrella.core.Util.mapValues; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Path.SEARCH; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; import static de.srsoftware.umbrella.notes.Constants.CONFIG_DATABASE; @@ -34,7 +33,7 @@ public class NoteModule extends BaseHandler implements NoteService { public NoteModule(Configuration config) { super(); - var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE)); + var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingField(CONFIG_DATABASE)); notesDb = new SqliteDb(connect(dbFile)); ModuleRegistry.add(this); } @@ -122,7 +121,7 @@ public class NoteModule extends BaseHandler implements NoteService { var head = path.pop(); long noteId = Long.parseLong(head); String text = body(ex); - if (text.isBlank()) throw missingFieldException("Note text"); + if (text.isBlank()) throw missingField("Note text"); var note = notesDb.load(noteId); if (note.authorId() != user.get().id()) throw forbidden("You are not allowed to edit notes of another user!"); note = new Note(note.id(),note.module(),note.entityId(),note.authorId(),text,LocalDateTime.now()); @@ -146,9 +145,9 @@ public class NoteModule extends BaseHandler implements NoteService { if (SEARCH.equals(module)) return postSearch(ex,user.get()); if (module == null) throw unprocessable("Module missing in path."); var entityId = path.pop(); - if (entityId == null || entityId.isBlank()) throw missingFieldException(ENTITY_ID); + if (entityId == null || entityId.isBlank()) throw missingField(ENTITY_ID); String text = body(ex); - if (text.isBlank()) throw missingFieldException("Note text"); + if (text.isBlank()) throw missingField("Note text"); var note = new Note(0,module,entityId,user.get().id(),text, LocalDateTime.now()); note = save(note); return sendContent(ex, note); @@ -170,7 +169,7 @@ public class NoteModule extends BaseHandler implements NoteService { private boolean postSearch(HttpExchange ex, UmbrellaUser user) throws IOException { var json = json(ex); - if (!(json.has(KEY) && json.get(KEY) instanceof String key)) throw missingFieldException(KEY); + if (!(json.has(KEY) && json.get(KEY) instanceof String key)) throw missingField(KEY); var keys = Arrays.asList(key.split(" ")); var fulltext = json.has(FULLTEXT) && json.get(FULLTEXT) instanceof Boolean val && val; var notes = notesDb.find(user.id(),keys,fulltext); diff --git a/notes/src/main/java/de/srsoftware/umbrella/notes/SqliteDb.java b/notes/src/main/java/de/srsoftware/umbrella/notes/SqliteDb.java index 4f42ad5d..0d06d269 100644 --- a/notes/src/main/java/de/srsoftware/umbrella/notes/SqliteDb.java +++ b/notes/src/main/java/de/srsoftware/umbrella/notes/SqliteDb.java @@ -5,9 +5,12 @@ import static de.srsoftware.tools.jdbc.Condition.equal; import static de.srsoftware.tools.jdbc.Condition.like; import static de.srsoftware.tools.jdbc.Query.*; import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL; -import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.Errors.*; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseException; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Text.NOTE; +import static de.srsoftware.umbrella.core.constants.Text.NOTE_WITH_ID; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; +import static de.srsoftware.umbrella.core.model.Translatable.t; import static de.srsoftware.umbrella.notes.Constants.*; import static java.lang.System.Logger.Level.*; import static java.text.MessageFormat.format; @@ -15,6 +18,7 @@ import static java.time.ZoneOffset.UTC; import de.srsoftware.tools.jdbc.Query; import de.srsoftware.umbrella.core.BaseDb; +import de.srsoftware.umbrella.core.constants.Text; import de.srsoftware.umbrella.core.model.Note; import java.sql.Connection; import java.sql.SQLException; @@ -55,7 +59,7 @@ ADD COLUMN entity_id VARCHAR(255); stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_UPDATE_COLUMN,"(not existing)",ENTITY_ID,TABLE_NOTES).causedBy(e); + throw databaseException(FAILED_TO_UPDATE_COLUMN,"old","(not existing)","new", ENTITY_ID, TABLE,TABLE_NOTES).causedBy(e); } } @@ -69,7 +73,7 @@ ADD COLUMN module VARCHAR(20); stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_UPDATE_COLUMN,"(not existing)",MODULE,TABLE_NOTES).causedBy(e); + throw databaseException(FAILED_TO_UPDATE_COLUMN,"old","(not existing)","new", MODULE, TABLE,TABLE_NOTES).causedBy(e); } } @@ -84,7 +88,7 @@ SET module = SUBSTR(uri, 1, INSTR(uri, ':') - 1), stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException("Failed to fill \"{0}\" and \"{1}\" columns",MODULE,ENTITY_ID).causedBy(e); + throw databaseException("Failed to fill \"{a}\" and \"{b}\" columns","a", MODULE,"b", ENTITY_ID).causedBy(e); } } @@ -101,7 +105,7 @@ CREATE TABLE IF NOT EXISTS notes ( stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_NOTES).causedBy(e); + throw failedToCreateTable(TABLE_NOTES).causedBy(e); } } @@ -120,7 +124,7 @@ CREATE TABLE IF NOT EXISTS "{0}" ( stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_NOTES).causedBy(e); + throw failedToCreateTable(TABLE_NOTES).causedBy(e); } } @@ -132,7 +136,7 @@ CREATE TABLE IF NOT EXISTS "{0}" ( .execute(db); return noteId; } catch (SQLException e){ - throw databaseException(FAILED_TO_DROP_ENTITY,"note",noteId); + throw failedToDropObject(t(NOTE_WITH_ID, ID,noteId)).causedBy(e); } } @@ -143,7 +147,7 @@ CREATE TABLE IF NOT EXISTS "{0}" ( .where(MODULE,equal(module)).where(ENTITY_ID,equal(entityId)) .execute(db); } catch (SQLException e){ - throw databaseException(FAILED_TO_DROP_NOTES,module,entityId).causedBy(e); + throw databaseException(FAILED_TO_DROP_NOTES,MODULE,module, ID,entityId).causedBy(e); } } @@ -154,7 +158,7 @@ CREATE TABLE IF NOT EXISTS "{0}" ( stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_DROP_ENTITY,"uri","column").causedBy(e); + throw databaseException(FAILED_TO_DROP_OBJECT, t("uri column")).causedBy(e); } } @@ -172,7 +176,7 @@ CREATE TABLE IF NOT EXISTS "{0}" ( rs.close(); return notes; } catch (SQLException e) { - throw databaseException(FAILED_TO_SEARCH_DB,TABLE_NOTES).causedBy(e); + throw failedToSearchDb(t(TABLE_NOTES)).causedBy(e); } } @@ -181,7 +185,7 @@ CREATE TABLE IF NOT EXISTS "{0}" ( try { var notes = new HashMap(); var rs = select(ALL).from(TABLE_NOTES).where(USER_ID,equal(authorId)) - .sort(format("{0} DESC",ID)).skip(offset).limit(limit).exec(db); + .sort(format("{0} DESC", ID)).skip(offset).limit(limit).exec(db); while (rs.next()) { var note = Note.of(rs); notes.put(note.id(),note); @@ -189,7 +193,7 @@ CREATE TABLE IF NOT EXISTS "{0}" ( rs.close(); return notes; } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_ENTITY,TABLE_NOTES).causedBy(e); + throw failedToLoadObject(TABLE_NOTES).causedBy(e); } } @@ -207,7 +211,7 @@ CREATE TABLE IF NOT EXISTS "{0}" ( rs.close(); return notes; } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_ENTITY,TABLE_NOTES).causedBy(e); + throw failedToLoadObject(TABLE_NOTES).causedBy(e); } } @@ -220,7 +224,7 @@ CREATE TABLE IF NOT EXISTS "{0}" ( rs.close(); return note; } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_ENTITY_BY_ID,"note",noteId).causedBy(e); + throw failedToLoadObject(t(Text.NOTE),noteId).causedBy(e); } } @@ -244,7 +248,7 @@ CREATE TABLE IF NOT EXISTS "{0}" ( } return note; } catch (SQLException e){ - throw databaseException(FAILED_TO_STORE_ENTITY,"note").causedBy(e); + throw failedToStoreObject(t(Text.NOTE)).causedBy(e); } } @@ -254,7 +258,7 @@ CREATE TABLE IF NOT EXISTS "{0}" ( update(TABLE_NOTES).set(ENTITY_ID).where(MODULE,equal(module)).where(ENTITY_ID,equal(oldId)).prepare(db).apply(newId).close(); LOG.log(DEBUG,"Updated note @ {0}.{1} → {0}.{2}",module,oldId,newId); } catch (SQLException e) { - throw databaseException("Failed to update {0}.{1} → {0}.{2}",module,oldId,newId).causedBy(e); + throw databaseException("Failed to update {module}.{a} → {module}.{b}", MODULE,module,"a",oldId,"b",newId).causedBy(e); } } } diff --git a/project/src/main/java/de/srsoftware/umbrella/project/ProjectModule.java b/project/src/main/java/de/srsoftware/umbrella/project/ProjectModule.java index 31de4591..fd65404f 100644 --- a/project/src/main/java/de/srsoftware/umbrella/project/ProjectModule.java +++ b/project/src/main/java/de/srsoftware/umbrella/project/ProjectModule.java @@ -2,16 +2,20 @@ package de.srsoftware.umbrella.project; import static de.srsoftware.umbrella.core.ConnectionProvider.connect; -import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.ModuleRegistry.*; -import static de.srsoftware.umbrella.core.Paths.LIST; -import static de.srsoftware.umbrella.core.Paths.SEARCH; import static de.srsoftware.umbrella.core.Util.mapValues; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Field.SETTINGS; +import static de.srsoftware.umbrella.core.constants.Field.TAGS; +import static de.srsoftware.umbrella.core.constants.Module.PROJECT; +import static de.srsoftware.umbrella.core.constants.Path.*; +import static de.srsoftware.umbrella.core.constants.Text.*; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; import static de.srsoftware.umbrella.core.model.Permission.*; import static de.srsoftware.umbrella.core.model.Permission.OWNER; import static de.srsoftware.umbrella.core.model.Status.OPEN; import static de.srsoftware.umbrella.core.model.Status.PREDEFINED; +import static de.srsoftware.umbrella.core.model.Translatable.t; import static de.srsoftware.umbrella.messagebus.MessageBus.messageBus; import static de.srsoftware.umbrella.messagebus.events.Event.EventType.CREATE; import static de.srsoftware.umbrella.messagebus.events.Event.EventType.UPDATE; @@ -21,11 +25,12 @@ import static java.net.HttpURLConnection.HTTP_BAD_REQUEST; import com.sun.net.httpserver.HttpExchange; import de.srsoftware.configuration.Configuration; -import de.srsoftware.tools.Path; import de.srsoftware.tools.SessionToken; -import de.srsoftware.umbrella.core.BaseHandler; -import de.srsoftware.umbrella.core.ModuleRegistry; +import de.srsoftware.umbrella.core.*; import de.srsoftware.umbrella.core.api.ProjectService; +import de.srsoftware.umbrella.core.constants.Field; +import de.srsoftware.umbrella.core.constants.Path; +import de.srsoftware.umbrella.core.constants.Text; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.core.model.*; import de.srsoftware.umbrella.messagebus.events.ProjectEvent; @@ -40,7 +45,7 @@ public class ProjectModule extends BaseHandler implements ProjectService { public ProjectModule(Configuration config) throws UmbrellaException { super(); - var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE)); + var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingField(CONFIG_DATABASE)); projectDb = new SqliteDb(connect(dbFile)); ModuleRegistry.add(this); } @@ -53,7 +58,7 @@ public class ProjectModule extends BaseHandler implements ProjectService { } @Override - public boolean doGet(Path path, HttpExchange ex) throws IOException { + public boolean doGet(de.srsoftware.tools.Path path, HttpExchange ex) throws IOException { addCors(ex); try { Optional token = SessionToken.from(ex).map(Token::of); @@ -77,7 +82,7 @@ public class ProjectModule extends BaseHandler implements ProjectService { } @Override - public boolean doPatch(Path path, HttpExchange ex) throws IOException { + public boolean doPatch(de.srsoftware.tools.Path path, HttpExchange ex) throws IOException { addCors(ex); try { Optional token = SessionToken.from(ex).map(Token::of); @@ -100,7 +105,7 @@ public class ProjectModule extends BaseHandler implements ProjectService { } @Override - public boolean doPost(Path path, HttpExchange ex) throws IOException { + public boolean doPost(de.srsoftware.tools.Path path, HttpExchange ex) throws IOException { addCors(ex); try { Optional token = SessionToken.from(ex).map(Token::of); @@ -115,7 +120,7 @@ public class ProjectModule extends BaseHandler implements ProjectService { var projectId = Long.parseLong(head); head = path.pop(); yield switch (head){ - case STATE -> postNewState(ex,projectId,user.get()); + case Path.STATE -> postNewState(ex,projectId,user.get()); case null, default -> super.doGet(path, ex); }; } @@ -135,9 +140,9 @@ public class ProjectModule extends BaseHandler implements ProjectService { private boolean getProject(HttpExchange ex, long projectId, UmbrellaUser user) throws IOException, UmbrellaException { var project = loadMembers(projectDb.load(projectId)); - if (!project.hasMember(user)) throw forbidden("You are not a member of {0}",project.name()); + if (!project.hasMember(user)) throw notAmember(t(PROJECT_WITH_ID,ID,project.name())); var map = project.toMap(); - project.companyId().map(companyService()::get).map(Company::toMap).ifPresent(data -> map.put(COMPANY,data)); + project.companyId().map(companyService()::get).map(Company::toMap).ifPresent(data -> map.put(Field.COMPANY,data)); return sendContent(ex,map); } @@ -149,7 +154,7 @@ public class ProjectModule extends BaseHandler implements ProjectService { private boolean listCompanyProjects(HttpExchange ex, UmbrellaUser user, long companyId) throws IOException, UmbrellaException { var company = companyService().get(companyId); - if (!companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name()); + if (!companyService().membership(companyId,user.id())) throw notAmember(t(COMPANY_WITH_ID,ID,company.name())); var projects = listCompanyProjects(companyId,false); return sendContent(ex,mapValues(projects)); } @@ -193,9 +198,9 @@ public class ProjectModule extends BaseHandler implements ProjectService { try { userId = Long.parseLong(key); } catch (NumberFormatException e) { - throw invalidFieldException(USER_ID,"long"); + throw invalidField(USER_ID,t(LONG)); } - if (!(json.get(key) instanceof Number number)) throw invalidFieldException(PERMISSION,"int"); + if (!(json.get(key) instanceof Number number)) throw invalidField(PERMISSION,t(Text.NUMBER)); var permission = Permission.of(number.intValue()); if (permission == OWNER) { // if a new person is about to become the project owner for (var member : members.values()){ // alter the previous owners to editors @@ -209,7 +214,7 @@ public class ProjectModule extends BaseHandler implements ProjectService { private boolean patchProject(HttpExchange ex, long projectId, UmbrellaUser user) throws IOException, UmbrellaException { var project = loadMembers(projectDb.load(projectId)); - if (!project.hasMember(user)) throw forbidden("You are not a member of {0}",project.name()); + if (!project.hasMember(user)) throw notAmember(t(PROJECT_WITH_ID,ID,project.name())); var json = json(ex); if (json.has(DROP_MEMBER) && json.get(DROP_MEMBER) instanceof Number id) dropMember(project,id.longValue()); if (json.has(MEMBERS) && json.get(MEMBERS) instanceof JSONObject memberJson) patchMembers(project,memberJson); @@ -223,17 +228,17 @@ public class ProjectModule extends BaseHandler implements ProjectService { private boolean postNewState(HttpExchange ex, long projectId, UmbrellaUser user) throws IOException { var project = loadMembers(load(projectId)); - if (!project.hasMember(user)) throw forbidden("You are not a member of {0}",project.name()); + if (!project.hasMember(user)) throw notAmember(t(PROJECT_WITH_ID,ID,project.name())); var json = json(ex); - if (!(json.has(CODE) && json.get(CODE) instanceof Number code)) throw missingFieldException(CODE); - if (!(json.has(NAME) && json.get(NAME) instanceof String name)) throw missingFieldException(NAME); + if (!(json.has(Field.CODE) && json.get(Field.CODE) instanceof Number code)) throw missingField(Field.CODE); + if (!(json.has(NAME) && json.get(NAME) instanceof String name)) throw missingField(NAME); var newState = new Status(name,code.intValue()); return sendContent(ex, projectDb.save(projectId,newState)); } private boolean postProject(HttpExchange ex, UmbrellaUser user) throws IOException, UmbrellaException { var json = json(ex); - if (!(json.has(NAME) && json.get(NAME) instanceof String name)) throw missingFieldException(NAME); + if (!(json.has(NAME) && json.get(NAME) instanceof String name)) throw missingField(NAME); String description = null; if (json.has(DESCRIPTION)){ var desc = json.get(DESCRIPTION); @@ -242,7 +247,7 @@ public class ProjectModule extends BaseHandler implements ProjectService { } Long companyId = null; if (json.has(COMPANY_ID) && json.get(COMPANY_ID) instanceof Number number){ - if (!companyService().membership(number.longValue(), user.id())) throw forbidden("You are not a member of company {0}!",number); + if (!companyService().membership(number.longValue(), user.id())) throw notAmember(t(COMPANY_WITH_ID, ID,number)); companyId = number.longValue(); } var showClosed = false; @@ -271,7 +276,7 @@ public class ProjectModule extends BaseHandler implements ProjectService { private boolean postSearch(UmbrellaUser user, HttpExchange ex) throws IOException { var json = json(ex); - if (!(json.has(KEY) && json.get(KEY) instanceof String key)) throw missingFieldException(KEY); + if (!(json.has(KEY) && json.get(KEY) instanceof String key)) throw missingField(KEY); var keys = Arrays.asList(key.split(" ")); var fulltext = json.has(FULLTEXT) && json.get(FULLTEXT) instanceof Boolean val && val; var projects = projectDb.find(user.id(),keys,fulltext); diff --git a/project/src/main/java/de/srsoftware/umbrella/project/SqliteDb.java b/project/src/main/java/de/srsoftware/umbrella/project/SqliteDb.java index 2c64ad97..12673ad1 100644 --- a/project/src/main/java/de/srsoftware/umbrella/project/SqliteDb.java +++ b/project/src/main/java/de/srsoftware/umbrella/project/SqliteDb.java @@ -4,22 +4,22 @@ package de.srsoftware.umbrella.project; import static de.srsoftware.tools.jdbc.Condition.*; import static de.srsoftware.tools.jdbc.Query.*; import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL; -import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.Errors.*; -import static de.srsoftware.umbrella.core.ModuleRegistry.translator; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseException; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.notFound; +import static de.srsoftware.umbrella.core.constants.Constants.TABLE_SETTINGS; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Field.TYPE; +import static de.srsoftware.umbrella.core.constants.Text.*; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; import static de.srsoftware.umbrella.core.model.Status.COMPLETE; import static de.srsoftware.umbrella.core.model.Status.OPEN; +import static de.srsoftware.umbrella.core.model.Translatable.t; import static de.srsoftware.umbrella.project.Constants.*; import static java.text.MessageFormat.format; import de.srsoftware.umbrella.core.BaseDb; +import de.srsoftware.umbrella.core.constants.Field; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; -import de.srsoftware.umbrella.core.model.Permission; -import de.srsoftware.umbrella.core.model.Project; -import de.srsoftware.umbrella.core.model.Status; -import de.srsoftware.umbrella.core.model.UmbrellaUser; +import de.srsoftware.umbrella.core.model.*; import java.sql.Connection; import java.sql.SQLException; import java.util.Collection; @@ -48,7 +48,7 @@ public class SqliteDb extends BaseDb implements ProjectDb { stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_PROJECTS).causedBy(e); + throw failedToCreateTable(TABLE_PROJECTS).causedBy(e); } } @@ -66,7 +66,7 @@ PRIMARY KEY (project_id, code) stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_CUSTOM_STATES).causedBy(e); + throw failedToCreateTable(TABLE_CUSTOM_STATES).causedBy(e); } } @@ -98,7 +98,7 @@ CREATE TABLE IF NOT EXISTS {0} ( stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_PROJECT_USERS).causedBy(e); + throw failedToCreateTable(TABLE_PROJECT_USERS).causedBy(e); } } @@ -111,7 +111,7 @@ CREATE TABLE IF NOT EXISTS {0} ( .where(USER_ID,equal(userId)) .execute(db); } catch (SQLException e) { - throw databaseException(FAILED_TO_DROP_ENTITY_OF_ENTITY,"member",userId,"project",projectId).causedBy(e); + throw failedToDropObjectFromObject("member",userId,t(PROJECT),projectId).causedBy(e); } } @@ -124,7 +124,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return result; } catch (SQLException e){ - throw databaseException(FAILED_TO_LOAD_ENTITY_MEMBERS,PROJECT,project.name()).causedBy(e); + throw failedToLoadMembers(t(PROJECT_WITH_ID,ID,project.name())).causedBy(e); } } @@ -136,7 +136,7 @@ CREATE TABLE IF NOT EXISTS {0} ( if (rs.next()) project = Project.of(rs); rs.close(); - if (project == null) throw notFound("no_project_for_id",projectId); + if (project == null) throw notFound("No project for id {id}", ID,projectId); rs = select(ALL).from(TABLE_CUSTOM_STATES).where(PROJECT_ID,equal(projectId)).exec(db); var states = project.allowedStates(); @@ -151,7 +151,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return project; } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_ENTITY,"project").causedBy(e); + throw failedToLoadObject(t(PROJECT),projectId).causedBy(e); } } @@ -173,7 +173,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return projects; } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_ENTITY,"items").causedBy(e); + throw failedToLoadObject("items").causedBy(e); } } @@ -181,9 +181,9 @@ CREATE TABLE IF NOT EXISTS {0} ( public Map find(long userId, Collection keys, boolean fulltext) { try { var projects = new HashMap(); - var query = select(ALL).from(TABLE_PROJECTS).leftJoin(ID,TABLE_PROJECT_USERS,PROJECT_ID).where(USER_ID, equal(userId)); + var query = select(ALL).from(TABLE_PROJECTS).leftJoin(ID,TABLE_PROJECT_USERS, PROJECT_ID).where(USER_ID, equal(userId)); if (fulltext) { - for (var key : keys) query.where(format("CONCAT({0},\" \",{1})",NAME,DESCRIPTION),like("%"+key+"%")); + for (var key : keys) query.where(format("CONCAT({0},\" \",{1})", NAME, DESCRIPTION),like("%"+key+"%")); } else { for (var key : keys) query.where(NAME,like("%"+key+"%")); } @@ -195,7 +195,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return projects; } catch (SQLException e) { - throw databaseException(FAILED_TO_LIST_ENTITIES,"items").causedBy(e); + throw databaseException(FAILED_TO_LIST_ENTITIES, TYPE,t(ITEMS)).causedBy(e); } } @@ -203,7 +203,7 @@ CREATE TABLE IF NOT EXISTS {0} ( public Map ofUser(long userId, boolean includeClosed) throws UmbrellaException { try { var projects = new HashMap(); - var query = select(ALL).from(TABLE_PROJECTS).leftJoin(ID,TABLE_PROJECT_USERS,PROJECT_ID).where(USER_ID, equal(userId)); + var query = select(ALL).from(TABLE_PROJECTS).leftJoin(ID,TABLE_PROJECT_USERS, PROJECT_ID).where(USER_ID, equal(userId)); if (!includeClosed) query = query.where(STATUS,lessThan(COMPLETE.code())); var rs = query.exec(db); while (rs.next()){ @@ -213,7 +213,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return projects; } catch (SQLException e) { - throw databaseException(FAILED_TO_LIST_ENTITIES).causedBy(e); + throw databaseException(FAILED_TO_LIST_ENTITIES, t("projects")).causedBy(e); } } @@ -234,29 +234,29 @@ CREATE TABLE IF NOT EXISTS {0} ( return new Project(id, prj.name(), prj.description(),prj.status(),prj.companyId().orElse(null),prj.showClosed(),prj.members(),prj.allowedStates()); } } catch (SQLException e) { - throw databaseException(FAILED_TO_STORE_ENTITY,PROJECT).causedBy(e); + throw failedToStoreObject(prj).causedBy(e); } } else { // Update try { if (prj.isDirty(MEMBERS)){ - var query = replaceInto(TABLE_PROJECT_USERS,PROJECT_ID,USER_ID,PERMISSIONS); + var query = replaceInto(TABLE_PROJECT_USERS, PROJECT_ID, USER_ID,PERMISSIONS); for (var member : prj.members().entrySet()) query.values(prj.id(),member.getKey(),member.getValue().permission().code()); query.execute(db).close(); prj.clean(MEMBERS); } if (prj.isDirty(TAG_COLORS)){ - replaceInto(TABLE_SETTINGS,KEY,VALUE).values(colorKey(prj.id()),new JSONObject(prj.tagColors()).toString()).execute(db).close(); + replaceInto(TABLE_SETTINGS, KEY,VALUE).values(colorKey(prj.id()),new JSONObject(prj.tagColors()).toString()).execute(db).close(); prj.clean(TAG_COLORS); } if (prj.isDirty()){ - update(TABLE_PROJECTS).set(NAME,DESCRIPTION,STATUS,COMPANY_ID,SHOW_CLOSED).where(ID,equal(prj.id())).prepare(db) + update(TABLE_PROJECTS).set(NAME, DESCRIPTION, STATUS, COMPANY_ID, SHOW_CLOSED).where(ID,equal(prj.id())).prepare(db) .apply(prj.name(),prj.description(),prj.status(),prj.companyId(),prj.showClosed()) .execute(); prj.clean(); } return prj; } catch (SQLException e) { - throw databaseException(FAILED_TO_UPDATE_ENTITY, translator().translate(user.language(),"project")).causedBy(e); + throw databaseException(FAILED_TO_UPDATE_OBJECT, t(PROJECT_WITH_ID, ID,prj.name())).causedBy(e); } } return null; @@ -266,7 +266,7 @@ CREATE TABLE IF NOT EXISTS {0} ( @Override public Status save(long projectId, Status newState) { try { - insertInto(TABLE_CUSTOM_STATES,PROJECT_ID,CODE,NAME).values(projectId,newState.code(),newState.name()).execute(db).close(); + insertInto(TABLE_CUSTOM_STATES, PROJECT_ID, Field.CODE, NAME).values(projectId,newState.code(),newState.name()).execute(db).close(); return newState; } catch (SQLException e) { throw databaseException(FAILED_TO_CREATE_STATE).causedBy(e); diff --git a/stock/src/main/java/de/srsoftware/umbrella/stock/Constants.java b/stock/src/main/java/de/srsoftware/umbrella/stock/Constants.java index cb178c81..917a62f9 100644 --- a/stock/src/main/java/de/srsoftware/umbrella/stock/Constants.java +++ b/stock/src/main/java/de/srsoftware/umbrella/stock/Constants.java @@ -9,10 +9,8 @@ public class Constants { public static final String BELOW = "below"; public static final String CONFIG_DATABASE = "umbrella.modules.stock.database"; public static final String CONFIG_ITEM_DB = "umbrella.modules.items.database"; - public static final String ITEM = "item"; public static final String ITEM_ID = "item_id"; public static final String ITEMS = "items"; - public static final String LOCATIONS = "locations"; public static final String MOVE_ITEM = "move_item"; public static final String MOVE_LOCATION = "move_location"; public static final String OF_USER = "of_user"; diff --git a/stock/src/main/java/de/srsoftware/umbrella/stock/ItemDb.java b/stock/src/main/java/de/srsoftware/umbrella/stock/ItemDb.java index a290ed4f..779253ed 100644 --- a/stock/src/main/java/de/srsoftware/umbrella/stock/ItemDb.java +++ b/stock/src/main/java/de/srsoftware/umbrella/stock/ItemDb.java @@ -4,16 +4,18 @@ package de.srsoftware.umbrella.stock; import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL; import static de.srsoftware.tools.jdbc.Query.select; import static de.srsoftware.umbrella.core.ConnectionProvider.connect; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.Field.COMPANY_ID; -import static de.srsoftware.umbrella.core.Field.UNIT_PRICE; import static de.srsoftware.umbrella.core.ModuleRegistry.companyService; import static de.srsoftware.umbrella.core.ModuleRegistry.translator; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Text.T_UNIT_PRICE; +import static de.srsoftware.umbrella.core.constants.Text.UNIT; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseException; import static de.srsoftware.umbrella.stock.Constants.TABLE_ITEMS; import static java.lang.System.Logger.Level.DEBUG; import de.srsoftware.tools.Tuple; +import de.srsoftware.umbrella.core.constants.Field; +import de.srsoftware.umbrella.core.constants.Text; import de.srsoftware.umbrella.core.model.*; import java.sql.Connection; import java.sql.SQLException; @@ -36,7 +38,7 @@ public class ItemDb { while (rs.next()){ var id = rs.getLong(ID); var companyId = rs.getLong(COMPANY_ID); - var code = rs.getString(CODE); + var code = rs.getString(Field.CODE); var name = rs.getString(NAME); var description = rs.getString(DESCRIPTION); var unit = rs.getString(UNIT); @@ -73,8 +75,8 @@ public class ItemDb { LOG.log(DEBUG, " using location: {0}",location.resolve().name()); var stockItem = new Item(0,company,0,location,code,name,description); var props = stockItem.properties(); - var keyUnitPrice = translator().translate(lang,UNIT_PRICE); - var keyUnit = translator().translate(lang,UNIT); + var keyUnitPrice = translator().translate(lang,T_UNIT_PRICE); + var keyUnit = translator().translate(lang, Text.UNIT); var keyTax = translator().translate(lang,TAX_RATE); var keyLegacyId = translator().translate(lang,"legacy_id"); props.add(new Property(0,keyUnitPrice,unitPrice/100d,company.currency())); @@ -86,7 +88,7 @@ public class ItemDb { } rs.close(); } catch (SQLException e) { - throw databaseException("Failed to migrate items from itemDB to stockDB!"); + throw databaseException("Failed to migrate items from ItemDB to stockDB!"); } } } diff --git a/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java b/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java index 9bc8e05f..ddbeddac 100644 --- a/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java +++ b/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java @@ -7,11 +7,18 @@ import static de.srsoftware.tools.jdbc.Condition.*; import static de.srsoftware.tools.jdbc.Condition.like; import static de.srsoftware.tools.jdbc.Query.*; import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL; -import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.Errors.*; import static de.srsoftware.umbrella.core.ModuleRegistry.noteService; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseException; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.notFound; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Field.LOCATIONS; +import static de.srsoftware.umbrella.core.constants.Field.TYPE; +import static de.srsoftware.umbrella.core.constants.Field.UNIT; +import static de.srsoftware.umbrella.core.constants.Text.*; +import static de.srsoftware.umbrella.core.constants.Text.ITEMS; +import static de.srsoftware.umbrella.core.constants.Text.LOCATION; +import static de.srsoftware.umbrella.core.constants.Text.PROPERTY; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; +import static de.srsoftware.umbrella.core.model.Translatable.t; import static de.srsoftware.umbrella.stock.Constants.*; import static java.lang.System.Logger.Level.*; import static java.text.MessageFormat.format; @@ -19,6 +26,8 @@ import static java.text.MessageFormat.format; import de.srsoftware.tools.jdbc.Query; import de.srsoftware.umbrella.core.BaseDb; import de.srsoftware.umbrella.core.api.Owner; +import de.srsoftware.umbrella.core.constants.Field; +import de.srsoftware.umbrella.core.constants.Text; import de.srsoftware.umbrella.core.model.*; import de.srsoftware.umbrella.core.model.Location; import java.sql.Connection; @@ -35,7 +44,7 @@ public class SqliteDb extends BaseDb implements StockDb { public String owner() { var parts = id.split(":"); - if (parts.length != 3) throw databaseException("Expected legacy location id to be of the form ss:dd:ss, encountered {0}!",id); + if (parts.length != 3) throw databaseException("Expected legacy location id to be of the form ss:dd:ss, encountered {ID}!", ID,id); return String.join(":", parts[0], parts[1]); } }; @@ -48,26 +57,26 @@ public class SqliteDb extends BaseDb implements StockDb { public Property addNewProperty(long itemId, String name, Object value, String unit) { try { db.setAutoCommit(false); - var rs = insertInto(TABLE_PROPERTIES,NAME,TYPE,UNIT).values(name,0,unit).execute(db).getGeneratedKeys(); + var rs = insertInto(TABLE_PROPERTIES, NAME, TYPE,UNIT).values(name,0,unit).execute(db).getGeneratedKeys(); Long propertyId = null; if (rs.next()) propertyId = rs.getLong(1); rs.close(); - if (propertyId == null || propertyId == 0) throw databaseException(FAILED_TO_STORE_ENTITY,"property"); + if (propertyId == null || propertyId == 0) throw failedToStoreObject(t(PROPERTY)); insertInto(TABLE_ITEM_PROPERTIES,ITEM_ID,PROPERTY_ID,VALUE).values(itemId,propertyId,value).execute(db).close(); db.setAutoCommit(true); return new Property(propertyId,name,value,unit); } catch (SQLException e) { - throw databaseException(FAILED_TO_STORE_ENTITY,"property").causedBy(e); + throw failedToStoreObject(t(PROPERTY)).causedBy(e); } } private void createDescriptionColumn(){ try { var sql = "ALTER TABLE {0} ADD COLUMN {1} TEXT"; - sql = format(sql,TABLE_ITEMS,DESCRIPTION); + sql = format(sql,TABLE_ITEMS, DESCRIPTION); db.prepareStatement(sql).execute(); } catch (SQLException e) { - throw databaseException(FAILED_TO_ADD_COLUMN,DESCRIPTION,TABLE_ITEMS).causedBy(e); + throw databaseException(FAILED_TO_ADD_COLUMN, NAME, DESCRIPTION, TABLE,TABLE_ITEMS).causedBy(e); } } @@ -84,7 +93,7 @@ public class SqliteDb extends BaseDb implements StockDb { {3} VARCHAR(255), {4} VARCHAR(255) NOT NULL, {5} LONG NOT NULL)"""; - sql = format(sql, ID, OWNER, OWNER_NUMBER, CODE, NAME, LOCATION_ID); + sql = format(sql, ID, OWNER, OWNER_NUMBER, Field.CODE, NAME, LOCATION_ID); db.prepareStatement(sql).execute(); } @@ -117,10 +126,10 @@ public class SqliteDb extends BaseDb implements StockDb { private void createItemsTable() { try { var sql = "CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255) NOT NULL, {3} TEXT, {4} VARCHAR(255))"; - sql = format(sql, TABLE_ITEMS, ID, CODE, NAME, LOCATION_ID); + sql = format(sql, TABLE_ITEMS, ID, Field.CODE, NAME, LOCATION_ID); db.prepareStatement(sql).execute(); } catch (SQLException e) { - throw databaseException(ERROR_FAILED_CREATE_TABLE,TABLE_ITEMS).causedBy(e); + throw failedToCreateTable(TABLE_ITEMS).causedBy(e); } } @@ -130,7 +139,7 @@ public class SqliteDb extends BaseDb implements StockDb { sql = format(sql, TABLE_ITEM_PROPERTIES, ITEM_ID, PROPERTY_ID,VALUE); db.prepareStatement(sql).execute(); } catch (SQLException e) { - throw databaseException(ERROR_FAILED_CREATE_TABLE,TABLE_ITEM_PROPERTIES).causedBy(e); + throw failedToCreateTable(TABLE_ITEM_PROPERTIES).causedBy(e); } } @@ -140,7 +149,7 @@ public class SqliteDb extends BaseDb implements StockDb { sql = format(sql, TABLE_LOCATIONS, ID, LOCATION_ID, NAME, DESCRIPTION); db.prepareStatement(sql).execute(); } catch (SQLException e) { - throw databaseException(ERROR_FAILED_CREATE_TABLE,TABLE_LOCATIONS).causedBy(e); + throw failedToCreateTable(TABLE_LOCATIONS).causedBy(e); } } @@ -150,7 +159,7 @@ public class SqliteDb extends BaseDb implements StockDb { sql = format(sql, TABLE_PROPERTIES, ID, NAME, TYPE, UNIT); db.prepareStatement(sql).execute(); } catch (SQLException e) { - throw databaseException(ERROR_FAILED_CREATE_TABLE,TABLE_PROPERTIES).causedBy(e); + throw failedToCreateTable(TABLE_PROPERTIES).causedBy(e); } } @@ -179,7 +188,7 @@ public class SqliteDb extends BaseDb implements StockDb { Query.delete().from(TABLE_LOCATIONS).where(ID,equal(location.id())).execute(db); return location; } catch (SQLException e){ - throw databaseException(FAILED_TO_DROP_ENTITY,location.name()).causedBy(e); + throw failedToDropObject(location.name()).causedBy(e); } } @@ -187,7 +196,7 @@ public class SqliteDb extends BaseDb implements StockDb { try { db.prepareStatement("DROP TABLE IF EXISTS tokens").execute(); } catch (SQLException e) { - throw databaseException(FAILED_TO_DROP_ENTITY,"table tokens").causedBy(e); + throw failedToDropObject("table tokens").causedBy(e); } } @@ -199,7 +208,7 @@ public class SqliteDb extends BaseDb implements StockDb { var query = select(ALL).from(TABLE_ITEMS).where(OWNER, in(ownerCodes)); if (fulltext) { query.leftJoin(ID,TABLE_ITEM_PROPERTIES,ITEM_ID); - for (var key : keys) query.where(format("CONCAT({0},\" \",{1},\" \",{2})",NAME,DESCRIPTION,VALUE),like("%"+key+"%")); + for (var key : keys) query.where(format("CONCAT({0},\" \",{1},\" \",{2})", NAME, DESCRIPTION,VALUE),like("%"+key+"%")); } else { for (var key : keys) query.where(NAME,like("%"+key+"%")); } @@ -211,7 +220,7 @@ public class SqliteDb extends BaseDb implements StockDb { rs.close(); return items; } catch (SQLException e) { - throw databaseException(FAILED_TO_LIST_ENTITIES,ITEMS).causedBy(e); + throw databaseException(FAILED_TO_LIST_ENTITIES, TYPE,t(ITEMS)).causedBy(e); } } @@ -224,7 +233,7 @@ public class SqliteDb extends BaseDb implements StockDb { rs.close(); return list; } catch (SQLException e){ - throw databaseException(FAILED_TO_LOAD_CHILD_LOCATIONS,parentId).causedBy(e); + throw databaseException(FAILED_TO_LOAD_CHILD_LOCATIONS,PARENT,parentId).causedBy(e); } } @@ -237,7 +246,7 @@ public class SqliteDb extends BaseDb implements StockDb { rs.close(); return list; } catch (SQLException e){ - throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER,"locations",company.name()).causedBy(e); + throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER, TYPE,t(Text.LOCATIONS), OWNER,company.name()).causedBy(e); } } @@ -252,7 +261,7 @@ public class SqliteDb extends BaseDb implements StockDb { for (var item : list) loadProperties(item); return list; } catch (SQLException e){ - throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER,ITEMS,location).causedBy(e); + throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER, TYPE,ITEMS, OWNER,location).causedBy(e); } } @@ -268,7 +277,7 @@ public class SqliteDb extends BaseDb implements StockDb { for (var item : list) loadProperties(item); return list; } catch (SQLException e){ - throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER,ITEMS,company).causedBy(e); + throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER, TYPE,ITEMS, OWNER,company).causedBy(e); } } @@ -280,7 +289,7 @@ public class SqliteDb extends BaseDb implements StockDb { rs.close(); return item; } catch (SQLException e){ - throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER,PROPERTIES,item.name()).causedBy(e); + throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER, TYPE,t(Text.PROPERTIES), OWNER,item.name()).causedBy(e); } } @@ -303,9 +312,9 @@ public class SqliteDb extends BaseDb implements StockDb { if (rs.next()) result = Item.of(rs); rs.close(); if (result != null) return result; - throw notFound(FAILED_TO_LOAD_ENTITY,ITEM); + throw notFound(FAILED_TO_LOAD_OBJECT, OBJECT,t(Text.ITEM)); } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_ENTITY,ITEM).causedBy(e); + throw failedToLoadObject(t(Text.ITEM)).causedBy(e); } } @@ -316,9 +325,9 @@ public class SqliteDb extends BaseDb implements StockDb { if (rs.next()) loc = DbLocation.of(rs); rs.close(); if (loc != null) return loc; - throw notFound(FAILED_TO_LOAD_ENTITY_BY_ID,LOCATION,locationId); + throw failedToLoadObject(t(LOCATION),locationId); } catch (SQLException e){ - throw databaseException(FAILED_TO_LOAD_ENTITY_BY_ID,LOCATION,locationId).causedBy(e); + throw failedToLoadObject(t(LOCATION),locationId).causedBy(e); } } @@ -331,7 +340,7 @@ public class SqliteDb extends BaseDb implements StockDb { rs.close(); return list; } catch (SQLException e){ - throw databaseException(FAILED_TO_LOAD_ENTITY,PROPERTIES).causedBy(e); + throw failedToLoadObject(t(Text.PROPERTIES)).causedBy(e); } } @@ -344,7 +353,7 @@ public class SqliteDb extends BaseDb implements StockDb { rs.close(); return list; } catch (SQLException e){ - throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER,LOCATIONS,user.name()).causedBy(e); + throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER, TYPE,t(Text.LOCATIONS), OWNER,user.name()).causedBy(e); } } @@ -356,7 +365,7 @@ public class SqliteDb extends BaseDb implements StockDb { rs.close(); return number +1L; } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER,"last item number",owner).causedBy(e); + throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER, TYPE,"last item number", OWNER,owner).causedBy(e); } } @@ -379,7 +388,7 @@ public class SqliteDb extends BaseDb implements StockDb { location = parent; } } catch (SQLException e){ - throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER,"path",target).causedBy(e); + throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER, TYPE,t(Text.PATH), OWNER,target).causedBy(e); } return root; } @@ -404,16 +413,16 @@ public class SqliteDb extends BaseDb implements StockDb { var parentId = is0(location.parent()) ? null : location.parent(); if (location.id() == 0) { // new location try { - var rs = insertInto(TABLE_LOCATIONS,OWNER,PARENT_LOCATION_ID,NAME,DESCRIPTION) + var rs = insertInto(TABLE_LOCATIONS, OWNER, PARENT_LOCATION_ID, NAME, DESCRIPTION) .values(location.owner().dbCode(),parentId,location.name(),location.description()) .execute(db).getGeneratedKeys(); long id = 0; if (rs.next()) id = rs.getLong(1); rs.close(); - if (id == 0) throw databaseException(FAILED_TO_STORE_ENTITY,location.name()); + if (id == 0) throw failedToStoreObject(location.name()); return location.id(id); } catch (SQLException e){ - throw databaseException(FAILED_TO_STORE_ENTITY,location.name()).causedBy(e); + throw failedToStoreObject(location.name()).causedBy(e); } } else { try { @@ -425,7 +434,7 @@ public class SqliteDb extends BaseDb implements StockDb { .close(); return location.clear(); } catch (SQLException e){ - throw databaseException(FAILED_TO_UPDATE_ENTITY,location.name()).causedBy(e); + throw databaseException(FAILED_TO_UPDATE_OBJECT, OBJECT,location.name()).causedBy(e); } } } @@ -435,22 +444,22 @@ public class SqliteDb extends BaseDb implements StockDb { if (item.id() == 0){ var number = nextItemNumberFor(item.location().resolve().owner()); try { - var rs = insertInto(TABLE_ITEMS, OWNER, OWNER_NUMBER, CODE, NAME, DESCRIPTION, LOCATION_ID) + var rs = insertInto(TABLE_ITEMS, OWNER, OWNER_NUMBER, Field.CODE, NAME, DESCRIPTION, LOCATION_ID) .values(item.owner().dbCode(), number, item.code(), item.name(), item.description(), item.location().id()) .execute(db).getGeneratedKeys(); if (rs.next()) item.id(rs.getLong(1)).ownerNumber(number); rs.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_STORE_ENTITY,item.name()).causedBy(e); + throw failedToStoreObject(item.name()).causedBy(e); } } else if (item.isDirty()) { try { var location = item.location(); var query = update(TABLE_ITEMS).where(ID, equal(item.id())); if (location == null) { - query.set(CODE,NAME,DESCRIPTION); + query.set(Field.CODE, NAME, DESCRIPTION); } else { - query.set(CODE,NAME,DESCRIPTION,LOCATION_ID); + query.set(Field.CODE, NAME, DESCRIPTION, LOCATION_ID); } var pq = query.prepare(db); if (location == null) { @@ -460,7 +469,7 @@ public class SqliteDb extends BaseDb implements StockDb { } item.clear(); } catch (SQLException e){ - throw databaseException(FAILED_TO_UPDATE_ENTITY,item.name()).causedBy(e); + throw databaseException(FAILED_TO_UPDATE_OBJECT, OBJECT,item.name()).causedBy(e); } } saveProperties(item); @@ -483,7 +492,7 @@ public class SqliteDb extends BaseDb implements StockDb { if (rs.next()) propId = rs.getLong(1); rs.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_ENTITY,property.name()).causedBy(e); + throw failedToLoadObject(property.name()).causedBy(e); } } if (is0(propId)) return addNewProperty(item.id(), property.name(), property.value(), property.unit()); @@ -497,7 +506,7 @@ public class SqliteDb extends BaseDb implements StockDb { var rs = select(ALL).from(TABLE_PROPERTIES).where(ID,equal(existingPropId)).exec(db); if (rs.next()) prop = Property.of(rs); rs.close(); - if (prop == null) throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER,"property "+existingPropId,"item "+itemId); + if (prop == null) throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER, TYPE,"property "+existingPropId, OWNER,"item "+itemId); if ("".equals(value)){ Query.delete().from(TABLE_ITEM_PROPERTIES).where(ITEM_ID,equal(itemId)).where(PROPERTY_ID,equal(existingPropId)).execute(db); } else { @@ -505,30 +514,30 @@ public class SqliteDb extends BaseDb implements StockDb { } return prop.value(value); } catch (SQLException e) { - throw databaseException(FAILED_TO_ADD_PROPERTY_TO_ITEM,itemId).causedBy(e); + throw databaseException(FAILED_TO_ADD_PROPERTY_TO_ITEM, OBJECT,itemId).causedBy(e); } } private HashMap transformItems(Map oldLocationIdsToNew) throws SQLException { var rs = select(ALL).from(TABLE_ITEMS).exec(db); - var insert = insertInto("items_temp",OWNER, OWNER_NUMBER, LOCATION_ID, CODE, NAME); + var insert = insertInto("items_temp", OWNER, OWNER_NUMBER, LOCATION_ID, Field.CODE, NAME); var oldToNew = new HashMap(); // maps from old item ids to new ones while (rs.next()){ var oldId = rs.getString(ID); var parts = oldId.split(":"); - if (parts.length != 3) throw databaseException(UNEXPECTED_ITEM_ID_FORMAT,oldId); + if (parts.length != 3) throw databaseException(UNEXPECTED_ITEM_ID_FORMAT,OBJECT,oldId); var owner = String.join(":",parts[0], parts[1]); long ownerNumber; try { ownerNumber = Long.parseLong(parts[2]); } catch (NumberFormatException e) { - throw databaseException(UNEXPECTED_ITEM_ID_FORMAT,oldId).causedBy(e); + throw databaseException(UNEXPECTED_ITEM_ID_FORMAT,OBJECT,oldId).causedBy(e); } var oldLocationId = rs.getString(LOCATION_ID); var locationId = oldLocationIdsToNew.get(oldLocationId); - if (locationId == null) throw databaseException(UNKNOWN_ITEM_LOCATION,oldId,parts[0],parts[1],oldLocationId); - var rs2 = insert.values(owner, ownerNumber, locationId, rs.getString(CODE), rs.getString(NAME)).execute(db).getGeneratedKeys(); + if (locationId == null) throw databaseException(UNKNOWN_ITEM_LOCATION, OBJECT,oldId, OWNER,parts[0]+" "+parts[1], Field.LOCATION,oldLocationId); + var rs2 = insert.values(owner, ownerNumber, locationId, rs.getString(Field.CODE), rs.getString(NAME)).execute(db).getGeneratedKeys(); oldToNew.put(oldId,rs2.getLong(1)); rs2.close(); } @@ -572,7 +581,7 @@ public class SqliteDb extends BaseDb implements StockDb { while (rs.next()){ var oldItemId = rs.getString(ITEM_ID); var itemId = oldItemIdsToNew.get(oldItemId); - if (itemId == null) throw databaseException(MISSING_NEW_ITEM_ID,oldItemId); + if (itemId == null) throw databaseException(MISSING_NEW_ITEM_ID, ID,oldItemId); insert.values(itemId, rs.getLong(PROPERTY_ID), rs.getString(VALUE)); } rs.close(); @@ -598,7 +607,7 @@ public class SqliteDb extends BaseDb implements StockDb { db.rollback(); } catch (SQLException ignored) { } - throw databaseException(FAILED_TO_UPDATE_TABLE,TABLE_LOCATIONS).causedBy(e); + throw databaseException(FAILED_TO_UPDATE_OBJECT, OBJECT, t(TABLE_WITH_NAME,NAME,TABLE_LOCATIONS)).causedBy(e); } } diff --git a/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java b/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java index 261441d3..4b46a2b6 100644 --- a/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java +++ b/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java @@ -4,13 +4,15 @@ package de.srsoftware.umbrella.stock; import static de.srsoftware.tools.Optionals.is0; import static de.srsoftware.tools.Optionals.nullIfEmpty; import static de.srsoftware.umbrella.core.ConnectionProvider.connect; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.Field.ITEM; import static de.srsoftware.umbrella.core.ModuleRegistry.companyService; import static de.srsoftware.umbrella.core.ModuleRegistry.userService; -import static de.srsoftware.umbrella.core.Paths.LIST; -import static de.srsoftware.umbrella.core.Paths.SEARCH; import static de.srsoftware.umbrella.core.Util.mapValues; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Field.ITEM; +import static de.srsoftware.umbrella.core.constants.Module.COMPANY; +import static de.srsoftware.umbrella.core.constants.Module.USER; +import static de.srsoftware.umbrella.core.constants.Path.*; +import static de.srsoftware.umbrella.core.constants.Path.PROPERTY; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; import static de.srsoftware.umbrella.stock.Constants.*; import static java.lang.System.Logger.Level.WARNING; @@ -19,12 +21,12 @@ import static java.util.Comparator.comparing; import com.sun.net.httpserver.HttpExchange; import de.srsoftware.configuration.Configuration; import de.srsoftware.configuration.JsonConfig; -import de.srsoftware.tools.Path; import de.srsoftware.tools.SessionToken; -import de.srsoftware.umbrella.core.BaseHandler; -import de.srsoftware.umbrella.core.ModuleRegistry; +import de.srsoftware.umbrella.core.*; import de.srsoftware.umbrella.core.api.Owner; import de.srsoftware.umbrella.core.api.StockService; +import de.srsoftware.umbrella.core.constants.Field; +import de.srsoftware.umbrella.core.constants.Path; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.core.model.*; import de.srsoftware.umbrella.core.model.Location; @@ -39,7 +41,7 @@ public class StockModule extends BaseHandler implements StockService { public StockModule(Configuration config) throws UmbrellaException { super(); - var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE)); + var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingField(CONFIG_DATABASE)); stockDb = new SqliteDb(connect(dbFile)); Optional itemDbConfig = config.get(CONFIG_ITEM_DB); itemDbConfig.map(ItemDb::new).ifPresent(itemDb -> itemDb.migrateTo(stockDb)); @@ -64,14 +66,14 @@ public class StockModule extends BaseHandler implements StockService { private boolean deleteLocation(UmbrellaUser user, Location locationRef, HttpExchange ex) throws IOException { var location = locationRef.resolve(); var owner = location.owner().resolve(); - if (!assigned(owner,user)) throw forbidden("You are not allowed to modify \"{0}\"",location); - if (!stockDb.listItemsAt(location).isEmpty()) throw forbidden("\"{0}\" cannot be deleted, as it contains items!",location); - if (!stockDb.listChildLocations(location.id()).isEmpty()) throw forbidden("\"{0}\" cannot be deleted, as it contains other locations!",location); + if (!assigned(owner,user)) throw forbidden("You are not allowed to modify \"{location}\"", Field.LOCATION,location); + if (!stockDb.listItemsAt(location).isEmpty()) throw forbidden("\"{location}\" cannot be deleted, as it contains items!", Field.LOCATION,location); + if (!stockDb.listChildLocations(location.id()).isEmpty()) throw forbidden("\"{location}\" cannot be deleted, as it contains other locations!", Field.LOCATION,location); return sendContent(ex,stockDb.delete(location)); } @Override - public boolean doDelete(Path path, HttpExchange ex) throws IOException { + public boolean doDelete(de.srsoftware.tools.Path path, HttpExchange ex) throws IOException { addCors(ex); try { Optional token = SessionToken.from(ex).map(Token::of); @@ -79,7 +81,7 @@ public class StockModule extends BaseHandler implements StockService { if (user.isEmpty()) return unauthorized(ex); var head = path.pop(); return switch (head) { - case LOCATION -> { + case Path.LOCATION -> { try { var location = Location.of(Long.parseLong(path.pop())); yield deleteLocation(user.get(), location, ex); @@ -95,7 +97,7 @@ public class StockModule extends BaseHandler implements StockService { } @Override - public boolean doGet(Path path, HttpExchange ex) throws IOException { + public boolean doGet(de.srsoftware.tools.Path path, HttpExchange ex) throws IOException { addCors(ex); try { Optional token = SessionToken.from(ex).map(Token::of); @@ -103,7 +105,7 @@ public class StockModule extends BaseHandler implements StockService { if (user.isEmpty()) return unauthorized(ex); var head = path.pop(); return switch (head) { - case COMPANY -> { + case Path.COMPANY -> { try { var company = companyService().get(Long.parseLong(path.pop())); yield getItem(user.get(),company,path,ex); @@ -111,7 +113,7 @@ public class StockModule extends BaseHandler implements StockService { yield super.doGet(path,ex); } } - case LOCATION -> { + case Path.LOCATION -> { try { var location = Location.of(Long.parseLong(path.pop())); yield getLocationEntities(location, ex); @@ -119,9 +121,9 @@ public class StockModule extends BaseHandler implements StockService { yield super.doGet(path,ex); } } - case LOCATIONS -> getLocations(path,user.get(),ex); - case PROPERTIES -> getProperties(ex); - case USER -> { + case Path.LOCATIONS -> getLocations(path,user.get(),ex); + case Path.PROPERTIES -> getProperties(ex); + case Path.USER -> { try { var userId = Long.parseLong(path.pop()); if (userId != user.get().id()) throw forbidden("You are not allowed to access items of another user!"); @@ -138,7 +140,7 @@ public class StockModule extends BaseHandler implements StockService { } @Override - public boolean doPatch(Path path, HttpExchange ex) throws IOException { + public boolean doPatch(de.srsoftware.tools.Path path, HttpExchange ex) throws IOException { addCors(ex); try { Optional token = SessionToken.from(ex).map(Token::of); @@ -146,7 +148,7 @@ public class StockModule extends BaseHandler implements StockService { if (user.isEmpty()) return unauthorized(ex); return switch (path.pop()){ case MOVE_ITEM -> patchMoveItem(user.get(), path,ex); - case LOCATION -> { + case Path.LOCATION -> { try { var id = Long.parseLong(path.pop()); yield patchLocation(id, user.get(), ex); @@ -164,7 +166,7 @@ public class StockModule extends BaseHandler implements StockService { } @Override - public boolean doPost(Path path, HttpExchange ex) throws IOException { + public boolean doPost(de.srsoftware.tools.Path path, HttpExchange ex) throws IOException { addCors(ex); try { Optional token = SessionToken.from(ex).map(Token::of); @@ -172,9 +174,9 @@ public class StockModule extends BaseHandler implements StockService { if (user.isEmpty()) return unauthorized(ex); var head = path.pop(); return switch (head) { - case ITEM -> postItem(user.get(), ex); + case Path.ITEM -> postItem(user.get(), ex); case LIST -> postItemList(user.get(), path, ex); - case LOCATION -> postLocation(user.get(),ex); + case Path.LOCATION -> postLocation(user.get(),ex); case PROPERTY -> postProperty(user.get(),ex); case SEARCH -> postSearch(user.get(),ex); case null, default -> super.doPost(path,ex); @@ -189,10 +191,10 @@ public class StockModule extends BaseHandler implements StockService { return sendContent(ex, stockDb.listChildLocations(parentId).stream().sorted(comparing(l -> l.name().toLowerCase())).map(DbLocation::toMap)); } - private boolean getItem(UmbrellaUser user, Owner owner, Path path, HttpExchange ex) throws IOException { - if (!assigned(owner,user)) throw forbidden("You are not allowed to access items of {0}",owner); + private boolean getItem(UmbrellaUser user, Owner owner, de.srsoftware.tools.Path path, HttpExchange ex) throws IOException { + if (!assigned(owner,user)) throw forbidden("You are not allowed to access items of {owner}", OWNER,owner); return switch (path.pop()){ - case ITEM -> { + case Path.ITEM -> { try { var itemId = Long.parseLong(path.pop()); var item = stockDb.loadItem(owner.dbCode(),itemId); @@ -211,13 +213,13 @@ public class StockModule extends BaseHandler implements StockService { List userIds = switch (owner.type()){ case COMPANY -> companyService().getMembers(owner.id()).stream().map(UmbrellaUser::id).toList(); case USER -> List.of(owner.id()); - case null, default -> throw unprocessable("Unprocessable owner type: {0}",owner.type()); + case null, default -> throw unprocessable("Unprocessable owner type: {type}", TYPE,owner.type()); }; var pathToLocation = stockDb.pathToLocation(location); - return sendContent(ex,Map.of(ITEMS,items,USERS,userIds,PATH,pathToLocation,LOCATION,location.resolve().toMap())); + return sendContent(ex,Map.of(ITEMS,items,USERS,userIds, PATH,pathToLocation, Field.LOCATION,location.resolve().toMap())); } - private boolean getLocations(Path path, UmbrellaUser user, HttpExchange ex) throws IOException { + private boolean getLocations(de.srsoftware.tools.Path path, UmbrellaUser user, HttpExchange ex) throws IOException { var head = path.pop(); return switch (head){ case BELOW -> { @@ -242,17 +244,17 @@ public class StockModule extends BaseHandler implements StockService { var result = new ArrayList(); var userLocations = stockDb.listUserLocations(user); result.add(Map.of( - PARENT, Map.of(USER, user.id()), + PARENT, Map.of(Field.USER, user.id()), NAME,user.name(), - LOCATIONS,userLocations.stream().map(DbLocation::toMap).toList())); + Field.LOCATIONS,userLocations.stream().map(DbLocation::toMap).toList())); var companies = companyService().listCompaniesOf(user); companies.values().stream().sorted(comparing(a -> a.name().toLowerCase())).forEach(company -> { var locations = stockDb.listCompanyLocations(company); result.add(Map.of( - PARENT, Map.of(COMPANY, company.id()), + PARENT, Map.of(Field.COMPANY, company.id()), NAME,company.name(), - LOCATIONS,locations.stream().sorted(comparing(a -> a.name().toLowerCase())).map(DbLocation::toMap).toList())); + Field.LOCATIONS,locations.stream().sorted(comparing(a -> a.name().toLowerCase())).map(DbLocation::toMap).toList())); }); return sendContent(ex, result); @@ -265,7 +267,7 @@ public class StockModule extends BaseHandler implements StockService { private boolean patchItem(UmbrellaUser user, HttpExchange ex) throws IOException { var json = json(ex); - if (!(json.get(ID) instanceof Number id)) throw missingFieldException(ID); + if (!(json.get(ID) instanceof Number id)) throw missingField(ID); json.remove(ID); var item = stockDb.loadItem(id.longValue()); @@ -273,20 +275,20 @@ public class StockModule extends BaseHandler implements StockService { return sendContent(ex,stockDb.save(item)); } - private boolean patchMoveItem(UmbrellaUser user, Path path, HttpExchange ex) throws IOException { + private boolean patchMoveItem(UmbrellaUser user, de.srsoftware.tools.Path path, HttpExchange ex) throws IOException { var json = json(ex); - if (!(json.get(ITEM) instanceof Number itemId)) throw missingFieldException(ITEM); - if (!(json.get(TARGET) instanceof Number locationId)) throw missingFieldException(TARGET); + if (!(json.get(ITEM) instanceof Number itemId)) throw missingField(ITEM); + if (!(json.get(TARGET) instanceof Number locationId)) throw missingField(TARGET); var item = stockDb.loadItem(itemId.longValue()); var itemOwner = item.owner().resolve(); - if (!assigned(itemOwner,user)) throw forbidden("You are not allowed to alter the location of \"{0}\"!",item.name()); + if (!assigned(itemOwner,user)) throw forbidden("You are not allowed to alter the location of \"{name}\"!", NAME,item.name()); var target = stockDb.loadLocation(locationId.longValue()); var locOwner = target.resolve().owner().resolve(); - if (!assigned(locOwner,user)) throw forbidden("You are not allowed to modify \"{0}\"!",target.name()); + if (!assigned(locOwner,user)) throw forbidden("You are not allowed to modify \"{name}\"!", NAME,target.name()); - if (!locOwner.equals(itemOwner)) throw unprocessable("You may not move items from one owner ({0}) to another ({1})",itemOwner,locOwner); + if (!locOwner.equals(itemOwner)) throw unprocessable("You may not move items from one owner ({owner}) to another ({object})", OWNER,itemOwner, OBJECT,locOwner); stockDb.save(item.location(target)); return sendContent(ex,item); @@ -296,7 +298,7 @@ public class StockModule extends BaseHandler implements StockService { var json = json(ex); var location = stockDb.loadLocation(locationId); var owner = location.owner().resolve(); - if (!assigned(owner,user)) throw forbidden("You are not allowed to edit \"{0}\"!",location.name()); + if (!assigned(owner,user)) throw forbidden("You are not allowed to edit \"{location}\"!", Field.LOCATION,location.name()); if (json.has(PARENT_LOCATION_ID) && json.get(PARENT_LOCATION_ID) instanceof Number parentId){ if (parentId.longValue() != 0L) { @@ -308,8 +310,8 @@ public class StockModule extends BaseHandler implements StockService { current = is0(current.parent()) ? null : stockDb.loadLocation(current.parent()); } var targetOwner = target.owner().resolve(); - if (!assigned(targetOwner, user)) throw forbidden("You are not allowed to edit \"{0}\"!", target.name()); - if (!targetOwner.equals(owner)) throw unprocessable("You may not move locations from one owner ({0}) to another ({1})", owner, targetOwner); + if (!assigned(targetOwner, user)) throw forbidden("You are not allowed to edit \"{name}\"!", NAME, target.name()); + if (!targetOwner.equals(owner)) throw unprocessable("You may not move locations from one owner ({a}) to another ({b})","a", owner,"b", targetOwner); LOG.log(WARNING,"Not checking, if location is moved to on of its own children!"); } } @@ -320,22 +322,22 @@ public class StockModule extends BaseHandler implements StockService { private boolean postItem(UmbrellaUser user, HttpExchange ex) throws IOException { var json = json(ex); - if (!json.has(NAME) || !(json.get(NAME) instanceof String name)) throw missingFieldException(NAME); + if (!json.has(NAME) || !(json.get(NAME) instanceof String name)) throw missingField(NAME); var description = json.has(DESCRIPTION) && json.get(DESCRIPTION) instanceof String d ? d : null; - if (!json.has(CODE) || !(json.get(CODE) instanceof String code)) throw missingFieldException(CODE); - if (!json.has(LOCATION) || !(json.get(LOCATION) instanceof JSONObject locationData)) throw missingFieldException(LOCATION); + if (!json.has(Field.CODE) || !(json.get(Field.CODE) instanceof String code)) throw missingField(Field.CODE); + if (!json.has(Field.LOCATION) || !(json.get(Field.LOCATION) instanceof JSONObject locationData)) throw missingField(Field.LOCATION); var location = stockDb.loadLocation(locationData.getLong(ID)); var owner = location.owner().resolve(); - if (!assigned(owner,user)) throw forbidden("You are not allowed to add items to {0}!",location); + if (!assigned(owner,user)) throw forbidden("You are not allowed to add items to {location}!", Field.LOCATION,location); var newItem = new Item(0,owner,0,location,code,name,description); return sendContent(ex,stockDb.save(newItem)); } - private boolean postItemList(UmbrellaUser user, Path path, HttpExchange ex) throws IOException { + private boolean postItemList(UmbrellaUser user, de.srsoftware.tools.Path path, HttpExchange ex) throws IOException { var json = json(ex); - if (!json.has(COMPANY_ID) || !(json.get(COMPANY_ID) instanceof Number company_id)) throw missingFieldException(COMPANY_ID); + if (!json.has(COMPANY_ID) || !(json.get(COMPANY_ID) instanceof Number company_id)) throw missingField(COMPANY_ID); var company = companyService().get(company_id.longValue()); - if (!companyService().membership(company_id.longValue(),user.id())) throw forbidden("You are not a member of {0}!", company.name()); + if (!companyService().membership(company_id.longValue(),user.id())) throw notAmember(company.name()); var map = new HashMap(); var items = stockDb.listItemsOf(company) .stream() @@ -346,10 +348,10 @@ public class StockModule extends BaseHandler implements StockService { private boolean postLocation(UmbrellaUser user, HttpExchange ex) throws IOException { var json = json(ex); - if (!(json.get(NAME) instanceof String name)) throw missingFieldException(NAME); - if (!(json.get(PARENT) instanceof JSONObject parentData)) throw missingFieldException(PARENT); - var key = parentData.keySet().stream().findFirst().orElseThrow(() -> missingFieldException(PARENT)); - if (!(parentData.get(key) instanceof Number id)) throw missingFieldException(key); + if (!(json.get(NAME) instanceof String name)) throw missingField(NAME); + if (!(json.get(PARENT) instanceof JSONObject parentData)) throw missingField(PARENT); + var key = parentData.keySet().stream().findFirst().orElseThrow(() -> missingField(PARENT)); + if (!(parentData.get(key) instanceof Number id)) throw missingField(key); Location parent; Owner owner; switch (key){ @@ -361,11 +363,11 @@ public class StockModule extends BaseHandler implements StockService { owner = userService().loadUser(id.longValue()); parent = null; break; - case LOCATION: + case Path.LOCATION: parent = stockDb.loadLocation(id.longValue()); owner = parent.resolve().owner().resolve(); break; - default: throw unprocessable("Unknown parent object: {0} → {1}",key,id); + default: throw unprocessable("Unknown parent object: {key} → {id}", KEY,key, ID,id); }; var loc = new DbLocation(0,owner,parent == null?null:parent.id(),name,null); return sendContent(ex,stockDb.save(loc)); @@ -373,12 +375,12 @@ public class StockModule extends BaseHandler implements StockService { private boolean postProperty(UmbrellaUser user, HttpExchange ex) throws IOException { var json = json(ex); - if (!(json.get(ITEM) instanceof JSONObject itemData)) throw missingFieldException(ITEM); - if (!(itemData.get(ID) instanceof Number itemId)) throw missingFieldException(ID); - if (!(json.get("add_prop") instanceof JSONObject propData)) throw missingFieldException("add_prop"); - if (!propData.has(VALUE)) throw missingFieldException(VALUE); + if (!(json.get(ITEM) instanceof JSONObject itemData)) throw missingField(ITEM); + if (!(itemData.get(ID) instanceof Number itemId)) throw missingField(ID); + if (!(json.get("add_prop") instanceof JSONObject propData)) throw missingField("add_prop"); + if (!propData.has(VALUE)) throw missingField(VALUE); var value = propData.get(VALUE); - if (value == null) throw missingFieldException(VALUE); + if (value == null) throw missingField(VALUE); Property property = null; if (propData.get("existing_prop_id") instanceof Number existingPropId && existingPropId.longValue() != 0L){ @@ -394,7 +396,7 @@ public class StockModule extends BaseHandler implements StockService { private boolean postSearch(UmbrellaUser user, HttpExchange ex) throws IOException { var json = json(ex); - if (!(json.has(KEY) && json.get(KEY) instanceof String key)) throw missingFieldException(KEY); + if (!(json.has(KEY) && json.get(KEY) instanceof String key)) throw missingField(KEY); var keys = Arrays.asList(key.split(" ")); var fulltext = json.has(FULLTEXT) && json.get(FULLTEXT) instanceof Boolean val && val; Set owners = new HashSet<>(companyService().listCompaniesOf(user).values()); diff --git a/tags/src/main/java/de/srsoftware/umbrella/tags/SqliteDb.java b/tags/src/main/java/de/srsoftware/umbrella/tags/SqliteDb.java index 9fbf67b7..48f8163a 100644 --- a/tags/src/main/java/de/srsoftware/umbrella/tags/SqliteDb.java +++ b/tags/src/main/java/de/srsoftware/umbrella/tags/SqliteDb.java @@ -8,10 +8,14 @@ import static de.srsoftware.tools.jdbc.Query.*; import static de.srsoftware.tools.jdbc.Query.Dialect.SQLITE; import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL; import static de.srsoftware.umbrella.bookmarks.Constants.*; -import static de.srsoftware.umbrella.core.Constants.*; -import static de.srsoftware.umbrella.core.Constants.USER_ID; import static de.srsoftware.umbrella.core.Errors.*; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseException; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Field.TAGS; +import static de.srsoftware.umbrella.core.constants.Module.BOOKMARK; +import static de.srsoftware.umbrella.core.constants.Text.TABLE_WITH_NAME; +import static de.srsoftware.umbrella.core.constants.Text.USER_WITH_ID; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; +import static de.srsoftware.umbrella.core.model.Translatable.t; import static de.srsoftware.umbrella.tags.Constants.*; import static java.lang.System.Logger.Level.*; import static java.text.MessageFormat.format; @@ -21,6 +25,8 @@ import de.srsoftware.tools.Tuple; import de.srsoftware.tools.jdbc.Query; import de.srsoftware.umbrella.bookmarks.BookmarkDb; import de.srsoftware.umbrella.core.BaseDb; +import de.srsoftware.umbrella.core.constants.Text; +import de.srsoftware.umbrella.core.model.Translatable; import java.sql.Connection; import java.sql.SQLException; import java.time.LocalDateTime; @@ -33,7 +39,6 @@ public class SqliteDb extends BaseDb implements TagDB{ public SqliteDb(Connection tagDb, Connection bmDb) { super(tagDb); bookmarks = new de.srsoftware.umbrella.bookmarks.SqliteDb(bmDb); - createTables(); } @Override @@ -61,14 +66,14 @@ public class SqliteDb extends BaseDb implements TagDB{ var pattern = Pattern.compile("/([^/]+)/(\\d+)/view"); try { LocalDateTime earliestDate = LocalDateTime.of(2000,1,1,0,0); - var rs = select(ALL).from(TABLE_URLS).leftJoin(HASH,TABLE_URL_COMMENTS,URL_HASH).leftJoin(COMMENT_HASH,TABLE_COMMENTS,HASH).where(TIMESTAMP,moreThan(0)).limit(1).exec(db); + var rs = select(ALL).from(TABLE_URLS).leftJoin(HASH,TABLE_URL_COMMENTS,URL_HASH).leftJoin(COMMENT_HASH,TABLE_COMMENTS, HASH).where(TIMESTAMP,moreThan(0)).limit(1).exec(db); if (rs.next()) earliestDate = LocalDateTime.ofEpochSecond(rs.getLong(1),0,UTC); rs.close(); var sql = "CREATE TABLE IF NOT EXISTS tags_new (TAG)"; db.prepareStatement(sql).execute(); // IMPORT BOOKMARKS - var commentedURLS = select(ALL).from(TABLE_URLS).leftJoin(HASH,TABLE_URL_COMMENTS,URL_HASH).leftJoin(COMMENT_HASH,TABLE_COMMENTS,HASH).exec(db); + var commentedURLS = select(ALL).from(TABLE_URLS).leftJoin(HASH,TABLE_URL_COMMENTS,URL_HASH).leftJoin(COMMENT_HASH,TABLE_COMMENTS, HASH).exec(db); while (commentedURLS.next()){ var userId = commentedURLS.getLong(USER_ID); @@ -92,10 +97,10 @@ public class SqliteDb extends BaseDb implements TagDB{ } var urlTags = select(ALL).from(TABLE_TAGS).where(URL_HASH,equal(urlHash)).where(USER_ID,equal(userId)).exec(db); - var insertQuery = insertInto(TABLE_TAGS_NEW,TAG,MODULE,ENTITY_ID,USER_ID).ignoreDuplicates(SQLITE); + var insertQuery = insertInto(TABLE_TAGS_NEW,TAG, MODULE, ENTITY_ID, USER_ID).ignoreDuplicates(SQLITE); while (urlTags.next()){ var tag = urlTags.getString(TAG); - insertQuery.values(tag,BOOKMARK,bm.urlId(),userId); + insertQuery.values(tag, BOOKMARK,bm.urlId(),userId); if (module != null && entityId != 0) insertQuery.values(tag,module,entityId,userId); } insertQuery.execute(db).close(); @@ -103,7 +108,7 @@ public class SqliteDb extends BaseDb implements TagDB{ } commentedURLS.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_UPDATE_TABLE,TABLE_URLS).causedBy(e); + throw databaseException(FAILED_TO_UPDATE_OBJECT, OBJECT, Translatable.t(TABLE_WITH_NAME,NAME,TABLE_URLS)).causedBy(e); } } @@ -114,7 +119,7 @@ public class SqliteDb extends BaseDb implements TagDB{ stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,"Comments (legacy)").causedBy(e); + throw failedToCreateTable("Comments (legacy)").causedBy(e); } } @@ -125,7 +130,7 @@ public class SqliteDb extends BaseDb implements TagDB{ stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,"Tags (legacy)").causedBy(e); + throw failedToCreateTable("Tags (legacy)").causedBy(e); } } @@ -136,7 +141,7 @@ public class SqliteDb extends BaseDb implements TagDB{ stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,"URLs (legacy)").causedBy(e); + throw failedToCreateTable("URLs (legacy)").causedBy(e); } } @@ -147,7 +152,7 @@ public class SqliteDb extends BaseDb implements TagDB{ stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,"URL_comments (legacy)").causedBy(e); + throw failedToCreateTable("URL_comments (legacy)").causedBy(e); } } @@ -166,7 +171,7 @@ CREATE TABLE IF NOT EXISTS {0} ( stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_TAGS_NEW).causedBy(e); + throw failedToCreateTable(TABLE_TAGS_NEW).causedBy(e); } } @@ -179,7 +184,7 @@ CREATE TABLE IF NOT EXISTS {0} ( stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_DROP_ENTITY,table).causedBy(e); + throw failedToDropObject(table).causedBy(e); } } @@ -190,7 +195,7 @@ CREATE TABLE IF NOT EXISTS {0} ( stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_TAGS).causedBy(e); + throw failedToCreateTable(TABLE_TAGS).causedBy(e); } } @@ -206,7 +211,7 @@ CREATE TABLE IF NOT EXISTS {0} ( .execute(db); return tag; } catch (SQLException e){ - throw databaseException(FAILED_TO_DROP_ENTITY,tag); + throw failedToDropObject(tag); } } @@ -217,7 +222,7 @@ CREATE TABLE IF NOT EXISTS {0} ( .where(MODULE,iEqual(module)).where(ENTITY_ID,equal(entityId)) .execute(db); } catch (SQLException e){ - throw databaseException(FAILED_TO_DROP_ENTITY_OF_ENTITY,entityId,module).causedBy(e); + throw failedToDropObject(Translatable.t("{module}.{id}", MODULE,module, ID,entityId)).causedBy(e); } } @@ -241,7 +246,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return result; } catch (SQLException e){ - throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER,"uses",tag).causedBy(e); + throw failedToDropObject(Translatable.t("uses of {tag}",TAG,tag)).causedBy(e); } } @@ -261,7 +266,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return tags; } catch (SQLException e) { - throw databaseException(FAILED_TO_LIST_ENTITIES,"tags").causedBy(e); + throw databaseException(FAILED_TO_LIST_ENTITIES, TYPE,TAGS).causedBy(e); } } @@ -279,7 +284,8 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return list; } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER,"tags",userId).causedBy(e); + + throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER, TYPE,t(Text.TAGS), OWNER, Translatable.t(USER_WITH_ID, ID,userId)).causedBy(e); } } @@ -299,14 +305,14 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return tags; } catch (SQLException e) { - throw databaseException(FAILED_TO_LIST_ENTITIES,"tags").causedBy(e); + throw databaseException(FAILED_TO_LIST_ENTITIES, TYPE,t(Text.TAGS)).causedBy(e); } } @Override public void save(Collection userIds, String module, long entityId, Collection tags) { try { - var query = replaceInto(TABLE_TAGS,USER_ID,MODULE,ENTITY_ID,TAG); + var query = replaceInto(TABLE_TAGS, USER_ID, MODULE, ENTITY_ID,TAG); for (var tag : tags) { if (userIds == null) { // tags not assigned to a user are available to all users query.values(null, module, entityId, tag); @@ -316,7 +322,7 @@ CREATE TABLE IF NOT EXISTS {0} ( } query.execute(db).close(); } catch (SQLException e){ - throw databaseException(FAILED_TO_STORE_ENTITY,String.join(", ",tags)).causedBy(e); + throw failedToStoreObject(String.join(", ",tags)).causedBy(e); } } @@ -326,7 +332,7 @@ CREATE TABLE IF NOT EXISTS {0} ( update(TABLE_TAGS).set(ENTITY_ID).where(MODULE,iEqual(module)).where(ENTITY_ID,equal(oldId)).prepare(db).apply(newId).close(); LOG.log(DEBUG,"Updated tag @ {0}.{1} → {0}.{2}",module,oldId,newId); } catch (SQLException e) { - throw databaseException(FAILED_TO_UPDATE_ENTITY,format("{0}.{1} → {0}.{2}",module,oldId,newId)).causedBy(e); + throw databaseException(FAILED_TO_UPDATE_OBJECT,format("{0}.{1} → {0}.{2}",module,oldId,newId)).causedBy(e); } } } diff --git a/tags/src/main/java/de/srsoftware/umbrella/tags/TagModule.java b/tags/src/main/java/de/srsoftware/umbrella/tags/TagModule.java index c8e3ddae..dab9e5ce 100644 --- a/tags/src/main/java/de/srsoftware/umbrella/tags/TagModule.java +++ b/tags/src/main/java/de/srsoftware/umbrella/tags/TagModule.java @@ -2,11 +2,11 @@ package de.srsoftware.umbrella.tags; import static de.srsoftware.umbrella.core.ConnectionProvider.connect; -import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.ModuleRegistry.userService; import static de.srsoftware.umbrella.core.ResponseCode.HTTP_UNPROCESSABLE; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.unprocessable; +import static de.srsoftware.umbrella.core.constants.Field.USER_LIST; +import static de.srsoftware.umbrella.core.constants.Path.USES; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; import static de.srsoftware.umbrella.tags.Constants.*; import com.sun.net.httpserver.HttpExchange; @@ -28,8 +28,8 @@ public class TagModule extends BaseHandler implements TagService { public TagModule(Configuration config) { super(); - var tagDbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE)); - var bmDbFile = config.get(de.srsoftware.umbrella.bookmarks.Constants.CONFIG_DATABASE).orElseThrow(() -> missingFieldException(de.srsoftware.umbrella.bookmarks.Constants.CONFIG_DATABASE)); + var tagDbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingField(CONFIG_DATABASE)); + var bmDbFile = config.get(de.srsoftware.umbrella.bookmarks.Constants.CONFIG_DATABASE).orElseThrow(() -> missingField(de.srsoftware.umbrella.bookmarks.Constants.CONFIG_DATABASE)); tagDb = new SqliteDb(connect(tagDbFile),connect(bmDbFile)); ModuleRegistry.add(this); } @@ -90,9 +90,9 @@ public class TagModule extends BaseHandler implements TagService { var head = path.pop(); long entityId = Long.parseLong(head); var json = json(ex); - if (!(json.has(TAG) && json.get(TAG) instanceof String tag && !tag.isBlank())) throw missingFieldException(TAG); + if (!(json.has(TAG) && json.get(TAG) instanceof String tag && !tag.isBlank())) throw missingField(TAG); List userList = null; - if (!json.has(USER_LIST)) throw missingFieldException(USER_LIST); + if (!json.has(USER_LIST)) throw missingField(USER_LIST); var ul = json.isNull(USER_LIST) ? null : json.get(USER_LIST); if (ul instanceof JSONArray arr){ userList = arr.toList().stream() diff --git a/task/src/main/java/de/srsoftware/umbrella/task/SqliteDb.java b/task/src/main/java/de/srsoftware/umbrella/task/SqliteDb.java index 779329b7..b068c832 100644 --- a/task/src/main/java/de/srsoftware/umbrella/task/SqliteDb.java +++ b/task/src/main/java/de/srsoftware/umbrella/task/SqliteDb.java @@ -5,17 +5,23 @@ package de.srsoftware.umbrella.task; import static de.srsoftware.tools.jdbc.Condition.*; import static de.srsoftware.tools.jdbc.Query.*; import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL; -import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.Errors.*; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseException; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.notFound; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Field.TASK; +import static de.srsoftware.umbrella.core.constants.Field.TYPE; +import static de.srsoftware.umbrella.core.constants.Text.*; +import static de.srsoftware.umbrella.core.constants.Text.TASKS; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.failedToCreateTable; import static de.srsoftware.umbrella.core.model.Status.*; +import static de.srsoftware.umbrella.core.model.Translatable.t; import static de.srsoftware.umbrella.project.Constants.*; import static de.srsoftware.umbrella.task.Constants.*; import static java.text.MessageFormat.format; import de.srsoftware.tools.jdbc.Query; import de.srsoftware.umbrella.core.BaseDb; +import de.srsoftware.umbrella.core.constants.Text; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.core.model.*; import java.sql.Connection; @@ -55,16 +61,16 @@ public class SqliteDb extends BaseDb implements TaskDb { stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_TASK_DEPENDENCIES).causedBy(e); + throw failedToCreateTable(TABLE_TASK_DEPENDENCIES).causedBy(e); } } private void createPriorityColumn() { - var sql = format("ALTER TABLE {0} ADD {1} INT NOT NULL DEFAULT 0",TABLE_TASKS,PRIORITY); + var sql = format("ALTER TABLE {0} ADD {1} INT NOT NULL DEFAULT 0",TABLE_TASKS, PRIORITY); try { db.prepareStatement(sql).execute(); } catch (SQLException e) { - throw databaseException(FAILED_TO_ADD_COLUMN,PRIORITY,TABLE_TASKS).causedBy(e); + throw databaseException(FAILED_TO_ADD_COLUMN, NAME, PRIORITY, TABLE,TABLE_TASKS).causedBy(e); } } @@ -88,7 +94,7 @@ public class SqliteDb extends BaseDb implements TaskDb { stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_PROJECTS).causedBy(e); + throw failedToCreateTable(TABLE_PROJECTS).causedBy(e); } } @@ -105,7 +111,7 @@ CREATE TABLE IF NOT EXISTS {0} ( stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_PROJECT_USERS).causedBy(e); + throw failedToCreateTable(TABLE_PROJECT_USERS).causedBy(e); } } @@ -116,23 +122,23 @@ CREATE TABLE IF NOT EXISTS {0} ( long count = 0; if (rs.next()) count = rs.getLong(1); rs.close(); - if (count>0) throw new UmbrellaException("Task \"{0}\" has child tasks and thus cannot be deleted!",task.name()); + if (count>0) throw unprocessable("Task \"{task}\" has child tasks and thus cannot be deleted!", TASK,task.name()); Query.delete().from(TABLE_TASKS).where(ID,equal(task.id())).execute(db); Query.delete().from(TABLE_TASKS_USERS).where(TASK_ID,equal(task.id())).execute(db); } catch (SQLException e) { - throw databaseException(FAILED_TO_DROP_ENTITY,"task").causedBy(e); + throw failedToDropObject(task).causedBy(e); } } @Override - public void dropMember(long projectId, long userId) { + public void dropMember(long taskId, long userId) { try { Query.delete().from(TABLE_TASKS_USERS) - .where(TASK_ID,equal(projectId)) + .where(TASK_ID,equal(taskId)) .where(USER_ID,equal(userId)) .execute(db); } catch (SQLException e) { - throw databaseException(FAILED_TO_DROP_ENTITY_OF_ENTITY,USER_ID,userId,PROJECT,projectId).causedBy(e); + throw failedToDropObjectFromObject(USER_ID,userId,t(Text.TASK),taskId).causedBy(e); } } @@ -143,7 +149,7 @@ CREATE TABLE IF NOT EXISTS {0} ( var query = select(ALL).from(TABLE_TASKS).leftJoin(ID,TABLE_TASKS_USERS,TASK_ID) .where(USER_ID,equal(userId)); if (fulltext) { - for (var key : keys) query.where(format("CONCAT({0},\" \",{1})",NAME,DESCRIPTION),like("%"+key+"%")); + for (var key : keys) query.where(format("CONCAT({0},\" \",{1})", NAME, DESCRIPTION),like("%"+key+"%")); } else { for (var key : keys) query.where(NAME,like("%"+key+"%")); } @@ -155,7 +161,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return tasks; } catch (SQLException e){ - throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER,TASKS,USER).causedBy(e); + throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER, TYPE,t(TASKS), OWNER,t(Text.USER)).causedBy(e); } } @@ -168,7 +174,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return result; } catch (SQLException e){ - throw databaseException(FAILED_TO_LIST_ENTITIES,"task members").causedBy(e); + throw failedToLoadObject("task members").causedBy(e); } } @@ -183,7 +189,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return loadDependencies(tasks); } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER,TASKS,"project_ids").causedBy(e); + throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER, TYPE,t(TASKS), OWNER,"project_ids").causedBy(e); } } @@ -203,7 +209,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return loadDependencies(tasks); } catch (SQLException e){ - throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER,TASKS,"project "+projectId).causedBy(e); + throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER, TYPE,t(TASKS), OWNER, t(PROJECT_WITH_ID, ID,projectId)).causedBy(e); } } @@ -222,7 +228,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return loadDependencies(tasks); } catch (SQLException e){ - throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER,"child tasks",parentTaskId).causedBy(e); + throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER, TYPE,"child tasks", OWNER,parentTaskId).causedBy(e); } } @@ -241,7 +247,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return loadDependencies(tasks); } catch (SQLException e){ - throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER,"project "+projectId).causedBy(e); + throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER, TYPE,t(TASKS), OWNER, t(PROJECT_WITH_ID, ID,projectId)).causedBy(e); } } @@ -256,7 +262,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return map; } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER,"user "+userId).causedBy(e); + throw databaseException(FAILED_TO_LOAD_ENTITIES_OF_OWNER, TYPE,t(TASKS), OWNER, t(USER_WITH_ID, ID,userId)).causedBy(e); } } @@ -264,7 +270,7 @@ CREATE TABLE IF NOT EXISTS {0} ( public Task load(long taskId) throws UmbrellaException { var map = load(List.of(taskId)); var task = map.get(taskId); - if (task == null) throw notFound(FAILED_TO_LOAD_ENTITY_BY_ID,TASK,taskId); + if (task == null) throw notFound(FAILED_TO_LOAD_OBJECT_BY_ID, OBJECT,t(Text.TASK), ID,taskId); return task; } @@ -280,7 +286,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return loadDependencies(map); } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_ENTITY,TASK).causedBy(e); + throw failedToLoadObject(t(TASKS)).causedBy(e); } } @@ -295,7 +301,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return tasks; } catch (SQLException e) { - throw databaseException(FAILED_TO_LOAD_ENTITY,"task dependencies").causedBy(e); + throw failedToLoadObject("task dependencies").causedBy(e); } } @@ -303,18 +309,18 @@ CREATE TABLE IF NOT EXISTS {0} ( public Task save(Task task) { try { if (task.id() == 0){ // new task - var rs = insertInto(TABLE_TASKS,PROJECT_ID,PARENT_TASK_ID,NAME,DESCRIPTION,STATUS,EST_TIME,START_DATE,DUE_DATE,SHOW_CLOSED,NO_INDEX,PRIORITY) + var rs = insertInto(TABLE_TASKS, PROJECT_ID, PARENT_TASK_ID, NAME, DESCRIPTION, STATUS, EST_TIME, START_DATE, DUE_DATE, SHOW_CLOSED, NO_INDEX, PRIORITY) .values(task.projectId(),task.parentTaskId(),task.name(),task.description(),task.status(),task.estimatedTime(),task.start(),task.dueDate(),task.showClosed(),task.noIndex(),task.priority()) .execute(db) .getGeneratedKeys(); Long taskId = null; if (rs.next()) taskId=rs.getLong(1); rs.close(); - if (taskId == null) throw new UmbrellaException("Failed to save task {0}",task.name()); + if (taskId == null) throw failedToStoreObject(task.name()); return new Task(taskId,task.projectId(),task.parentTaskId(),task.name(),task.description(),task.status(),task.estimatedTime(),task.start(),task.dueDate(),task.showClosed(),task.noIndex(),task.members(), task.priority()); } if (task.isDirty(MEMBERS)){ - var query = replaceInto(TABLE_TASKS_USERS,TASK_ID,USER_ID,PERMISSIONS); + var query = replaceInto(TABLE_TASKS_USERS,TASK_ID, USER_ID,PERMISSIONS); for (var member : task.members().entrySet()) query.values(task.id(),member.getKey(),member.getValue().permission().code()); query.execute(db).close(); task.clean(MEMBERS); @@ -336,7 +342,7 @@ CREATE TABLE IF NOT EXISTS {0} ( task.clean(REQUIRED_TASKS_IDS); } if (task.isDirty()) { - update(TABLE_TASKS).set(PROJECT_ID,PARENT_TASK_ID,NAME,DESCRIPTION,STATUS,EST_TIME,START_DATE,DUE_DATE,SHOW_CLOSED,NO_INDEX,PRIORITY) + update(TABLE_TASKS).set(PROJECT_ID, PARENT_TASK_ID, NAME, DESCRIPTION, STATUS, EST_TIME, START_DATE, DUE_DATE, SHOW_CLOSED, NO_INDEX, PRIORITY) .where(ID,equal(task.id())).prepare(db) .apply(task.projectId(),task.parentTaskId(),task.name(),task.description(),task.status(),task.estimatedTime(),task.start(),task.dueDate(),task.showClosed(),task.noIndex(),task.priority()) .close(); @@ -344,16 +350,16 @@ CREATE TABLE IF NOT EXISTS {0} ( } return task; } catch (SQLException e){ - throw databaseException(FAILED_TO_STORE_ENTITY,task.name()).causedBy(e); + throw failedToStoreObject(task.name()).causedBy(e); } } @Override public void setMember(long taskId, long userId, Permission permission) { try { - replaceInto(TABLE_TASKS_USERS,TASK_ID,USER_ID,PERMISSIONS).values(taskId,userId,permission.code()).execute(db).close(); + replaceInto(TABLE_TASKS_USERS,TASK_ID, USER_ID,PERMISSIONS).values(taskId,userId,permission.code()).execute(db).close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_STORE_ENTITY,PERMISSIONS).causedBy(e); + throw failedToStoreObject(PERMISSIONS).causedBy(e); } } } diff --git a/task/src/main/java/de/srsoftware/umbrella/task/TaskModule.java b/task/src/main/java/de/srsoftware/umbrella/task/TaskModule.java index de70beef..5a619e8e 100644 --- a/task/src/main/java/de/srsoftware/umbrella/task/TaskModule.java +++ b/task/src/main/java/de/srsoftware/umbrella/task/TaskModule.java @@ -3,14 +3,19 @@ package de.srsoftware.umbrella.task; import static de.srsoftware.tools.Optionals.*; import static de.srsoftware.umbrella.core.ConnectionProvider.connect; -import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.ModuleRegistry.*; -import static de.srsoftware.umbrella.core.Paths.*; import static de.srsoftware.umbrella.core.ResponseCode.HTTP_NOT_IMPLEMENTED; import static de.srsoftware.umbrella.core.Util.mapValues; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Field.TAGS; +import static de.srsoftware.umbrella.core.constants.Field.TASKS; +import static de.srsoftware.umbrella.core.constants.Module.TASK; +import static de.srsoftware.umbrella.core.constants.Path.*; +import static de.srsoftware.umbrella.core.constants.Text.LONG; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; import static de.srsoftware.umbrella.core.model.Permission.*; import static de.srsoftware.umbrella.core.model.Permission.OWNER; +import static de.srsoftware.umbrella.core.model.Translatable.t; import static de.srsoftware.umbrella.messagebus.MessageBus.messageBus; import static de.srsoftware.umbrella.messagebus.events.Event.EventType.CREATE; import static de.srsoftware.umbrella.messagebus.events.Event.EventType.UPDATE; @@ -27,6 +32,7 @@ import de.srsoftware.tools.SessionToken; import de.srsoftware.umbrella.core.BaseHandler; import de.srsoftware.umbrella.core.ModuleRegistry; import de.srsoftware.umbrella.core.api.*; +import de.srsoftware.umbrella.core.constants.Text; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.core.model.*; import de.srsoftware.umbrella.core.model.Task; @@ -62,7 +68,7 @@ public class TaskModule extends BaseHandler implements TaskService { public TaskModule(Configuration config) throws UmbrellaException { super(); - var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE)); + var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingField(CONFIG_DATABASE)); taskDb = new SqliteDb(connect(dbFile)); ModuleRegistry.add(this); } @@ -77,7 +83,7 @@ public class TaskModule extends BaseHandler implements TaskService { private boolean deleteTask(HttpExchange ex, long taskId, UmbrellaUser user) throws IOException { var task = loadMembers(taskDb.load(taskId)); var member = task.members().get(user.id()); - if (member == null || !member.mayWrite()) throw forbidden("You are not allowed to delete {0}", task.name()); + if (member == null || !member.mayWrite()) throw forbidden("You are not allowed to delete {object}", OBJECT, task.name()); taskDb.delete(task); noteService().deleteEntity(TASK, "" + taskId); tagService().deleteEntity(TASK, taskId); @@ -170,17 +176,17 @@ public class TaskModule extends BaseHandler implements TaskService { } private void dropMember(Task task, long userId) { - if (task.members().get(userId).permission() == OWNER) throw forbidden("You may not remove the owner of the task"); + if (task.members().get(userId).permission() == OWNER) throw forbidden("You may not remove the owner of {object}", OBJECT,task.name()); taskDb.dropMember(task.id(), userId); task.members().remove(userId); } private boolean estimatedTimes(UmbrellaUser user, HttpExchange ex) throws IOException, UmbrellaException { var json = json(ex); - if (!(json.has(COMPANY_ID) && json.get(COMPANY_ID) instanceof Number cid)) throw missingFieldException(COMPANY_ID); + if (!(json.has(COMPANY_ID) && json.get(COMPANY_ID) instanceof Number cid)) throw missingField(COMPANY_ID); var companyId = cid.longValue(); var company = companyService().get(companyId); - if (!companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name()); + if (!companyService().membership(companyId,user.id())) throw notAmember(company.name()); var projectMap = projectService().listCompanyProjects(companyId, false); var taskMap = taskDb.listTasks(projectMap.keySet()); var taskTree = new HashMap>(); @@ -218,7 +224,7 @@ public class TaskModule extends BaseHandler implements TaskService { private boolean getTask(HttpExchange ex, long taskId, UmbrellaUser user) throws IOException { var task = loadMembers(taskDb.load(taskId)); - if (!task.hasMember(user)) throw forbidden("You are not a member of {0}",task.name()); + if (!task.hasMember(user)) throw notAmember(task.name()); return sendContent(ex, task); } @@ -229,12 +235,12 @@ public class TaskModule extends BaseHandler implements TaskService { if (params.get(OFFSET) instanceof String o) try { offset = Long.parseLong(o); } catch (NumberFormatException e) { - throw invalidFieldException(OFFSET, "number"); + throw invalidField(OFFSET, t(Text.NUMBER)); } if (params.get(LIMIT) instanceof String l) try { limit = Long.parseLong(l); } catch (NumberFormatException e) { - throw invalidFieldException(LIMIT, "number"); + throw invalidField(LIMIT, t(Text.NUMBER)); } var tasks = taskDb.listUserTasks(user.id(), limit, offset, false); var mapped = loadMembers(tasks).stream().map(Task::toMap); @@ -311,12 +317,12 @@ public class TaskModule extends BaseHandler implements TaskService { try { userId = Long.parseLong(key); } catch (NumberFormatException e) { - throw invalidFieldException(USER_ID, "long"); + throw invalidField(USER_ID, t(LONG)); } var permission = switch (json.get(key)) { case Number code -> Permission.of(code.intValue()); case String name -> Permission.valueOf(name); - default -> throw invalidFieldException(PERMISSION, "int / String"); + default -> throw invalidField(PERMISSION, "int / String"); }; if (permission == OWNER) { // if a new person is about to become the task owner for (var member : members.values()) { // alter the previous owners to editors @@ -336,7 +342,7 @@ public class TaskModule extends BaseHandler implements TaskService { private boolean patchTask(HttpExchange ex, long taskId, UmbrellaUser user) throws IOException { var task = loadMembers(taskDb.load(taskId)); var member = task.members().get(user.id()); - if (member == null || member.permission() == READ_ONLY) throw forbidden("You are not a allowed to edit {0}!", task.name()); + if (member == null || member.permission() == READ_ONLY) throw forbidden("You are not a allowed to edit {object}!", OBJECT, task.name()); var json = json(ex); if (json.has(DROP_MEMBER) && json.get(DROP_MEMBER) instanceof Number id) dropMember(task, id.longValue()); if (json.has(MEMBERS) && json.get(MEMBERS) instanceof JSONObject memberJson) patchMembers(task, memberJson); @@ -350,7 +356,7 @@ public class TaskModule extends BaseHandler implements TaskService { private boolean postNewTask(UmbrellaUser user, HttpExchange ex) throws IOException { var json = json(ex); - if (!(json.has(PROJECT_ID) && json.get(PROJECT_ID) instanceof Number pid)) throw missingFieldException(PROJECT_ID); + if (!(json.has(PROJECT_ID) && json.get(PROJECT_ID) instanceof Number pid)) throw missingField(PROJECT_ID); long projectId = pid.longValue(); var project = projectService().load(projectId); @@ -364,7 +370,7 @@ public class TaskModule extends BaseHandler implements TaskService { taskService().loadMembers(parentTask); members = parentTask.members(); member = members.get(user.id()); - if (member == null || member.permission() == READ_ONLY) throw forbidden("You are not allowed to add sub-stasks to {0}", parentTask.name()); + if (member == null || member.permission() == READ_ONLY) throw forbidden("You are not allowed to add sub-stasks to {object}", OBJECT, parentTask.name()); } var newMembers = new HashMap(); @@ -412,7 +418,7 @@ public class TaskModule extends BaseHandler implements TaskService { private boolean postSearch(UmbrellaUser user, HttpExchange ex) throws IOException { var json = json(ex); - if (!(json.has(KEY) && json.get(KEY) instanceof String key)) throw missingFieldException(KEY); + if (!(json.has(KEY) && json.get(KEY) instanceof String key)) throw missingField(KEY); var projectId = json.has(PROJECT_ID) && json.get(PROJECT_ID) instanceof Number pid ? pid.longValue() : null; var keys = Arrays.asList(key.split(" ")); var fulltext = json.has(FULLTEXT) && json.get(FULLTEXT) instanceof Boolean val && val; diff --git a/time/src/main/java/de/srsoftware/umbrella/time/Constants.java b/time/src/main/java/de/srsoftware/umbrella/time/Constants.java index 5859381b..89632140 100644 --- a/time/src/main/java/de/srsoftware/umbrella/time/Constants.java +++ b/time/src/main/java/de/srsoftware/umbrella/time/Constants.java @@ -4,7 +4,6 @@ package de.srsoftware.umbrella.time; public class Constants { private Constants(){} - public static final String CHILDREN = "children"; public static final String CLOSED = "closed"; public static final String CONFIG_DATABASE = "umbrella.modules.time.database"; public static final String DOCUMENTS = "documents"; @@ -14,8 +13,6 @@ public class Constants { public static final String TABLE_TASK_TIMES = "task_times"; public static final String TABLE_TIMES = "times"; public static final String TASK_ID = "task_id"; - public static final String TASKS = "tasks"; - public static final String TIME_ID = "time_id"; public static final String TIMES = "times"; public static final String TRACK_TASK = "track_task"; diff --git a/time/src/main/java/de/srsoftware/umbrella/time/SqliteDb.java b/time/src/main/java/de/srsoftware/umbrella/time/SqliteDb.java index a9b3e91e..d68ca5a9 100644 --- a/time/src/main/java/de/srsoftware/umbrella/time/SqliteDb.java +++ b/time/src/main/java/de/srsoftware/umbrella/time/SqliteDb.java @@ -4,10 +4,13 @@ package de.srsoftware.umbrella.time; import static de.srsoftware.tools.jdbc.Condition.*; import static de.srsoftware.tools.jdbc.Query.*; import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL; -import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.Errors.*; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseException; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Field.TIME_ID; +import static de.srsoftware.umbrella.core.constants.Text.TIME_WITH_ID; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; import static de.srsoftware.umbrella.core.model.Time.State.Complete; +import static de.srsoftware.umbrella.core.model.Translatable.t; import static de.srsoftware.umbrella.time.Constants.*; import static java.text.MessageFormat.format; @@ -50,7 +53,7 @@ CREATE TABLE IF NOT EXISTS {0} ( stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_TASK_TIMES).causedBy(e); + throw failedToCreateTable(TABLE_TASK_TIMES).causedBy(e); } } @@ -65,13 +68,13 @@ CREATE TABLE IF NOT EXISTS {0} ( {6} TIMESTAMP, {7} INT NOT NULL DEFAULT {8} )"""; - sql = format(sql,TABLE_TIMES,ID,USER_ID,SUBJECT,DESCRIPTION,START_TIME,END_TIME,STATE, Time.State.Started.code()); + sql = format(sql,TABLE_TIMES, ID, USER_ID, SUBJECT, DESCRIPTION,START_TIME, END_TIME, STATE, Time.State.Started.code()); try { var stmt = db.prepareStatement(sql); stmt.execute(); stmt.close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_CREATE_TABLE,TABLE_TIMES).causedBy(e); + throw failedToCreateTable(TABLE_TIMES).causedBy(e); } } @@ -84,7 +87,7 @@ CREATE TABLE IF NOT EXISTS {0} ( db.setAutoCommit(false); return timeId; } catch (SQLException e) { - throw databaseException(FAILED_TO_DROP_ENTITY,"time "+timeId).causedBy(e); + throw failedToDropObject(t(TIME_WITH_ID, ID,timeId)).causedBy(e); } } @@ -93,7 +96,7 @@ CREATE TABLE IF NOT EXISTS {0} ( try { var query = select(ALL).from(TABLE_TIMES).where(USER_ID,equal(userId)); if (fulltext) { - for (var key : keys) query.where(format("CONCAT({0},\" \",{1})",SUBJECT,DESCRIPTION),like("%"+key+"%")); + for (var key : keys) query.where(format("CONCAT({0},\" \",{1})", SUBJECT, DESCRIPTION),like("%"+key+"%")); } else { for (var key : keys) query.where(SUBJECT,like("%"+key+"%")); } @@ -106,7 +109,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return times; } catch (Exception e) { - throw databaseException(FAILED_TO_SEARCH_DB,TABLE_TIMES).causedBy(e); + throw failedToSearchDb(t(TIMES)).causedBy(e); } } @@ -133,7 +136,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return times; } catch (Exception e) { - throw databaseException(FAILED_TO_LIST_ENTITIES,TIMES).causedBy(e); + throw databaseException(FAILED_TO_LIST_ENTITIES, TYPE,TIMES).causedBy(e); } } @@ -157,7 +160,7 @@ CREATE TABLE IF NOT EXISTS {0} ( rs.close(); return times; } catch (SQLException e) { - throw databaseException(FAILED_TO_LIST_ENTITIES,TIMES).causedBy(e); + throw databaseException(FAILED_TO_LIST_ENTITIES, TYPE,TIMES).causedBy(e); } } @@ -172,10 +175,10 @@ CREATE TABLE IF NOT EXISTS {0} ( rs = select(ALL).from(TABLE_TASK_TIMES).where(TIME_ID,equal(timeId)).exec(db); while (rs.next()) time.taskIds().add(rs.getLong(TASK_ID)); rs.close(); - if (time == null) throw UmbrellaException.notFound("No time found with id = {0}",timeId); + if (time == null) throw notFound("No time found with id = {id}", ID,timeId); return time; } catch (SQLException e) { - throw databaseException(FAILED_TO_LIST_ENTITIES,TIMES).causedBy(e); + throw databaseException(FAILED_TO_LIST_ENTITIES, TYPE,TIMES).causedBy(e); } } @@ -199,7 +202,7 @@ CREATE TABLE IF NOT EXISTS {0} ( query.execute(db).close(); return track; } catch (SQLException e){ - throw databaseException(FAILED_TO_STORE_ENTITY,"time").causedBy(e); + throw failedToStoreObject("time").causedBy(e); } } @@ -213,7 +216,7 @@ CREATE TABLE IF NOT EXISTS {0} ( .apply(timeState.code()) .close(); } catch (SQLException e) { - throw databaseException(FAILED_TO_UPDATE_ENTITY,TIMES).causedBy(e); + throw databaseException(FAILED_TO_UPDATE_OBJECT, OBJECT,TIMES).causedBy(e); } } } diff --git a/time/src/main/java/de/srsoftware/umbrella/time/TimeModule.java b/time/src/main/java/de/srsoftware/umbrella/time/TimeModule.java index 4b255bbc..7f94dc7f 100644 --- a/time/src/main/java/de/srsoftware/umbrella/time/TimeModule.java +++ b/time/src/main/java/de/srsoftware/umbrella/time/TimeModule.java @@ -2,13 +2,17 @@ package de.srsoftware.umbrella.time; import static de.srsoftware.umbrella.core.ConnectionProvider.connect; -import static de.srsoftware.umbrella.core.Constants.*; +import static de.srsoftware.umbrella.core.Errors.FAILED_TO_LOAD_OBJECT_BY_ID; import static de.srsoftware.umbrella.core.ModuleRegistry.*; -import static de.srsoftware.umbrella.core.Paths.*; import static de.srsoftware.umbrella.core.Util.mapValues; +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Field.TASKS; +import static de.srsoftware.umbrella.core.constants.Path.*; +import static de.srsoftware.umbrella.core.constants.Text.TIME_WITH_ID; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; import static de.srsoftware.umbrella.core.model.Time.State.Open; import static de.srsoftware.umbrella.core.model.Time.State.Started; +import static de.srsoftware.umbrella.core.model.Translatable.t; import static de.srsoftware.umbrella.time.Constants.*; import com.sun.net.httpserver.HttpExchange; @@ -18,6 +22,7 @@ import de.srsoftware.tools.SessionToken; import de.srsoftware.umbrella.core.BaseHandler; import de.srsoftware.umbrella.core.ModuleRegistry; import de.srsoftware.umbrella.core.api.*; +import de.srsoftware.umbrella.core.constants.Text; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.core.model.*; import java.io.IOException; @@ -31,7 +36,7 @@ public class TimeModule extends BaseHandler implements TimeService { public TimeModule( Configuration config) throws UmbrellaException { super(); - var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE)); + var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingField(CONFIG_DATABASE)); timeDb = new SqliteDb(connect(dbFile)); ModuleRegistry.add(this); } @@ -59,7 +64,7 @@ public class TimeModule extends BaseHandler implements TimeService { var timeId = Long.parseLong(head); return deleteTime(user.get(),timeId,ex); } catch (NumberFormatException e){ - return send(ex,invalidFieldException(TIME_ID,"long value")); + return send(ex,invalidField(TIME_ID,"long value")); } catch (UmbrellaException e){ return send(ex,e); } @@ -98,7 +103,7 @@ public class TimeModule extends BaseHandler implements TimeService { var timeId = Long.parseLong(head); return patchTime(user.get(), timeId, ex); } catch (NumberFormatException e) { - return send(ex, invalidFieldException(TIME_ID, "long value")); + return send(ex, invalidField(TIME_ID, "long value")); } } catch (UmbrellaException e){ return send(ex,e); @@ -143,10 +148,10 @@ public class TimeModule extends BaseHandler implements TimeService { throw unprocessable("Expected two time ids as body"); } var time1 = timeDb.load(id1); - if (time1.userId() != user.id()) throw forbidden("You are not owner of time {0}",time1.id()); + if (time1.userId() != user.id()) throw notAmember(t(TIME_WITH_ID, ID, time1.id())); if (time1.state() != Open) throw forbidden("Time is not editable"); var time2 = timeDb.load(id2); - if (time2.userId() != user.id()) throw forbidden("You are not owner of time {0}",time2.id()); + if (time2.userId() != user.id()) throw forbidden("You are not owner of time {id}", ID,time2.id()); if (time2.state() != Open) throw forbidden("Time is not editable"); if (time1.start() > time2.start()) { @@ -196,16 +201,16 @@ public class TimeModule extends BaseHandler implements TimeService { private boolean getStartedTime(UmbrellaUser user, HttpExchange ex) throws IOException { var startedTime = getStartedTime(user); if (startedTime.isPresent()) return sendContent(ex,startedTime.get()); - return send(ex,UmbrellaException.notFound("no started time")); + return send(ex, UmbrellaException.notFound("no started time")); } private boolean listTimes(HttpExchange ex, UmbrellaUser user) throws IOException, UmbrellaException { var json = json(ex); - if (!(json.has(COMPANY_ID) && json.get(COMPANY_ID) instanceof Number cid)) throw missingFieldException(COMPANY_ID); + if (!(json.has(COMPANY_ID) && json.get(COMPANY_ID) instanceof Number cid)) throw missingField(COMPANY_ID); var companyId = cid.longValue(); var company = companyService().get(companyId); - if (!companyService().membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name()); - if (!(json.has(PROJECT_ID) && json.get(PROJECT_ID) instanceof Number pid)) throw missingFieldException(PROJECT_ID); + if (!companyService().membership(companyId,user.id())) throw notAmember(company.name()); + if (!(json.has(PROJECT_ID) && json.get(PROJECT_ID) instanceof Number pid)) throw missingField(PROJECT_ID); long projectId = pid.longValue(); Map tasksOfProject = taskService().listProjectTasks(projectId); @@ -235,12 +240,12 @@ public class TimeModule extends BaseHandler implements TimeService { private boolean patchTimes(UmbrellaUser user, HttpExchange ex) throws IOException { var json = json(ex); - if (!json.has(IDS) || !(json.get(IDS) instanceof JSONArray ids)) throw missingFieldException(IDS); + if (!json.has(IDS) || !(json.get(IDS) instanceof JSONArray ids)) throw missingField(IDS); var times = new HashSet