"Fossies" - the Fresh Open Source Software Archive

Member "jitsi-meet-7316/resources/prosody-plugins/mod_polls.lua" (5 Jun 2023, 6779 Bytes) of package /linux/misc/jitsi-meet-7316.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Lua source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 -- This module provides persistence for the "polls" feature,
    2 -- by keeping track of the state of polls in each room, and sending
    3 -- that state to new participants when they join.
    4 
    5 local json = require("util.json");
    6 local st = require("util.stanza");
    7 local jid = require "util.jid";
    8 local util = module:require("util");
    9 local muc = module:depends("muc");
   10 
   11 local NS_NICK = 'http://jabber.org/protocol/nick';
   12 local is_healthcheck_room = util.is_healthcheck_room;
   13 
   14 -- Checks if the given stanza contains a JSON message,
   15 -- and that the message type pertains to the polls feature.
   16 -- If yes, returns the parsed message. Otherwise, returns nil.
   17 local function get_poll_message(stanza)
   18     if stanza.attr.type ~= "groupchat" then
   19         return nil;
   20     end
   21     local json_data = stanza:get_child_text("json-message", "http://jitsi.org/jitmeet");
   22     if json_data == nil then
   23         return nil;
   24     end
   25     local data = json.decode(json_data);
   26     if not data or (data.type ~= "new-poll" and data.type ~= "answer-poll") then
   27         return nil;
   28     end
   29     return data;
   30 end
   31 
   32 -- Logs a warning and returns true if a room does not
   33 -- have poll data associated with it.
   34 local function check_polls(room)
   35     if room.polls == nil then
   36         module:log("warn", "no polls data in room");
   37         return true;
   38     end
   39     return false;
   40 end
   41 
   42 --- Returns a table having occupant id and occupant name.
   43 --- If the id cannot be extracted from nick a nil value is returned
   44 --- if the occupant name cannot be extracted from presence the Fellow Jitster
   45 --- name is used
   46 local function get_occupant_details(occupant)
   47     if not occupant then
   48         return nil
   49     end
   50     local presence = occupant:get_presence();
   51     local occupant_name;
   52     if presence then
   53         occupant_name = presence:get_child("nick", NS_NICK) and presence:get_child("nick", NS_NICK):get_text() or 'Fellow Jitster';
   54     else
   55         occupant_name = 'Fellow Jitster'
   56     end
   57     local _, _, occupant_id = jid.split(occupant.nick)
   58     if not occupant_id then
   59         return nil
   60     end
   61     return { ["occupant_id"] = occupant_id, ["occupant_name"] = occupant_name }
   62 end
   63 
   64 -- Sets up poll data in new rooms.
   65 module:hook("muc-room-created", function(event)
   66     local room = event.room;
   67     if is_healthcheck_room(room.jid) then return end
   68     module:log("debug", "setting up polls in room %s", room.jid);
   69     room.polls = {
   70         by_id = {};
   71         order = {};
   72     };
   73 end);
   74 
   75 -- Keeps track of the current state of the polls in each room,
   76 -- by listening to "new-poll" and "answer-poll" messages,
   77 -- and updating the room poll data accordingly.
   78 -- This mirrors the client-side poll update logic.
   79 module:hook("message/bare", function(event)
   80     local data = get_poll_message(event.stanza);
   81     if data == nil then return end
   82 
   83     local room = muc.get_room_from_jid(event.stanza.attr.to);
   84 
   85     if data.type == "new-poll" then
   86         if check_polls(room) then return end
   87 
   88         local occupant_jid = event.stanza.attr.from;
   89         local occupant = room:get_occupant_by_real_jid(occupant_jid);
   90         if not occupant then
   91             module:log("error", "Occupant %s was not found in room %s", occupant_jid, room.jid)
   92             return
   93         end
   94         local poll_creator = get_occupant_details(occupant)
   95         if not poll_creator then
   96             module:log("error", "Cannot retrieve poll creator id and name for %s from %s", occupant.jid, room.jid)
   97             return
   98         end
   99 
  100         local answers = {}
  101         local compact_answers = {}
  102         for i, name in ipairs(data.answers) do
  103             table.insert(answers, { name = name, voters = {} });
  104             table.insert(compact_answers, { key = i, name = name});
  105         end
  106 
  107         local poll = {
  108             id = data.pollId,
  109             sender_id = poll_creator.occupant_id,
  110             sender_name = poll_creator.occupant_name,
  111             question = data.question,
  112             answers = answers
  113         };
  114 
  115         room.polls.by_id[data.pollId] = poll
  116         table.insert(room.polls.order, poll)
  117 
  118         local pollData = {
  119             event = event,
  120             room = room,
  121             poll = {
  122                 pollId = data.pollId,
  123                 senderId = poll_creator.occupant_id,
  124                 senderName = poll_creator.occupant_name,
  125                 question = data.question,
  126                 answers = compact_answers
  127             }
  128         }
  129         module:fire_event("poll-created", pollData);
  130 
  131     elseif data.type == "answer-poll" then
  132         if check_polls(room) then return end
  133 
  134         local occupant_jid = event.stanza.attr.from;
  135         local occupant = room:get_occupant_by_real_jid(occupant_jid);
  136         if not occupant then
  137             module:log("error", "Occupant %s does not exists for room %s", occupant_jid, room.jid)
  138             return
  139         end
  140         local poll = room.polls.by_id[data.pollId];
  141         if poll == nil then
  142             module:log("warn", "answering inexistent poll");
  143             return;
  144         end
  145 
  146         local voter = get_occupant_details(occupant)
  147         if not voter then
  148             module:log("error", "Cannot retrieve voter id and name for %s from %s", occupant.jid, room.jid)
  149             return
  150         end
  151 
  152         local answers = {};
  153         for vote_option_idx, vote_flag in ipairs(data.answers) do
  154             table.insert(answers, {
  155                 key = vote_option_idx,
  156                 value = vote_flag,
  157                 name = poll.answers[vote_option_idx].name,
  158             });
  159             poll.answers[vote_option_idx].voters[voter.occupant_id] = vote_flag and voter.occupant_name or nil;
  160         end
  161         local answerData = {
  162             event = event,
  163             room = room,
  164             pollId = poll.id,
  165             voterName = voter.occupant_name,
  166             voterId = voter.occupant_id,
  167             answers = answers
  168         }
  169         module:fire_event("answer-poll",  answerData);
  170     end
  171 end);
  172 
  173 -- Sends the current poll state to new occupants after joining a room.
  174 module:hook("muc-occupant-joined", function(event)
  175     local room = event.room;
  176     if is_healthcheck_room(room.jid) then return end
  177     if room.polls == nil or #room.polls.order == 0 then
  178         return
  179     end
  180 
  181     local data = {
  182         type = "old-polls",
  183         polls = {},
  184     };
  185     for i, poll in ipairs(room.polls.order) do
  186         data.polls[i] = {
  187             id = poll.id,
  188             senderId = poll.sender_id,
  189             senderName = poll.sender_name,
  190             question = poll.question,
  191             answers = poll.answers
  192         };
  193     end
  194 
  195     local stanza = st.message({
  196         from = room.jid,
  197         to = event.occupant.jid
  198     })
  199     :tag("json-message", { xmlns = "http://jitsi.org/jitmeet" })
  200     :text(json.encode(data))
  201     :up();
  202     room:route_stanza(stanza);
  203 end);