From 4343ff7d7ae722e0df45f74cec2b42f6dd5bfab4 Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Thu, 12 Feb 2026 08:48:11 +0100 Subject: [PATCH 01/19] preparing new poll module Signed-off-by: Stephan Richter --- .../java/de/srsoftware/umbrella/core/api/PollService.java | 4 ++++ poll/build.gradle.kts | 6 ++++++ .../main/java/de/srsoftware/umbrella/poll/PollModule.java | 7 +++++++ settings.gradle.kts | 3 ++- 4 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/de/srsoftware/umbrella/core/api/PollService.java create mode 100644 poll/build.gradle.kts create mode 100644 poll/src/main/java/de/srsoftware/umbrella/poll/PollModule.java diff --git a/core/src/main/java/de/srsoftware/umbrella/core/api/PollService.java b/core/src/main/java/de/srsoftware/umbrella/core/api/PollService.java new file mode 100644 index 00000000..b7aaef47 --- /dev/null +++ b/core/src/main/java/de/srsoftware/umbrella/core/api/PollService.java @@ -0,0 +1,4 @@ +package de.srsoftware.umbrella.core.api; + +public interface PollService { +} diff --git a/poll/build.gradle.kts b/poll/build.gradle.kts new file mode 100644 index 00000000..9df7f44d --- /dev/null +++ b/poll/build.gradle.kts @@ -0,0 +1,6 @@ +description = "Umbrella : Polls" + +dependencies{ + implementation(project(":core")) +} + diff --git a/poll/src/main/java/de/srsoftware/umbrella/poll/PollModule.java b/poll/src/main/java/de/srsoftware/umbrella/poll/PollModule.java new file mode 100644 index 00000000..82838a9b --- /dev/null +++ b/poll/src/main/java/de/srsoftware/umbrella/poll/PollModule.java @@ -0,0 +1,7 @@ +package de.srsoftware.umbrella.poll; + +import de.srsoftware.umbrella.core.BaseHandler; +import de.srsoftware.umbrella.core.api.PollService; + +public class PollModule extends BaseHandler implements PollService { +} diff --git a/settings.gradle.kts b/settings.gradle.kts index c5f2d7c2..9b27edfe 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -8,10 +8,12 @@ include("contact") include("core") include("documents") include("files") +include("journal") include("legacy") include("messages") include("markdown") include("notes") +include("poll") include("project") include("stock") include("tags") @@ -22,4 +24,3 @@ include("user") include("web") include("wiki") -include("journal") \ No newline at end of file From 0db2ad8b0e96be6a1c95c64ebf555a366b78979b Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Thu, 12 Feb 2026 16:19:41 +0100 Subject: [PATCH 02/19] preparing poll module Signed-off-by: Stephan Richter --- .../umbrella/core/constants/Field.java | 4 + .../srsoftware/umbrella/poll/Constants.java | 9 ++ .../de/srsoftware/umbrella/poll/PollDb.java | 4 + .../srsoftware/umbrella/poll/PollModule.java | 16 ++++ .../de/srsoftware/umbrella/poll/SqliteDb.java | 83 +++++++++++++++++++ 5 files changed, 116 insertions(+) create mode 100644 poll/src/main/java/de/srsoftware/umbrella/poll/Constants.java create mode 100644 poll/src/main/java/de/srsoftware/umbrella/poll/PollDb.java create mode 100644 poll/src/main/java/de/srsoftware/umbrella/poll/SqliteDb.java 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 index 8ec434c6..6df01416 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/constants/Field.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/constants/Field.java @@ -103,6 +103,7 @@ public class Field { public static final String OBJECT = "object"; public static final String OFFSET = "offset"; public static final String OPTIONAL = "optional"; + public static final String OPTION_ID = "option_id"; public static final String OWNER = "owner"; public static final String OWNER_NUMBER = "owner_number"; @@ -113,11 +114,13 @@ public class Field { public static final String PATH = "path"; public static final String PERMISSION = "permission"; public static final String PHONE = "phone"; + public static final String POLL_ID = "poll_id"; 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 PRIVATE = "private"; public static final String PROJECT = "project"; public static final String PROJECT_ID = "project_id"; public static final String PROPERTIES = "properties"; @@ -178,4 +181,5 @@ public class Field { public static final String VERSION = "version"; public static final String VERSIONS = "versions"; + public static final String WEIGHT = "weight"; } diff --git a/poll/src/main/java/de/srsoftware/umbrella/poll/Constants.java b/poll/src/main/java/de/srsoftware/umbrella/poll/Constants.java new file mode 100644 index 00000000..b7f3f511 --- /dev/null +++ b/poll/src/main/java/de/srsoftware/umbrella/poll/Constants.java @@ -0,0 +1,9 @@ +package de.srsoftware.umbrella.poll; + +public class Constants { + public static final String CONFIG_DATABASE = "de.umbrella.module.polls"; + public static final String TABLE_OPTIONS = "options"; + public static final String TABLE_POLLS = "polls"; + public static final String TABLE_SELECTIONS = "selections"; + public static final String TABLE_WEIGHTS = "weights"; +} diff --git a/poll/src/main/java/de/srsoftware/umbrella/poll/PollDb.java b/poll/src/main/java/de/srsoftware/umbrella/poll/PollDb.java new file mode 100644 index 00000000..ced305ca --- /dev/null +++ b/poll/src/main/java/de/srsoftware/umbrella/poll/PollDb.java @@ -0,0 +1,4 @@ +package de.srsoftware.umbrella.poll; + +public interface PollDb { +} diff --git a/poll/src/main/java/de/srsoftware/umbrella/poll/PollModule.java b/poll/src/main/java/de/srsoftware/umbrella/poll/PollModule.java index 82838a9b..2af331ca 100644 --- a/poll/src/main/java/de/srsoftware/umbrella/poll/PollModule.java +++ b/poll/src/main/java/de/srsoftware/umbrella/poll/PollModule.java @@ -1,7 +1,23 @@ package de.srsoftware.umbrella.poll; +import de.srsoftware.configuration.Configuration; import de.srsoftware.umbrella.core.BaseHandler; +import de.srsoftware.umbrella.core.ModuleRegistry; import de.srsoftware.umbrella.core.api.PollService; +import static de.srsoftware.umbrella.core.ConnectionProvider.connect; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingField; +import static de.srsoftware.umbrella.poll.Constants.CONFIG_DATABASE; + public class PollModule extends BaseHandler implements PollService { + + private PollDb pollDb; + + PollModule(Configuration config){ + super(); + var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingField(CONFIG_DATABASE)); + pollDb = new SqliteDb(connect(dbFile)); + ModuleRegistry.add(this); + + } } diff --git a/poll/src/main/java/de/srsoftware/umbrella/poll/SqliteDb.java b/poll/src/main/java/de/srsoftware/umbrella/poll/SqliteDb.java new file mode 100644 index 00000000..a6e8166d --- /dev/null +++ b/poll/src/main/java/de/srsoftware/umbrella/poll/SqliteDb.java @@ -0,0 +1,83 @@ +package de.srsoftware.umbrella.poll; + +import de.srsoftware.umbrella.core.BaseDb; +import de.srsoftware.umbrella.core.constants.Field; + +import java.sql.Connection; +import java.sql.SQLException; + +import static de.srsoftware.umbrella.core.constants.Field.*; +import static de.srsoftware.umbrella.core.constants.Field.DESCRIPTION; +import static de.srsoftware.umbrella.core.constants.Field.SHOW_CLOSED; +import static de.srsoftware.umbrella.core.constants.Field.STATUS; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.failedToCreateTable; +import static de.srsoftware.umbrella.core.model.Status.OPEN; +import static de.srsoftware.umbrella.poll.Constants.*; +import static java.text.MessageFormat.format; + +public class SqliteDb extends BaseDb implements PollDb { + + public SqliteDb(Connection connection) { + super(connection); + } + + @Override + protected int createTables() { + var version = createSettingsTable(); + switch (version){ + case 0: + createPollsTable(); + createOptionsTable(); + createWeightsTable(); + createSelectionsTable(); + case 1: + createSharesTable(); + } + return setCurrentVersion(2); + } + + private void createOptionsTable() { + var sql = "CREATE TABLE IF NOT EXISTS {0} ({1} INT NOT NULL, {2} VARCHAR(255) NOT NULL REFERENCES {3}({1}), {4} VARCHAR(255) NOT NULL, {5} TEXT, {6} INT DEFAULT 0, PRIMARY KEY ({1}, {2}))"; + try { + var stmt = db.prepareStatement(format(sql,TABLE_OPTIONS, Field.ID,Field.POLL_ID,TABLE_POLLS,Field.NAME, Field.DESCRIPTION, Field.STATUS)); + stmt.execute(); + stmt.close(); + } catch (SQLException e) { + throw failedToCreateTable(TABLE_OPTIONS).causedBy(e); + } + } + + private void createPollsTable() { + var sql = "CREATE TABLE IF NOT EXISTS {0} ({1} VARCHAR(255) NOT NULL PRIMARY_KEY, {2} INT NOT NULL, {3} VARCHAR(255) NOT NULL, {4} TEXT, {5} BOOLEAN)"; + try { + var stmt = db.prepareStatement(format(sql,TABLE_POLLS, Field.ID,Field.USER_ID,Field.NAME,Field.DESCRIPTION, Field.PRIVATE)); + stmt.execute(); + stmt.close(); + } catch (SQLException e) { + throw failedToCreateTable(TABLE_POLLS).causedBy(e); + } + } + + private void createSelectionsTable() { + var sql = "CREATE TABLE IF NOT EXISTS {0} ({1} INT NOT NULL REFERENCES {2}({3}), {4} VARCHAR(255) NOT NULL REFERENCES {5}({3}), {6} VARCHAR(255) NOT NULL, {7} INT NOT NULL REFERENCES {8}({7}), PRIMARY KEY ({1}, {4}, {6}))"; + try { + var stmt = db.prepareStatement(format(sql,TABLE_SELECTIONS,Field.OPTION_ID,TABLE_OPTIONS,ID, POLL_ID, TABLE_POLLS, USER, Field.WEIGHT, TABLE_WEIGHTS)); + stmt.execute(); + stmt.close(); + } catch (SQLException e) { + throw failedToCreateTable(TABLE_SELECTIONS).causedBy(e); + } + } + + private void createWeightsTable(){ + var sql = "CREATE TABLE {0} ( {1} INT NOT NULL, {2} VARCHAR(255) NOT NULL REFERENCES {3}({4}), {5} TEXT, PRIMARY KEY ({2}, {1}))" + try { + var stmt = db.prepareStatement(format(sql,TABLE_WEIGHTS, WEIGHT,POLL_ID,TABLE_POLLS, ID, DESCRIPTION)); + stmt.execute(); + stmt.close(); + } catch (SQLException e) { + throw failedToCreateTable(TABLE_WEIGHTS).causedBy(e); + } + } + } +} From dbc4525e80e495ebe4088c4d444b59c36d124510 Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Fri, 13 Feb 2026 09:15:19 +0100 Subject: [PATCH 03/19] started implementing poll backend Signed-off-by: Stephan Richter --- backend/build.gradle.kts | 1 + .../umbrella/backend/Application.java | 2 + .../umbrella/core/ModuleRegistry.java | 8 ++- .../umbrella/core/api/PollService.java | 1 + .../srsoftware/umbrella/core/model/Poll.java | 37 +++++++++++++ .../srsoftware/umbrella/poll/Constants.java | 4 +- .../de/srsoftware/umbrella/poll/PollDb.java | 7 +++ .../srsoftware/umbrella/poll/PollModule.java | 41 +++++++++++++-- .../de/srsoftware/umbrella/poll/SqliteDb.java | 52 +++++++++++++++---- .../umbrella/stock/StockModule.java | 6 +-- 10 files changed, 138 insertions(+), 21 deletions(-) create mode 100644 core/src/main/java/de/srsoftware/umbrella/core/model/Poll.java diff --git a/backend/build.gradle.kts b/backend/build.gradle.kts index 36aa6e03..9b7230cb 100644 --- a/backend/build.gradle.kts +++ b/backend/build.gradle.kts @@ -23,6 +23,7 @@ dependencies{ implementation(project(":markdown")) implementation(project(":messages")) implementation(project(":notes")) + implementation(project(":poll")) implementation(project(":project")) implementation(project(":stock")) implementation(project(":tags")) 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 aa47ccf1..42e76b2a 100644 --- a/backend/src/main/java/de/srsoftware/umbrella/backend/Application.java +++ b/backend/src/main/java/de/srsoftware/umbrella/backend/Application.java @@ -23,6 +23,7 @@ import de.srsoftware.umbrella.markdown.MarkdownApi; import de.srsoftware.umbrella.message.MessageSystem; import de.srsoftware.umbrella.messagebus.MessageApi; import de.srsoftware.umbrella.notes.NoteModule; +import de.srsoftware.umbrella.poll.PollModule; import de.srsoftware.umbrella.project.ProjectModule; import de.srsoftware.umbrella.stock.StockModule; import de.srsoftware.umbrella.tags.TagModule; @@ -81,6 +82,7 @@ public class Application { new MarkdownApi().bindPath("/api/markdown").on(server); new NoteModule(config).bindPath("/api/notes").on(server); new StockModule(config).bindPath("/api/stock").on(server); + new PollModule(config).bindPath("/api/poll").on(server); new ProjectModule(config).bindPath("/api/project").on(server); new ProjectLegacy(config).bindPath("/legacy/project").on(server); new TaskModule(config).bindPath("/api/task").on(server); diff --git a/core/src/main/java/de/srsoftware/umbrella/core/ModuleRegistry.java b/core/src/main/java/de/srsoftware/umbrella/core/ModuleRegistry.java index ea02c2c0..dff11922 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/ModuleRegistry.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/ModuleRegistry.java @@ -12,6 +12,7 @@ public class ModuleRegistry { private FileService fileService; private MarkdownService markdownService; private NoteService noteService; + private PollService pollService; private PostBox postBox; private ProjectService projectService; private StockService stockService; @@ -33,9 +34,10 @@ public class ModuleRegistry { case ContactService cs: singleton.contactService = cs; break; case DocumentService ds: singleton.documentService = ds; break; case FileService fs: singleton.fileService = fs; break; - case StockService is: singleton.stockService = is; break; + case StockService is: singleton.stockService = is; break; case MarkdownService ms: singleton.markdownService = ms; break; case NoteService ns: singleton.noteService = ns; break; + case PollService ps: singleton.pollService = ps; break; case PostBox pb: singleton.postBox = pb; break; case ProjectService ps: singleton.projectService = ps; break; case TagService ts: singleton.tagService = ts; break; @@ -81,6 +83,10 @@ public class ModuleRegistry { return singleton.noteService; } + public static PollService pollService() { + return singleton.pollService; + } + public static PostBox postBox() { return singleton.postBox; } diff --git a/core/src/main/java/de/srsoftware/umbrella/core/api/PollService.java b/core/src/main/java/de/srsoftware/umbrella/core/api/PollService.java index b7aaef47..c559ce2e 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/api/PollService.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/api/PollService.java @@ -1,3 +1,4 @@ +/* © SRSoftware 2025 */ package de.srsoftware.umbrella.core.api; public interface PollService { diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Poll.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Poll.java new file mode 100644 index 00000000..8f2769e1 --- /dev/null +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Poll.java @@ -0,0 +1,37 @@ +package de.srsoftware.umbrella.core.model; + +import de.srsoftware.tools.Mappable; +import de.srsoftware.umbrella.core.ModuleRegistry; +import de.srsoftware.umbrella.core.Util; +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.Map; + +public record Poll(String id, Owner owner, String name, String description, boolean isPrivate) implements Mappable { + public static Poll of(ResultSet rs) throws SQLException { + var id = rs.getString(Field.ID); + var userId = rs.getLong(Field.USER_ID); + var name = rs.getString(Field.NAME); + var description = rs.getString(Field.DESCRIPTION); + var isPrivate = rs.getBoolean(Field.PRIVATE); + var owner = ModuleRegistry.userService().loadUser(userId); + return new Poll(id,owner,name,description,isPrivate); + } + + @Override + public Map toMap() { + return Map.of( + Field.ID, id, + Field.OWNER, owner.toMap(), + Field.NAME,name, + Field.DESCRIPTION, Map.of( + Field.SOURCE,description, + Field.RENDERED,Util.markdown(description) + ), + Field.PRIVATE, isPrivate + ); + } +} diff --git a/poll/src/main/java/de/srsoftware/umbrella/poll/Constants.java b/poll/src/main/java/de/srsoftware/umbrella/poll/Constants.java index b7f3f511..a3eed034 100644 --- a/poll/src/main/java/de/srsoftware/umbrella/poll/Constants.java +++ b/poll/src/main/java/de/srsoftware/umbrella/poll/Constants.java @@ -1,9 +1,11 @@ +/* © SRSoftware 2025 */ package de.srsoftware.umbrella.poll; public class Constants { - public static final String CONFIG_DATABASE = "de.umbrella.module.polls"; + public static final String CONFIG_DATABASE = "umbrella.modules.poll.database"; public static final String TABLE_OPTIONS = "options"; public static final String TABLE_POLLS = "polls"; public static final String TABLE_SELECTIONS = "selections"; + public static final String TABLE_SHARES = "shares"; public static final String TABLE_WEIGHTS = "weights"; } diff --git a/poll/src/main/java/de/srsoftware/umbrella/poll/PollDb.java b/poll/src/main/java/de/srsoftware/umbrella/poll/PollDb.java index ced305ca..f69d5db0 100644 --- a/poll/src/main/java/de/srsoftware/umbrella/poll/PollDb.java +++ b/poll/src/main/java/de/srsoftware/umbrella/poll/PollDb.java @@ -1,4 +1,11 @@ +/* © SRSoftware 2025 */ package de.srsoftware.umbrella.poll; +import de.srsoftware.umbrella.core.model.Poll; +import de.srsoftware.umbrella.core.model.UmbrellaUser; + +import java.util.Collection; + public interface PollDb { + Collection listPolls(UmbrellaUser user); } diff --git a/poll/src/main/java/de/srsoftware/umbrella/poll/PollModule.java b/poll/src/main/java/de/srsoftware/umbrella/poll/PollModule.java index 2af331ca..992fc719 100644 --- a/poll/src/main/java/de/srsoftware/umbrella/poll/PollModule.java +++ b/poll/src/main/java/de/srsoftware/umbrella/poll/PollModule.java @@ -1,23 +1,56 @@ +/* © SRSoftware 2025 */ package de.srsoftware.umbrella.poll; +import static de.srsoftware.umbrella.core.ConnectionProvider.connect; +import static de.srsoftware.umbrella.core.ModuleRegistry.userService; +import static de.srsoftware.umbrella.core.constants.Path.LIST; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingField; +import static de.srsoftware.umbrella.poll.Constants.CONFIG_DATABASE; + +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.PollService; +import de.srsoftware.umbrella.core.exceptions.UmbrellaException; +import de.srsoftware.umbrella.core.model.Token; +import de.srsoftware.umbrella.core.model.UmbrellaUser; -import static de.srsoftware.umbrella.core.ConnectionProvider.connect; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingField; -import static de.srsoftware.umbrella.poll.Constants.CONFIG_DATABASE; +import java.io.IOException; +import java.util.Optional; public class PollModule extends BaseHandler implements PollService { private PollDb pollDb; - PollModule(Configuration config){ + public PollModule(Configuration config){ super(); var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingField(CONFIG_DATABASE)); pollDb = new SqliteDb(connect(dbFile)); ModuleRegistry.add(this); + } + @Override + public boolean doGet(Path path, HttpExchange ex) throws IOException { + addCors(ex); + try { + Optional token = SessionToken.from(ex).map(Token::of); + var user = userService().loadUser(token); + if (user.isEmpty()) return unauthorized(ex); + var head = path.pop(); + return switch (head) { + case LIST -> getPollList(ex,user.get()); + case null, default -> super.doGet(path,ex); + }; + } catch (UmbrellaException e){ + return send(ex,e); + } + } + + private boolean getPollList(HttpExchange ex, UmbrellaUser user) throws IOException { + var list = pollDb.listPolls(user); + return sendContent(ex,list); } } diff --git a/poll/src/main/java/de/srsoftware/umbrella/poll/SqliteDb.java b/poll/src/main/java/de/srsoftware/umbrella/poll/SqliteDb.java index a6e8166d..d193c132 100644 --- a/poll/src/main/java/de/srsoftware/umbrella/poll/SqliteDb.java +++ b/poll/src/main/java/de/srsoftware/umbrella/poll/SqliteDb.java @@ -1,19 +1,25 @@ +/* © SRSoftware 2025 */ package de.srsoftware.umbrella.poll; +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.Field.*; +import static de.srsoftware.umbrella.core.constants.Field.DESCRIPTION; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; +import static de.srsoftware.umbrella.poll.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.model.Poll; +import de.srsoftware.umbrella.core.model.UmbrellaUser; import java.sql.Connection; import java.sql.SQLException; - -import static de.srsoftware.umbrella.core.constants.Field.*; -import static de.srsoftware.umbrella.core.constants.Field.DESCRIPTION; -import static de.srsoftware.umbrella.core.constants.Field.SHOW_CLOSED; -import static de.srsoftware.umbrella.core.constants.Field.STATUS; -import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.failedToCreateTable; -import static de.srsoftware.umbrella.core.model.Status.OPEN; -import static de.srsoftware.umbrella.poll.Constants.*; -import static java.text.MessageFormat.format; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; public class SqliteDb extends BaseDb implements PollDb { @@ -48,7 +54,7 @@ public class SqliteDb extends BaseDb implements PollDb { } private void createPollsTable() { - var sql = "CREATE TABLE IF NOT EXISTS {0} ({1} VARCHAR(255) NOT NULL PRIMARY_KEY, {2} INT NOT NULL, {3} VARCHAR(255) NOT NULL, {4} TEXT, {5} BOOLEAN)"; + var sql = "CREATE TABLE IF NOT EXISTS {0} ({1} VARCHAR(255) NOT NULL PRIMARY KEY, {2} INT NOT NULL, {3} VARCHAR(255) NOT NULL, {4} TEXT, {5} BOOLEAN)"; try { var stmt = db.prepareStatement(format(sql,TABLE_POLLS, Field.ID,Field.USER_ID,Field.NAME,Field.DESCRIPTION, Field.PRIVATE)); stmt.execute(); @@ -69,8 +75,19 @@ public class SqliteDb extends BaseDb implements PollDb { } } + private void createSharesTable() { + var sql = "CREATE TABLE IF NOT EXISTS {0} ({1} VARCHAR(255) NOT NULL REFERENCES {2}({3}), {4} INT NOT NULL, {5} INT, PRIMARY KEY ({1}, {4}))"; + try { + var stmt = db.prepareStatement(format(sql,TABLE_SHARES,POLL_ID,TABLE_POLLS,ID,USER_ID, PERMISSION)); + stmt.execute(); + stmt.close(); + } catch (SQLException e) { + throw failedToCreateTable(TABLE_SHARES).causedBy(e); + } + } + private void createWeightsTable(){ - var sql = "CREATE TABLE {0} ( {1} INT NOT NULL, {2} VARCHAR(255) NOT NULL REFERENCES {3}({4}), {5} TEXT, PRIMARY KEY ({2}, {1}))" + var sql = "CREATE TABLE {0} ( {1} INT NOT NULL, {2} VARCHAR(255) NOT NULL REFERENCES {3}({4}), {5} TEXT, PRIMARY KEY ({2}, {1}))"; try { var stmt = db.prepareStatement(format(sql,TABLE_WEIGHTS, WEIGHT,POLL_ID,TABLE_POLLS, ID, DESCRIPTION)); stmt.execute(); @@ -79,5 +96,18 @@ public class SqliteDb extends BaseDb implements PollDb { throw failedToCreateTable(TABLE_WEIGHTS).causedBy(e); } } + + @Override + public Collection listPolls(UmbrellaUser user) { + // TODO + try { + var rs = select(ALL).from(TABLE_POLLS).where(USER_ID,equal(user.id())).exec(db); + var list = new ArrayList(); + while (rs.next()) list.add(Poll.of(rs)); + return list; + } catch (SQLException sqle){ + throw failedToLoadObject(TABLE_POLLS); + } + return List.of(); } } 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 c53f10b0..38355eaf 100644 --- a/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java +++ b/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java @@ -33,12 +33,10 @@ 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.Location; - -import java.io.IOException; -import java.util.*; - import de.srsoftware.umbrella.messagebus.events.Event; import de.srsoftware.umbrella.messagebus.events.ItemEvent; +import java.io.IOException; +import java.util.*; import org.json.JSONObject; public class StockModule extends BaseHandler implements StockService { From a25736eff3edd183fd88d9e857ae4ad4a2629630 Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Sun, 15 Feb 2026 10:59:19 +0100 Subject: [PATCH 04/19] working on editor for polls Signed-off-by: Stephan Richter --- .../umbrella/core/constants/Field.java | 3 + .../umbrella/core/constants/Text.java | 1 + .../srsoftware/umbrella/core/model/Poll.java | 65 +++++++++++--- frontend/src/App.svelte | 4 + frontend/src/routes/poll/Edit.svelte | 88 +++++++++++++++++++ frontend/src/routes/poll/Index.svelte | 66 ++++++++++++++ .../de/srsoftware/umbrella/poll/PollDb.java | 2 + .../srsoftware/umbrella/poll/PollModule.java | 14 ++- .../de/srsoftware/umbrella/poll/SqliteDb.java | 50 ++++++++++- 9 files changed, 277 insertions(+), 16 deletions(-) create mode 100644 frontend/src/routes/poll/Edit.svelte create mode 100644 frontend/src/routes/poll/Index.svelte 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 index 6df01416..15f03df1 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/constants/Field.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/constants/Field.java @@ -102,6 +102,7 @@ public class Field { public static final String OBJECT = "object"; public static final String OFFSET = "offset"; + public static final String OPTIONS = "options"; public static final String OPTIONAL = "optional"; public static final String OPTION_ID = "option_id"; public static final String OWNER = "owner"; @@ -133,6 +134,7 @@ public class Field { public static final String SENDER = "sender"; public static final String SENDER_USER_ID = "sender_user_id"; public static final String SETTINGS = "settings"; + public static final String SHARES = "shares"; public static final String SHOW_CLOSED = "show_closed"; public static final String SILENT = "silent"; public static final String SOURCE = "source"; @@ -182,4 +184,5 @@ public class Field { public static final String VERSIONS = "versions"; public static final String WEIGHT = "weight"; + public static final String WEIGHTS = "weights"; } 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 index 562c3e46..913c3a7c 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/constants/Text.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/constants/Text.java @@ -45,6 +45,7 @@ public class Text { public static final String NUMBER = "number"; public static final String PATH = "path"; + public static final String POLL = "poll"; public static final String POLLS = "polls"; public static final String PROJECTS = "projects"; public static final String PROJECT_WITH_ID = "project ({id})"; diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Poll.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Poll.java index 8f2769e1..607df1d0 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Poll.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Poll.java @@ -8,30 +8,75 @@ import de.srsoftware.umbrella.core.constants.Field; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; + +import static de.srsoftware.umbrella.core.constants.Field.*; + +public record Poll(String id, Owner owner, String name, String description, boolean isPrivate, List