diff --git a/core/src/main/java/de/srsoftware/umbrella/core/constants/Path.java b/core/src/main/java/de/srsoftware/umbrella/core/constants/Path.java index 853be141..62cfeb14 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/constants/Path.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/constants/Path.java @@ -27,6 +27,8 @@ public class Path { public static final String MENU = "menu"; + public static final String OPTION = "option"; + public static final String PAGE = "page"; public static final String PASSWORD = "password"; public static final String PROJECT = "project"; 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 913c3a7c..38988a16 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 @@ -39,10 +39,11 @@ public class Text { public static final String MESSAGE = "message"; public static final String MESSAGES = "messages"; - public static final String NOTE = "note"; - public static final String NOTES = "notes"; - public static final String NOTE_WITH_ID = "note ({id})"; - public static final String NUMBER = "number"; + public static final String NOT_ALLOWED_TO_EDIT = "You are not allowed to edit {object}!"; + public static final String NOTE = "note"; + public static final String NOTES = "notes"; + 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 POLL = "poll"; diff --git a/frontend/src/routes/poll/Edit.svelte b/frontend/src/routes/poll/Edit.svelte index ad7cad4b..2178c907 100644 --- a/frontend/src/routes/poll/Edit.svelte +++ b/frontend/src/routes/poll/Edit.svelte @@ -5,12 +5,13 @@ import LineEditor from '../../Components/LineEditor.svelte'; import MarkdownEditor from '../../Components/MarkdownEditor.svelte'; - import { api, get } from '../../urls.svelte'; + import { api, get, post } from '../../urls.svelte'; import { error, yikes } from '../../warn.svelte'; import { t } from '../../translations.svelte'; import { user } from '../../user.svelte.js'; let { id } = $props(); + let new_option = $state({name:'',description:{'source':'',rendered:''}}); let poll = $state(null); async function load(){ @@ -22,6 +23,14 @@ } else error(res); } + async function save_new_option(){ + let url = api('poll/'+id+'/option'); + let res = await post(url,new_option); + if (res.ok){ + yikes(); + } else error(res); + } + onMount(load); @@ -48,7 +57,7 @@ - {#each poll.options as option} + {#each poll.options as option} @@ -57,7 +66,17 @@ - {/each} + {/each} + + + {t('add element',{element:t('options')})} + + + + + + + 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 80b15667..ace5e596 100644 --- a/poll/src/main/java/de/srsoftware/umbrella/poll/PollDb.java +++ b/poll/src/main/java/de/srsoftware/umbrella/poll/PollDb.java @@ -10,4 +10,6 @@ public interface PollDb { Collection listPolls(UmbrellaUser user); Poll loadPoll(String id); + + Poll save(Poll poll); } 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 23ddfed0..27043e78 100644 --- a/poll/src/main/java/de/srsoftware/umbrella/poll/PollModule.java +++ b/poll/src/main/java/de/srsoftware/umbrella/poll/PollModule.java @@ -4,6 +4,8 @@ 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.constants.Path.OPTION; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.forbidden; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingField; import static de.srsoftware.umbrella.poll.Constants.CONFIG_DATABASE; import static java.lang.System.Logger.Level.WARNING; @@ -15,10 +17,13 @@ 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.constants.Field; +import de.srsoftware.umbrella.core.constants.Text; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.core.model.Poll; import de.srsoftware.umbrella.core.model.Token; import de.srsoftware.umbrella.core.model.UmbrellaUser; +import org.json.JSONObject; import java.io.IOException; import java.util.Optional; @@ -52,6 +57,23 @@ public class PollModule extends BaseHandler implements PollService { } } + @Override + public boolean doPost(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 null -> super.doGet(path,ex); + default -> postToPoll(ex,user.get(),head, path); + }; + } catch (UmbrellaException e){ + return send(ex,e); + } + } + private boolean getPoll(HttpExchange ex, UmbrellaUser user, String id) throws IOException { var poll = pollDb.loadPoll(id); // TODO: check permissions @@ -63,4 +85,32 @@ public class PollModule extends BaseHandler implements PollService { var list = pollDb.listPolls(user).stream().map(Poll::toMap); return sendContent(ex,list); } + + private boolean postToPoll(HttpExchange ex, UmbrellaUser user, String id, Path path) throws IOException { + var poll = pollDb.loadPoll(id); + var permitted = user.equals(poll.owner()); + if (!permitted) { + var permission = poll.shares().get(user); + if (permission == null || permission < 2) throw forbidden(Text.NOT_ALLOWED_TO_EDIT, Field.OBJECT,Text.POLL); + } + var head = path.pop(); + return switch (head){ + case OPTION -> postOption(ex, poll); + default -> notFound(ex); + }; + } + + private boolean postOption(HttpExchange ex, Poll poll) throws IOException { + var json = json(ex); + if (!json.has(Field.NAME) || !(json.get(Field.NAME) instanceof String name)) throw missingField(Field.NAME); + String description = null; + if (json.has(Field.DESCRIPTION)) { + var val = json.get(Field.DESCRIPTION); + if (val instanceof JSONObject j && j.has(Field.SOURCE)) val = j.get(Field.SOURCE); + if (val instanceof String d) description = d; + } + var option = new Poll.Option(0, name, description, 0); + poll.options().add(option); + return sendContent(ex,pollDb.save(poll)); + } } 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 b1df15b8..f9b674bb 100644 --- a/poll/src/main/java/de/srsoftware/umbrella/poll/SqliteDb.java +++ b/poll/src/main/java/de/srsoftware/umbrella/poll/SqliteDb.java @@ -1,14 +1,18 @@ /* © SRSoftware 2025 */ package de.srsoftware.umbrella.poll; +import static de.srsoftware.tools.Optionals.is0; import static de.srsoftware.tools.jdbc.Condition.equal; +import static de.srsoftware.tools.jdbc.Condition.isNull; 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.core.ModuleRegistry.userService; 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.lang.System.Logger.Level.WARNING; import static java.text.MessageFormat.format; import de.srsoftware.umbrella.core.BaseDb; @@ -152,4 +156,33 @@ public class SqliteDb extends BaseDb implements PollDb { throw failedToLoadObject(Text.POLL,id).causedBy(e); } } + + @Override + public Poll save(Poll poll) { + return is0(poll.id()) ? saveNew(poll) : update(poll); + } + + public Poll.Option saveOption(Long pollId, Poll.Option option){ + return is0(option.id()) ? saveNew(pollId, option) : update(pollId, option); + } + + private Poll saveNew(Poll poll) { + throw new RuntimeException("Not implemented"); + } + + private Poll saveNew(long pollId, Poll.Option option) { + throw new RuntimeException("Not implemented"); + } + + private Poll update(Poll poll) { + LOG.log(WARNING,"Updating poll not fully implemented"); + for (var option : poll.options()) saveOption(poll.id(),option); + throw new RuntimeException("Not implemented"); + } + + private Poll update(long pollId, Poll.Option option) { + insertInto(TABLE_OPTIONS) // TODO + throw new RuntimeException("Not implemented"); + } + }