diff --git a/conversejs/custom/plugins/poll/components/poll-form-view.js b/conversejs/custom/plugins/poll/components/poll-form-view.js index df171595..32110ab7 100644 --- a/conversejs/custom/plugins/poll/components/poll-form-view.js +++ b/conversejs/custom/plugins/poll/components/poll-form-view.js @@ -72,6 +72,7 @@ export default class MUCPollFormView extends CustomElement { const iq = $iq({ type: 'set', + to: this.model.get('jid'), id: u.getUniqueId() }).c('query', { xmlns: XMLNS_POLL }) @@ -83,9 +84,19 @@ export default class MUCPollFormView extends CustomElement { await api.sendIQ(iq) if (this.modal) { - this.modal.hide() + this.modal.onHide() } } catch (err) { + if (u.isErrorStanza(err)) { + // Checking if there is a text error that we can show to the user. + if (sizzle('error bad-request', err).length) { + const text = sizzle('error text', err) + if (text.length) { + this.alert_message = __('Error') + ': ' + text[0].textContent + return + } + } + } console.error(err) this.alert_message = __('Error') } diff --git a/conversejs/custom/plugins/poll/templates/poll-form.js b/conversejs/custom/plugins/poll/templates/poll-form.js index 5316f099..085ea040 100644 --- a/conversejs/custom/plugins/poll/templates/poll-form.js +++ b/conversejs/custom/plugins/poll/templates/poll-form.js @@ -20,13 +20,9 @@ export function tplPollForm (el) { ${el.form_fields} - ${ - el.modal - ? html`` // no need for submit button, the modal will have one in the footer - : html`
- -
` - } +
+ +
` : '' }` diff --git a/prosody-modules/mod_muc_poll/mod_muc_poll.lua b/prosody-modules/mod_muc_poll/mod_muc_poll.lua index 1e12d025..43e809ba 100644 --- a/prosody-modules/mod_muc_poll/mod_muc_poll.lua +++ b/prosody-modules/mod_muc_poll/mod_muc_poll.lua @@ -1,6 +1,8 @@ local st = require "util.stanza"; local dataform = require "util.dataforms"; +local get_form_type = require "util.dataforms".get_type; local jid_bare = require "util.jid".bare; +local get_time = require "util.time".now; local mod_muc = module:depends"muc"; local get_room_from_jid = mod_muc.get_room_from_jid; @@ -25,6 +27,7 @@ local function get_form_layout(room, stanza) label = "Question"; desc = "The poll question."; value = ""; + required = true; }); table.insert(form, { name = "muc#roompoll_duration"; @@ -34,13 +37,13 @@ local function get_form_layout(room, stanza) label = "Poll duration (in minutes)"; desc = "The number of minutes to run the poll."; value = ""; + required = true; }); table.insert(form, { name = "muc#roompoll_anonymous"; - type = "text-single"; + type = "boolean"; label = "Anonymous results"; desc = "By enabling this, user's votes won't be publicly shown in the room."; - value = ""; }); table.insert(form, { name = "muc#roompoll_choice1"; @@ -48,6 +51,7 @@ local function get_form_layout(room, stanza) label = "Choice 1"; desc = ""; value = ""; + required = true; }); table.insert(form, { name = "muc#roompoll_choice2"; @@ -55,6 +59,7 @@ local function get_form_layout(room, stanza) label = "Choice 2"; desc = ""; value = ""; + required = true; }); table.insert(form, { name = "muc#roompoll_choice3"; @@ -88,13 +93,73 @@ local function send_form(room, origin, stanza) ) ; end --- module:hook("iq/bare", function (event) --- local stanza = event.stanza; --- local type = stanza.attr.type; --- local child = stanza.tags[1]; --- local xmlns = child.attr.xmlns or "jabber:client"; --- module:log("info", "coucou %s %s %s", type, xmlns, child.name); --- end, 1000); +local function dataform_error_message(err) + local out = {}; + for field, errmsg in pairs(err) do + table.insert(out, ("%s: %s"):format(field, errmsg)) + end + return table.concat(out, "; "); +end + +local function process_form(room, origin, stanza) + if not stanza.tags[1] then + origin.send(st.error_reply(stanza, "modify", "bad-request")); + return true; + end + local form = stanza.tags[1]:get_child("x", "jabber:x:data"); + if not form then + origin.send(st.error_reply(stanza, "modify", "bad-request")); + return true; + end + + local form_type, err = get_form_type(form); + if not form_type then + origin.send(st.error_reply(stanza, "modify", "bad-request", "Invalid dataform: "..err)); + return true; + elseif form_type ~= xmlns_poll then + origin.send(st.error_reply(stanza, "modify", "bad-request", "Unexpected FORM_TYPE, expected '"..xmlns_poll.."'")); + return true; + end + + if form.attr.type == "cancel" then + origin.send(st.reply(stanza)); + return true; + elseif form.attr.type ~= "submit" then + origin.send(st.error_reply(stanza, "cancel", "bad-request", "Not a submitted form")); + return true; + end + + -- form submitted + local fields, errors, present = get_form_layout(room, stanza.attr.from):data(form); + if errors then + origin.send(st.error_reply(stanza, "modify", "bad-request", dataform_error_message(errors))); + return true; + end + + -- stop any poll that is already here + end_current_poll(room); + + -- create the new poll + create_poll(room, fields); + + origin.send(st.reply(stanza)); + return true; +end + +local function end_current_poll (room) + if not room._data.current_poll then + return; + end + -- TODO: compute and send last result. + room._data.current_poll = nil; +end + +local function create_poll(room, fields) + room._data.current_poll = fields; + room._data.current_poll.end_timestamp = now() + (60 * fields["muc#roompoll_duration"]); + room._data.current_poll.votes = {}; + -- TODO: create and send poll message. +end -- new poll creation, get form module:hook("iq-get/bare/" .. xmlns_poll .. ":query", function (event) @@ -118,6 +183,28 @@ module:hook("iq-get/bare/" .. xmlns_poll .. ":query", function (event) return true; end); + +-- new poll creation, form submission +module:hook("iq-set/bare/" .. xmlns_poll .. ":query", function (event) + local origin, stanza = event.origin, event.stanza; + local room_jid = stanza.attr.to; + module:log("debug", "Received a form submission for the poll form"); + local room = get_room_from_jid(room_jid); + if not room then + origin.send(st.error_reply(stanza, "cancel", "item-not-found")); + return true; + end + local from = jid_bare(stanza.attr.from); + + local from_affiliation = room:get_affiliation(from); + if (from_affiliation ~= "owner" and from_affiliation ~= "admin") then + origin.send(st.error_reply(stanza, "auth", "forbidden")) + return true; + end + + return process_form(room, origin, stanza); +end); + -- Discovering support module:hook("muc-disco#info", function (event) event.reply:tag("feature", { var = xmlns_poll }):up();