changeset 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 679be18e6a5e
children 3fe2c264aac4
files mod_groups_muc_bookmarks/mod_groups_muc_bookmarks.lua
diffstat 1 files changed, 132 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_groups_muc_bookmarks/mod_groups_muc_bookmarks.lua	Wed Feb 03 18:03:12 2021 +0100
@@ -0,0 +1,132 @@
+local jid_split = require "util.jid".split;
+
+local st = require "util.stanza";
+
+local mod_groups = module:depends("groups_internal")
+local mod_pep = module:depends("pep")
+
+local PUBSUB_NODE_XEP0048 = "storage:bookmarks";
+local XMLNS_XEP0048 = "storage:bookmarks";
+local XMLNS_XEP0060 = "http://jabber.org/protocol/pubsub";
+
+local default_options = {
+	["persist_items"] = true;
+	["access_model"] = "whitelist";
+};
+
+local function get_current_bookmarks(jid, service)
+	local ok, id, item = service:get_last_item(PUBSUB_NODE_XEP0048, jid)
+	if not ok or id == nil then
+		if id == "item-not-found" or id == nil then
+			-- return empty
+			return st.stanza("storage", { xmlns = XMLNS_XEP0048 });
+		end
+		return nil, result
+	end
+	-- first item is the actual storage element
+	local hit = item:get_child("storage", XMLNS_XEP0048);
+	if not hit then
+		return nil, "internal-server-error"
+	end
+	return hit
+end
+
+local function update_bookmarks(jid, service, storage)
+	local item = st.stanza("item", { xmlns = XMLNS_XEP0060, id = "current" }):add_child(storage)
+	module:log("debug", "updating bookmarks with %q", item)
+	local ok, err = service:publish(
+		PUBSUB_NODE_XEP0048,
+		jid,
+		"current",
+		item,
+		default_options
+	)
+	if not ok then
+		module:log("error", "failed to update bookmarks: %s", err)
+	end
+end
+
+local function find_matching_bookmark(storage, room)
+	for node in storage:childtags("conference") do
+		if node.attr.jid == room then
+			return node
+		end
+	end
+	return nil
+end
+
+local function inject_bookmark(jid, room, autojoin, name)
+	local pep_service = mod_pep.get_pep_service(jid_split(jid))
+
+	autojoin = autojoin or false and true
+	local current = get_current_bookmarks(jid, pep_service)
+	local existing = find_matching_bookmark(current, room)
+	if existing then
+		if autojoin ~= nil then
+			existing.attr.autojoin = autojoin and "true" or "false"
+		end
+		if name ~= nil then
+			-- do not change already configured names
+			if not existing.attr.name then
+				existing.attr.name = name
+			end
+		end
+		done = true
+		module:log("debug", "found existing matching bookmark, updated")
+	else
+		module:log("debug", "no existing bookmark found, adding new")
+		current:tag("conference", {
+			name = name,
+			autojoin = autojoin and "true" or "false",
+			jid = room,
+			xmlns = XMLNS_XEP0048,
+		})
+	end
+
+	update_bookmarks(jid, pep_service, current)
+end
+
+local function remove_bookmark(jid, room, autojoin, name)
+	local pep_service = mod_pep.get_pep_service(jid_split(jid))
+
+	autojoin = autojoin or false and true
+	local current = get_current_bookmarks(jid, pep_service)
+	current:maptags(function (node)
+		if node.attr.xmlns and node.attr.xmlns ~= XMLNS_XEP0048 then
+			return node
+		end
+		if node.name ~= "conference" then
+			return node
+		end
+		if node.attr.jid == room then
+			-- remove matching bookmark
+			return nil
+		end
+		return node
+	end)
+
+	update_bookmarks(jid, pep_service, current)
+end
+
+local function handle_user_added(event)
+	if not event.group_info.muc_jid then
+		module:log("debug", "ignoring user added event on group %s because it has no MUC", event.id)
+		return
+	end
+	local jid = event.user .. "@" .. event.host
+	inject_bookmark(jid, event.group_info.muc_jid, true, event.group_info.name)
+end
+
+local function handle_user_removed(event)
+	if not event.group_info.muc_jid then
+		module:log("debug", "ignoring user removed event on group %s because it has no MUC", event.id)
+		return
+	end
+	-- Removing the bookmark is fine as the user just lost any privilege to
+	-- be in the MUC (as group MUCs are members-only).
+	local jid = event.user .. "@" .. event.host
+	remove_bookmark(jid, event.group_info.muc_jid, true, event.group_info.name)
+end
+
+module:hook("group-user-added", handle_user_added)
+module:hook("group-user-removed", handle_user_removed)