From 212076c3a35aba1ca01d2f24e7ff46ff0b6bee79 Mon Sep 17 00:00:00 2001 From: John Livingston Date: Sun, 30 Jun 2024 17:19:14 +0200 Subject: [PATCH] Poll WIP (#231): * poll backend WIP --- prosody-modules/mod_muc_poll/form.lib.lua | 4 +- prosody-modules/mod_muc_poll/message.lib.lua | 61 ++++++++++++++++++- prosody-modules/mod_muc_poll/mod_muc_poll.lua | 16 +++-- prosody-modules/mod_muc_poll/poll.lib.lua | 11 +++- 4 files changed, 82 insertions(+), 10 deletions(-) diff --git a/prosody-modules/mod_muc_poll/form.lib.lua b/prosody-modules/mod_muc_poll/form.lib.lua index 47466e85..c86b7c3b 100644 --- a/prosody-modules/mod_muc_poll/form.lib.lua +++ b/prosody-modules/mod_muc_poll/form.lib.lua @@ -102,7 +102,7 @@ local function dataform_error_message(err) end -local function process_form(room, origin, stanza) +local function process_form(room, origin, stanza, occupant) if not stanza.tags[1] then origin.send(st.error_reply(stanza, "modify", "bad-request")); return true; @@ -141,7 +141,7 @@ local function process_form(room, origin, stanza) end_current_poll(room); -- create the new poll - create_poll(room, fields); + create_poll(room, fields, occupant); origin.send(st.reply(stanza)); return true; diff --git a/prosody-modules/mod_muc_poll/message.lib.lua b/prosody-modules/mod_muc_poll/message.lib.lua index 884e6258..feb94b42 100644 --- a/prosody-modules/mod_muc_poll/message.lib.lua +++ b/prosody-modules/mod_muc_poll/message.lib.lua @@ -1,12 +1,71 @@ -- SPDX-FileCopyrightText: 2024 John Livingston -- SPDX-License-Identifier: AGPL-3.0-only +local id = require "util.id"; +local st = require "util.stanza"; +local format = require"util.format".format; +local xmlns_occupant_id = "urn:xmpp:occupant-id:0"; + +local function build_poll_message(room, message_id) + local current_poll = room._data.current_poll; + if not current_poll then + return nil; + end + local from = room.jid .. '/' .. current_poll.occupant_nick; + + local content = current_poll["muc#roompoll_question"] .. "\n"; + + local total = 0; + for choice, nb in pairs(current_poll.votes_by_choices) do + total = total + nb; + end + for choice, label in pairs(current_poll.choices) do + content = content .. choice .. ': ' .. label; + if total > 0 then + local nb = current_poll.votes_by_choices[choice] or 0; + local percent = format("%d.%d%d", nb * 100 / total); + content = content .. " (" .. nb .. "/" .. total .. " = " .. percent .. "%)"; + end + content = content .. "\n"; + end + content = content .. "Send a message with an exclamation mark followed by your choice number to vote. Example: !1\n"; + + local msg = st.message({ + type = "groupchat", + from = from, + id = message_id + }, content); + + msg:tag("occupant-id", { + xmlns = xmlns_occupant_id, + id = current_poll.occupant_id + }):up(); + + return msg; +end + local function poll_start_message(room) - -- TODO + if not room._data.current_poll then + return nil; + end + module:log("debug", "Sending the start message for room %s poll", room.jid); + local message_id = id.medium(); + local msg = build_poll_message(room, message_id); + room:broadcast_message(msg); + return message_id; end local function schedule_poll_update_message(room) -- TODO + + -- if not room._data.current_poll then + -- return nil; + -- end + -- module:log("debug", "Sending an update message for room %s poll", room.jid); + -- local message_id = id.medium(); + -- local msg = build_poll_message(room, message_id); + -- room:broadcast_message(msg); + -- return message_id; end local function poll_end_message(room) diff --git a/prosody-modules/mod_muc_poll/mod_muc_poll.lua b/prosody-modules/mod_muc_poll/mod_muc_poll.lua index 2d8fef3b..b8afaf61 100644 --- a/prosody-modules/mod_muc_poll/mod_muc_poll.lua +++ b/prosody-modules/mod_muc_poll/mod_muc_poll.lua @@ -47,21 +47,29 @@ end); 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 from = stanza.attr.from; + module:log("debug", "Received a form submission for the poll form on %s from %s", room_jid, from); 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); + local occupant = room:get_occupant_by_real_jid(from); + if not occupant then + module:log("debug", "No occupant, ignoring..."); + origin.send(st.error_reply(stanza, "auth", "forbidden")) + return true; + end + + local from_bare = jid_bare(stanza.attr.from); + local from_affiliation = room:get_affiliation(from_bare); 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); + return process_form(room, origin, stanza, occupant); end); -- Discovering support diff --git a/prosody-modules/mod_muc_poll/poll.lib.lua b/prosody-modules/mod_muc_poll/poll.lib.lua index c6ff9757..6d15a8bd 100644 --- a/prosody-modules/mod_muc_poll/poll.lib.lua +++ b/prosody-modules/mod_muc_poll/poll.lib.lua @@ -90,22 +90,27 @@ local function schedule_poll_end (room_jid, timestamp) end); end -local function create_poll(room, fields) - module:log("debug", "Creating a new poll for room %s", room.jid); +local function create_poll(room, fields, occupant) + module:log("debug", "Creating a new poll for room %s, by %s", room.jid, occupant.bare_jid); room._data.current_poll = fields; room._data.current_poll.end_timestamp = get_time() + (60 * fields["muc#roompoll_duration"]); room._data.current_poll.votes_by_occupant = {}; room._data.current_poll.votes_by_choices = {}; + room._data.current_poll.choices = {}; room._data.current_poll.already_ended = false; + room._data.current_poll.occupant_bare_jid = occupant.bare_jid; + room._data.current_poll.occupant_nick = occupant.nick; + room._data.current_poll.occupant_id = room:get_occupant_id(occupant); for field, _ in pairs(fields) do local c = field:match("^muc#roompoll_choice(%d+)$"); if c then if fields["muc#roompoll_choice" .. c]:find("%S") then room._data.current_poll.votes_by_choices[c] = 0; + room._data.current_poll.choices[c] = fields["muc#roompoll_choice" .. c]; end end end - poll_start_message(room); + room._data.current_poll.start_message_id = poll_start_message(room); schedule_poll_end(room.jid, room._data.current_poll.end_timestamp); end