comparison mod_groups_muc_bookmarks/mod_groups_muc_bookmarks.lua @ 4425:b3e0295e14a3

mod_groups_muc_bookmarks: manage PEP (XEP-0048) bookmarks of group members
author Jonas Schäfer <jonas@wielicki.name>
date Wed, 03 Feb 2021 18:03:12 +0100
parents
children 240fa534f586
comparison
equal deleted inserted replaced
4424:679be18e6a5e 4425:b3e0295e14a3
1 local jid_split = require "util.jid".split;
2
3 local st = require "util.stanza";
4
5 local mod_groups = module:depends("groups_internal")
6 local mod_pep = module:depends("pep")
7
8 local PUBSUB_NODE_XEP0048 = "storage:bookmarks";
9 local XMLNS_XEP0048 = "storage:bookmarks";
10 local XMLNS_XEP0060 = "http://jabber.org/protocol/pubsub";
11
12 local default_options = {
13 ["persist_items"] = true;
14 ["access_model"] = "whitelist";
15 };
16
17 local function get_current_bookmarks(jid, service)
18 local ok, id, item = service:get_last_item(PUBSUB_NODE_XEP0048, jid)
19 if not ok or id == nil then
20 if id == "item-not-found" or id == nil then
21 -- return empty
22 return st.stanza("storage", { xmlns = XMLNS_XEP0048 });
23 end
24 return nil, result
25 end
26 -- first item is the actual storage element
27 local hit = item:get_child("storage", XMLNS_XEP0048);
28 if not hit then
29 return nil, "internal-server-error"
30 end
31 return hit
32 end
33
34 local function update_bookmarks(jid, service, storage)
35 local item = st.stanza("item", { xmlns = XMLNS_XEP0060, id = "current" }):add_child(storage)
36 module:log("debug", "updating bookmarks with %q", item)
37 local ok, err = service:publish(
38 PUBSUB_NODE_XEP0048,
39 jid,
40 "current",
41 item,
42 default_options
43 )
44 if not ok then
45 module:log("error", "failed to update bookmarks: %s", err)
46 end
47 end
48
49 local function find_matching_bookmark(storage, room)
50 for node in storage:childtags("conference") do
51 if node.attr.jid == room then
52 return node
53 end
54 end
55 return nil
56 end
57
58 local function inject_bookmark(jid, room, autojoin, name)
59 local pep_service = mod_pep.get_pep_service(jid_split(jid))
60
61 autojoin = autojoin or false and true
62 local current = get_current_bookmarks(jid, pep_service)
63 local existing = find_matching_bookmark(current, room)
64 if existing then
65 if autojoin ~= nil then
66 existing.attr.autojoin = autojoin and "true" or "false"
67 end
68 if name ~= nil then
69 -- do not change already configured names
70 if not existing.attr.name then
71 existing.attr.name = name
72 end
73 end
74 done = true
75 module:log("debug", "found existing matching bookmark, updated")
76 else
77 module:log("debug", "no existing bookmark found, adding new")
78 current:tag("conference", {
79 name = name,
80 autojoin = autojoin and "true" or "false",
81 jid = room,
82 xmlns = XMLNS_XEP0048,
83 })
84 end
85
86 update_bookmarks(jid, pep_service, current)
87 end
88
89 local function remove_bookmark(jid, room, autojoin, name)
90 local pep_service = mod_pep.get_pep_service(jid_split(jid))
91
92 autojoin = autojoin or false and true
93 local current = get_current_bookmarks(jid, pep_service)
94 current:maptags(function (node)
95 if node.attr.xmlns and node.attr.xmlns ~= XMLNS_XEP0048 then
96 return node
97 end
98 if node.name ~= "conference" then
99 return node
100 end
101 if node.attr.jid == room then
102 -- remove matching bookmark
103 return nil
104 end
105 return node
106 end)
107
108 update_bookmarks(jid, pep_service, current)
109 end
110
111 local function handle_user_added(event)
112 if not event.group_info.muc_jid then
113 module:log("debug", "ignoring user added event on group %s because it has no MUC", event.id)
114 return
115 end
116 local jid = event.user .. "@" .. event.host
117 inject_bookmark(jid, event.group_info.muc_jid, true, event.group_info.name)
118 end
119
120 local function handle_user_removed(event)
121 if not event.group_info.muc_jid then
122 module:log("debug", "ignoring user removed event on group %s because it has no MUC", event.id)
123 return
124 end
125 -- Removing the bookmark is fine as the user just lost any privilege to
126 -- be in the MUC (as group MUCs are members-only).
127 local jid = event.user .. "@" .. event.host
128 remove_bookmark(jid, event.group_info.muc_jid, true, event.group_info.name)
129 end
130
131 module:hook("group-user-added", handle_user_added)
132 module:hook("group-user-removed", handle_user_removed)