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 15f03df1..c22ac312 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 @@ -51,6 +51,7 @@ public class Field { public static final String DUE_DATE = "due_date"; public static final String DURATION = "duration"; + public static final String EDITOR = "editor"; public static final String EMAIL = "email"; public static final String END_TIME = "end_time"; public static final String ENTITY_ID = "entity_id"; @@ -131,6 +132,7 @@ public class Field { public static final String RENDERED = "rendered"; public static final String REQUIRED_TASKS_IDS = "required_tasks_ids"; + public static final String SELECTION = "selection"; public static final String SENDER = "sender"; public static final String SENDER_USER_ID = "sender_user_id"; public static final String SETTINGS = "settings"; 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 dc00e11f..cba6f172 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 @@ -41,6 +41,7 @@ public class Path { public static final String REDIRECT = "redirect"; public static final String SEARCH = "search"; + public static final String SELECT = "select"; public static final String SETTINGS = "settings"; public static final String STATES = "states"; public static final String STARTED = "started"; 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 574048e9..259e9f3c 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 @@ -58,6 +58,7 @@ public class Text { public static final String RECEIVER = "receiver"; public static final String RECEIVERS = "receivers"; + public static final String SELECTIONS = "selections"; public static final String SENDER = "sender"; public static final String SERVICE_WITH_ID = "service ({id})"; public static final String SESSION = "session"; diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte index d7ab0546..c001e524 100644 --- a/frontend/src/App.svelte +++ b/frontend/src/App.svelte @@ -40,6 +40,7 @@ import Times from "./routes/time/Index.svelte"; import User from "./routes/user/User.svelte"; import ViewDoc from "./routes/document/View.svelte"; + import ViewPoll from "./routes/poll/View.svelte"; import ViewPrj from "./routes/project/View.svelte"; import ViewTask from "./routes/task/View.svelte"; import WikiIndex from "./routes/wiki/Index.svelte"; @@ -101,6 +102,7 @@ + diff --git a/frontend/src/routes/poll/Index.svelte b/frontend/src/routes/poll/Index.svelte index a066e86f..8e808913 100644 --- a/frontend/src/routes/poll/Index.svelte +++ b/frontend/src/routes/poll/Index.svelte @@ -40,7 +40,12 @@ } else error(res); } + function open(poll){ + router.navigate(`/poll/${poll.id}/view`); + } + function share(poll){ + } onMount(load); @@ -61,9 +66,9 @@ {#each polls as poll} - {poll.name} + open(poll)}>{poll.name} {@html poll.description.rendered} - {poll.owner.name} + open(poll)}>{poll.owner.name} {#if user.id == poll.owner.id || poll.shares[user.id].permission == 2} diff --git a/frontend/src/routes/poll/View.svelte b/frontend/src/routes/poll/View.svelte new file mode 100644 index 00000000..d9181d10 --- /dev/null +++ b/frontend/src/routes/poll/View.svelte @@ -0,0 +1,103 @@ + + + + +
+ {t('User')} +{#if user} +
{t('logged in as: {user}',{user:user.name})}
+{:else} + +{/if} +
+{#if poll} +
+ {t('poll')}: {poll.name} +
+ {@html poll.description.rendered} +
+ + + + + {#each Object.entries(poll.weights) as [weight,name]} + + {/each} + + + + {#each poll.options as option} + + + {#each Object.entries(poll.weights) as [weight,name]} + + {/each} + + {/each} + +
{t('option')} + {weight} + + {name} + +
+ {option.name} + + {@html option.description.rendered} + + select(option,weight)} title={t('click to select')} > + {#if selection[option.id] == weight} + X + {/if} +
+ {#if Object.keys(selection).length} + + {/if} +
+
TODO: add notes
+{/if} \ No newline at end of file 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 ace5e596..b49f8633 100644 --- a/poll/src/main/java/de/srsoftware/umbrella/poll/PollDb.java +++ b/poll/src/main/java/de/srsoftware/umbrella/poll/PollDb.java @@ -3,8 +3,10 @@ package de.srsoftware.umbrella.poll; import de.srsoftware.umbrella.core.model.Poll; import de.srsoftware.umbrella.core.model.UmbrellaUser; +import org.json.JSONObject; import java.util.Collection; +import java.util.Map; public interface PollDb { Collection listPolls(UmbrellaUser user); @@ -12,4 +14,7 @@ public interface PollDb { Poll loadPoll(String id); Poll save(Poll poll); + + void saveSelection(Poll poll, Map optionsToWeights, String guestName); + void saveSelection(Poll poll, Map optionsToWeights, 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 9d4c2c56..cc1396e6 100644 --- a/poll/src/main/java/de/srsoftware/umbrella/poll/PollModule.java +++ b/poll/src/main/java/de/srsoftware/umbrella/poll/PollModule.java @@ -8,6 +8,7 @@ import static de.srsoftware.umbrella.core.constants.Field.ID; import static de.srsoftware.umbrella.core.constants.Path.*; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; import static de.srsoftware.umbrella.poll.Constants.CONFIG_DATABASE; +import static java.text.MessageFormat.format; import com.sun.net.httpserver.HttpExchange; import de.srsoftware.configuration.Configuration; @@ -25,6 +26,7 @@ import de.srsoftware.umbrella.core.model.UmbrellaUser; import org.json.JSONObject; import java.io.IOException; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -81,12 +83,11 @@ public class PollModule extends BaseHandler implements PollService { addCors(ex); try { Optional token = SessionToken.from(ex).map(Token::of); - var user = userService().loadUser(token); - if (user.isEmpty()) return unauthorized(ex); + var user = userService().loadUser(token).orElse(null ); var head = path.pop(); return switch (head) { - case null -> postNewPoll(ex,user.get()); - default -> postToPoll(ex,user.get(),head, path); + case null -> postNewPoll(ex,user); + default -> postToPoll(ex, user, head, path); }; } catch (UmbrellaException e){ return send(ex,e); @@ -185,6 +186,7 @@ public class PollModule extends BaseHandler implements PollService { } private boolean postNewPoll(HttpExchange ex, UmbrellaUser user) throws IOException { + if (user == null) return unauthorized(ex); var json = json(ex); if (!json.has(Field.NAME)) throw missingField(Field.NAME); var name = json.getString(Field.NAME); @@ -193,6 +195,7 @@ public class PollModule extends BaseHandler implements PollService { } private boolean postToPoll(HttpExchange ex, UmbrellaUser user, String id, Path path) throws IOException { + if (user == null) return unauthorized(ex); var poll = pollDb.loadPoll(id); var permitted = user.equals(poll.owner()); if (!permitted) { @@ -202,10 +205,33 @@ public class PollModule extends BaseHandler implements PollService { var head = path.pop(); return switch (head){ case OPTION -> postOption(ex, poll); + case SELECT -> postSelection(ex, poll, user); case null, default -> notFound(ex); }; } + private boolean postSelection(HttpExchange ex, Poll poll, UmbrellaUser user) throws IOException { + var json = json(ex); + if (!json.has(Field.SELECTION)) throw missingField(Field.SELECTION); + if (!(json.get(Field.SELECTION) instanceof JSONObject job)) throw invalidField(Field.SELECTION,JSON); + var map = new HashMap(); + for (var key : job.keySet()){ + var optionId = Integer.parseInt(key); + if (!(job.get(key) instanceof Integer weight)) throw invalidField(Field.WEIGHT,Text.NUMBER); + map.put(optionId,weight); + } + if (user != null) { + pollDb.saveSelection(poll, map, user); + } else { + if (!json.has(Field.EDITOR)) throw missingField(Field.EDITOR); + if (!(json.get(Field.EDITOR) instanceof JSONObject editor)) throw invalidField(Field.EDITOR,JSON); + if (!editor.has(Field.NAME)) throw missingField(format("{0}.{1}}",Field.EDITOR,Field.NAME)); + if (!(editor.get(Field.NAME) instanceof String name)) throw invalidField(format("{0}.{1}",Field.EDITOR,Field.NAME),Text.STRING); + pollDb.saveSelection(poll, map, name); + } + return 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); 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 6387ffa3..a69e5e7d 100644 --- a/poll/src/main/java/de/srsoftware/umbrella/poll/SqliteDb.java +++ b/poll/src/main/java/de/srsoftware/umbrella/poll/SqliteDb.java @@ -15,6 +15,7 @@ import static java.text.MessageFormat.format; import de.srsoftware.umbrella.core.BaseDb; 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.UmbrellaUser; @@ -206,6 +207,30 @@ public class SqliteDb extends BaseDb implements PollDb { return option; } + @Override + public void saveSelection(Poll poll, Map optionsToWeights, String guestName) { + saveSelection(poll.id(), optionsToWeights, guestName); + } + + @Override + public void saveSelection(Poll poll, Map optionsToWeights, UmbrellaUser user) { + saveSelection(poll.id(), optionsToWeights, user.id()); + } + + private void saveSelection(String pollId, Map optionsToWeights, Object editor) { + var query = insertInto(TABLE_SELECTIONS,POLL_ID,OPTION_ID,USER_ID,WEIGHT); + for (var entry : optionsToWeights.entrySet()){ + var optionId = entry.getKey(); + var weight = entry.getValue(); + query.values(pollId,optionId,editor,weight); + } + try { + query.execute(db).close(); + } catch (SQLException sqle){ + throw UmbrellaException.failedToStoreObject(Text.SELECTIONS); + } + } + private Poll update(Poll poll) { if (poll.isDirty(NAME, DESCRIPTION)) try { replaceInto(TABLE_POLLS,ID,Field.USER_ID,NAME,DESCRIPTION).values(poll.id(),poll.owner().id(),poll.name(),poll.description()).execute(db); diff --git a/translations/src/main/resources/de.json b/translations/src/main/resources/de.json index 3eaabea6..95f48625 100644 --- a/translations/src/main/resources/de.json +++ b/translations/src/main/resources/de.json @@ -196,6 +196,7 @@ "locality": "Ort", "location": "Ort", "locations": "Orte", + "logged in as: {user}": "Anegemeldet als: {user}", "login" : "Anmeldung", "login service": "Login-Service", "login_services": "Login-Services", diff --git a/translations/src/main/resources/en.json b/translations/src/main/resources/en.json index 5bc60bb4..539dccd9 100644 --- a/translations/src/main/resources/en.json +++ b/translations/src/main/resources/en.json @@ -196,6 +196,7 @@ "locality": "locality", "location": "location", "locations": "locations", + "logged in as: {user}": "logged in as: {user}", "login" : "login", "login service": "login service", "login_services": "login service",