Software /
code /
prosody-modules
Comparison
mod_groups_internal/mod_groups_internal.lua @ 5708:9edc698848e9
mod_groups_internal: Update to support multiple MUCs per group
This was a feature request for Snikket.
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Thu, 02 Nov 2023 16:59:44 +0000 |
parent | 4707:27f7ed9f50cd |
child | 5818:5533c577dd02 |
comparison
equal
deleted
inserted
replaced
5707:7c264a2cb970 | 5708:9edc698848e9 |
---|---|
1 local rostermanager = require"core.rostermanager"; | 1 local rostermanager = require"core.rostermanager"; |
2 local modulemanager = require"core.modulemanager"; | 2 local modulemanager = require"core.modulemanager"; |
3 local array = require "util.array"; | |
3 local id = require "util.id"; | 4 local id = require "util.id"; |
4 local jid = require "util.jid"; | 5 local jid = require "util.jid"; |
5 local st = require "util.stanza"; | 6 local st = require "util.stanza"; |
6 local jid_join = jid.join; | 7 local jid_join = jid.join; |
7 local host = module.host; | 8 local host = module.host; |
8 | 9 |
9 local group_info_store = module:open_store("group_info"); | 10 local group_info_store = module:open_store("group_info", "keyval+"); |
10 local group_members_store = module:open_store("groups"); | 11 local group_members_store = module:open_store("groups"); |
11 local group_memberships = module:open_store("groups", "map"); | 12 local group_memberships = module:open_store("groups", "map"); |
12 | 13 |
13 local muc_host_name = module:get_option("groups_muc_host", "groups."..host); | 14 local muc_host_name = module:get_option("groups_muc_host", "groups."..host); |
14 local muc_host = nil; | 15 local muc_host = nil; |
74 module:hook("resource-bind", function(event) | 75 module:hook("resource-bind", function(event) |
75 module:log("debug", "Updating group subscriptions..."); | 76 module:log("debug", "Updating group subscriptions..."); |
76 do_all_group_subscriptions_by_user(event.session.username); | 77 do_all_group_subscriptions_by_user(event.session.username); |
77 end); | 78 end); |
78 | 79 |
80 local function _create_muc_room(name) | |
81 if not muc_host_name then | |
82 module:log("error", "cannot create group MUC: no MUC host configured") | |
83 return nil, "service-unavailable" | |
84 end | |
85 if not muc_host then | |
86 module:log("error", "cannot create group MUC: MUC host %s not configured properly", muc_host_name) | |
87 return nil, "internal-server-error" | |
88 end | |
89 | |
90 local muc_jid = jid.prep(id.short() .. "@" .. muc_host_name); | |
91 local room = muc_host.create_room(muc_jid) | |
92 if not room then | |
93 return nil, "internal-server-error" | |
94 end | |
95 | |
96 local ok = pcall(function () | |
97 room:set_public(false); | |
98 room:set_persistent(true); | |
99 room:set_members_only(true); | |
100 room:set_allow_member_invites(false); | |
101 room:set_moderated(false); | |
102 room:set_whois("anyone"); | |
103 room:set_name(name); | |
104 end); | |
105 | |
106 if not ok then | |
107 module:log("error", "Failed to configure group MUC %s", muc_jid); | |
108 room:destroy(); | |
109 return nil, "internal-server-error"; | |
110 end | |
111 | |
112 return muc_jid, room; | |
113 end | |
114 | |
79 --luacheck: ignore 131 | 115 --luacheck: ignore 131 |
80 function create(group_info, create_muc, group_id) | 116 function create(group_info, create_default_muc, group_id) |
81 if not group_info.name then | 117 if not group_info.name then |
82 return nil, "group-name-required"; | 118 return nil, "group-name-required"; |
83 end | 119 end |
84 if group_id then | 120 if group_id then |
85 if exists(group_id) then | 121 if exists(group_id) then |
89 group_id = id.short(); | 125 group_id = id.short(); |
90 end | 126 end |
91 | 127 |
92 local muc_jid = nil | 128 local muc_jid = nil |
93 local room = nil | 129 local room = nil |
94 if create_muc then | 130 if create_default_muc then |
95 if not muc_host_name then | 131 muc_jid, room = _create_muc_room(group_info.name); |
96 module:log("error", "cannot create group with MUC: no MUC host configured") | 132 if not muc_jid then |
97 return nil, "service-unavailable" | 133 -- MUC creation failed, fail to create group |
98 end | |
99 if not muc_host then | |
100 module:log("error", "cannot create group with MUC: MUC host %s not configured properly", muc_host_name) | |
101 return nil, "internal-server-error" | |
102 end | |
103 | |
104 muc_jid = jid.prep(id.short() .. "@" .. muc_host_name); | |
105 room = muc_host.create_room(muc_jid) | |
106 if not room then | |
107 delete(group_id) | 134 delete(group_id) |
108 return nil, "internal-server-error" | 135 return nil, room; |
109 end | 136 end |
110 room:set_public(false) | |
111 room:set_persistent(true) | |
112 room:set_members_only(true) | |
113 room:set_allow_member_invites(false) | |
114 room:set_moderated(false) | |
115 room:set_whois("anyone") | |
116 room:set_name(group_info.name) | |
117 end | 137 end |
118 | 138 |
119 local ok = group_info_store:set(group_id, { | 139 local ok = group_info_store:set(group_id, { |
120 name = group_info.name; | 140 name = group_info.name; |
121 muc_jid = muc_jid; | 141 muc_jid = muc_jid; |
156 end | 176 end |
157 return true | 177 return true |
158 end | 178 end |
159 | 179 |
160 function get_members(group_id) | 180 function get_members(group_id) |
161 return group_members_store:get(group_id); | 181 return group_members_store:get(group_id) or {}; |
162 end | 182 end |
163 | 183 |
164 function exists(group_id) | 184 function exists(group_id) |
165 return not not get_info(group_id); | 185 return not not get_info(group_id); |
166 end | 186 end |
262 | 282 |
263 function sync(group_id) | 283 function sync(group_id) |
264 do_all_group_subscriptions_by_group(group_id); | 284 do_all_group_subscriptions_by_group(group_id); |
265 end | 285 end |
266 | 286 |
287 function add_group_chat(group_id, name) | |
288 local group_info = group_info_store:get(group_id); | |
289 local mucs = group_info.mucs or {}; | |
290 | |
291 -- Create the MUC | |
292 local muc_jid, room = _create_muc_room(name); | |
293 if not muc_jid then return nil, room; end | |
294 table.insert(mucs, muc_jid); | |
295 if group_info.muc_jid then -- COMPAT include old muc_jid into array | |
296 table.insert(mucs, group_info.muc_jid); | |
297 end | |
298 local store_ok, store_err = group_info_store:set_key(group_id, "mucs", mucs); | |
299 if not store_ok then | |
300 module:log("error", "Failed to store new MUC association: %s", store_err); | |
301 room:destroy(); | |
302 return nil, "internal-server-error"; | |
303 end | |
304 | |
305 -- COMPAT: clear old muc_jid (it's now in mucs array) | |
306 if group_info.muc_jid then | |
307 module:log("debug", "Clearing old single-MUC JID"); | |
308 group_info.muc_jid = nil; | |
309 group_info_store:set_key(group_id, "muc_jid", nil); | |
310 end | |
311 | |
312 -- Make existing group members, members of the MUC | |
313 for username in pairs(get_members(group_id)) do | |
314 local user_jid = username .. "@" ..module.host; | |
315 room:set_affiliation(true, user_jid, "member"); | |
316 module:send(st.message( | |
317 { from = muc_jid, to = user_jid } | |
318 ):tag("x", { | |
319 xmlns = "jabber:x:conference", | |
320 jid = muc_jid | |
321 }):up()); | |
322 module:log("debug", "set user %s to be member in %s and sent invite", user_jid, muc_jid); | |
323 end | |
324 | |
325 -- Notify other modules (such as mod_groups_muc_bookmarks) | |
326 local muc = { | |
327 jid = muc_jid; | |
328 name = name; | |
329 }; | |
330 | |
331 module:fire_event("group-chat-added", { | |
332 group_id = group_id; | |
333 group_info = group_info; | |
334 muc = muc; | |
335 }); | |
336 | |
337 return muc; | |
338 end | |
339 | |
340 function remove_group_chat(group_id, muc_id) | |
341 local group_info = group_info_store:get(group_id); | |
342 if not group_info then | |
343 return nil, "group-not-found"; | |
344 end | |
345 | |
346 local mucs = group_info.mucs; | |
347 if not mucs then | |
348 if not group_info.muc_jid then | |
349 return true; | |
350 end | |
351 -- COMPAT with old single-MUC groups - upgrade to new format | |
352 mucs = {}; | |
353 end | |
354 if group_info.muc_jid then | |
355 table.insert(mucs, group_info.muc_jid); | |
356 end | |
357 | |
358 local removed; | |
359 for i, muc_jid in ipairs(mucs) do | |
360 if muc_id == jid.node(muc_jid) then | |
361 removed = table.remove(mucs, i); | |
362 break; | |
363 end | |
364 end | |
365 | |
366 if removed then | |
367 if not group_info_store:set_key(group_id, "mucs", mucs) then | |
368 return nil, "internal-server-error"; | |
369 end | |
370 | |
371 if group_info.muc_jid then | |
372 -- COMPAT: Now we've set the array, clean up muc_jid | |
373 group_info.muc_jid = nil; | |
374 group_info_store:set_key(group_id, "muc_jid", nil); | |
375 end | |
376 | |
377 module:log("debug", "Updated group MUC list"); | |
378 | |
379 local room = muc_host.get_room_from_jid(removed); | |
380 if room then | |
381 room:destroy(); | |
382 else | |
383 module:log("warn", "Removing a group chat, but associated MUC not found (%s)", removed); | |
384 end | |
385 | |
386 module:fire_event( | |
387 "group-chat-removed", | |
388 { | |
389 group_id = group_id; | |
390 group_info = group_info; | |
391 muc = { | |
392 id = muc_id; | |
393 jid = removed; | |
394 }; | |
395 } | |
396 ); | |
397 else | |
398 module:log("warn", "Removal of a group chat that can't be found - %s", muc_id); | |
399 end | |
400 | |
401 return true; | |
402 end | |
403 | |
404 function get_group_chats(group_id) | |
405 local group_info, err = group_info_store:get(group_id); | |
406 if not group_info then | |
407 module:log("debug", "Unable to load group info: %s - %s", group_id, err); | |
408 return nil; | |
409 end | |
410 | |
411 local mucs = group_info.mucs or {}; | |
412 | |
413 -- COMPAT with single-MUC groups | |
414 if group_info.muc_jid then | |
415 table.insert(mucs, group_info.muc_jid); | |
416 end | |
417 | |
418 return array.map(mucs, function (muc_jid) | |
419 return { | |
420 id = jid.node(muc_jid); | |
421 jid = muc_jid; | |
422 name = muc_host.get_room_from_jid(muc_jid):get_name(); | |
423 }; | |
424 end); | |
425 end | |
426 | |
267 function emit_member_events(group_id) | 427 function emit_member_events(group_id) |
268 local group_info, err = get_info(group_id) | 428 local group_info, err = get_info(group_id) |
269 if group_info == nil then | 429 if group_info == nil then |
270 return false, err | 430 return false, err |
271 end | 431 end |
285 return true | 445 return true |
286 end | 446 end |
287 | 447 |
288 -- Returns iterator over group ids | 448 -- Returns iterator over group ids |
289 function groups() | 449 function groups() |
290 return group_info_store:users(); | 450 return group_info_store:items(); |
291 end | 451 end |
292 | 452 |
293 local function setup() | 453 local function setup() |
294 if not muc_host_name then | 454 if not muc_host_name then |
295 module:log("info", "MUC management disabled (groups_muc_host set to nil)"); | 455 module:log("info", "MUC management disabled (groups_muc_host set to nil)"); |