"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);