選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

mod_polls.lua 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  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. local json = require("util.json");
  5. local st = require("util.stanza");
  6. local util = module:require("util");
  7. local muc = module:depends("muc");
  8. local is_healthcheck_room = util.is_healthcheck_room;
  9. -- Checks if the given stanza contains a JSON message,
  10. -- and that the message type pertains to the polls feature.
  11. -- If yes, returns the parsed message. Otherwise, returns nil.
  12. local function get_poll_message(stanza)
  13. if stanza.attr.type ~= "groupchat" then
  14. return nil;
  15. end
  16. local json_data = stanza:get_child_text("json-message", "http://jitsi.org/jitmeet");
  17. if json_data == nil then
  18. return nil;
  19. end
  20. local data = json.decode(json_data);
  21. if data.type ~= "new-poll" and data.type ~= "answer-poll" then
  22. return nil;
  23. end
  24. return data;
  25. end
  26. -- Logs a warning and returns true if a room does not
  27. -- have poll data associated with it.
  28. local function check_polls(room)
  29. if room.polls == nil then
  30. module:log("warn", "no polls data in room");
  31. return true;
  32. end
  33. return false;
  34. end
  35. -- Sets up poll data in new rooms.
  36. module:hook("muc-room-created", function(event)
  37. local room = event.room;
  38. if is_healthcheck_room(room.jid) then return end
  39. module:log("debug", "setting up polls in room "..tostring(room));
  40. room.polls = {
  41. by_id = {};
  42. order = {};
  43. };
  44. end);
  45. -- Keeps track of the current state of the polls in each room,
  46. -- by listening to "new-poll" and "answer-poll" messages,
  47. -- and updating the room poll data accordingly.
  48. -- This mirrors the client-side poll update logic.
  49. module:hook("message/bare", function(event)
  50. local data = get_poll_message(event.stanza);
  51. if data == nil then return end
  52. local room = muc.get_room_from_jid(event.stanza.attr.to);
  53. if data.type == "new-poll" then
  54. if check_polls(room) then return end
  55. local answers = {}
  56. for _, name in ipairs(data.answers) do
  57. table.insert(answers, { name = name, voters = {} });
  58. end
  59. local poll = {
  60. id = data.pollId,
  61. sender_id = data.senderId,
  62. sender_name = data.senderName,
  63. question = data.question,
  64. answers = answers
  65. };
  66. room.polls.by_id[data.pollId] = poll
  67. table.insert(room.polls.order, poll)
  68. elseif data.type == "answer-poll" then
  69. if check_polls(room) then return end
  70. local poll = room.polls.by_id[data.pollId];
  71. if poll == nil then
  72. module:log("warn", "answering inexistent poll");
  73. return;
  74. end
  75. for i, value in ipairs(data.answers) do
  76. poll.answers[i].voters[data.voterId] = value and data.voterName or nil;
  77. end
  78. end
  79. end);
  80. -- Sends the current poll state to new occupants after joining a room.
  81. module:hook("muc-occupant-joined", function(event)
  82. local room = event.room;
  83. if is_healthcheck_room(room.jid) then return end
  84. if room.polls == nil or #room.polls.order == 0 then
  85. return
  86. end
  87. local data = {
  88. type = "old-polls",
  89. polls = {},
  90. };
  91. for i, poll in ipairs(room.polls.order) do
  92. data.polls[i] = {
  93. id = poll.id,
  94. senderId = poll.sender_id,
  95. senderName = poll.sender_name,
  96. question = poll.question,
  97. answers = poll.answers
  98. };
  99. end
  100. local stanza = st.message({
  101. from = room.jid,
  102. to = event.occupant.jid
  103. })
  104. :tag("json-message", { xmlns = "http://jitsi.org/jitmeet" })
  105. :text(json.encode(data))
  106. :up();
  107. room:route_stanza(stanza);
  108. end);