changeset 4280:278f2998ce49

mod_muc_room_mention_notifications: Publish module
author Seve Ferrer <seve@delape.net>
date Fri, 04 Dec 2020 16:58:36 +0100
parents 776eacd233b5
children 3c80e46e26f2
files mod_muc_room_mention_notifications/README.markdown mod_muc_room_mention_notifications/mod_muc_room_mention_notifications.lua
diffstat 2 files changed, 105 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_muc_room_mention_notifications/README.markdown	Fri Dec 04 16:58:36 2020 +0100
@@ -0,0 +1,16 @@
+# Configuring
+
+## Enabling
+
+``` {.lua}
+Component "rooms.example.net" "muc"
+modules_enabled = {
+    "muc_room_mention_notifications";
+}
+```
+
+## Settings
+
+|Name |Description |Default |
+|-----|------------|--------|
+|muc_rmn_notify_unaffiliated_users| Notify mentioned users even if they are not members of the room they were mentioned in | false |
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_muc_room_mention_notifications/mod_muc_room_mention_notifications.lua	Fri Dec 04 16:58:36 2020 +0100
@@ -0,0 +1,89 @@
+local jid = require "util.jid";
+local st = require "util.stanza";
+local datetime = require "util.datetime";
+
+local notify_unaffiliated_users = module:get_option("muc_rmn_notify_unaffiliated_users", false)
+
+local muc_affiliation_store = module:open_store("config", "map");
+
+local rmn_xmlns = "urn:xmpp:rmn:0";
+local reference_xmlns = "urn:xmpp:reference:0";
+local forwarded_xmlns = "urn:xmpp:forward:0";
+local deplay_xmlns = "urn:xmpp:delay";
+
+
+-- Returns a set of rooms the user is affiliated to
+local function get_user_rooms(user_bare_jid)
+	return muc_affiliation_store:get_all(user_bare_jid);
+end
+
+local function is_eligible(user_bare_jid, room)
+	if notify_unaffiliated_users then return true; end
+
+	local user_rooms, err = get_user_rooms(user_bare_jid);
+	if not user_rooms then
+		if err then
+			return false, err;
+		end
+		return false;
+	end
+
+	local room_node = jid.node(room.jid)
+	if user_rooms[room_node] then
+		return true;
+	end
+
+	return false
+end
+
+-- Send a single notification for a room, updating data structures as needed
+local function send_single_notification(user_bare_jid, room_jid, mention_stanza)
+	local notification = st.message({ to = user_bare_jid, from = module.host })
+		:tag("mentions", { xmlns = rmn_xmlns })
+		:tag("forwarded", {xmlns = forwarded_xmlns})
+		:tag("delay", {xmlns = deplay_xmlns, stamp = datetime.datetime()}):up()
+		:add_child(mention_stanza)
+		:reset();
+	module:log("debug", "Sending mention notification from %s to %s", room_jid, user_bare_jid);
+	return module:send(notification);
+end
+
+local function notify_mentioned_users(room, client_mentions, mention_stanza)
+	module:log("debug", "NOTIFYING FOR %s", room.jid)
+	for user_bare_jid in pairs(client_mentions) do
+		if is_eligible(user_bare_jid, room) then
+			send_single_notification(user_bare_jid, room.jid, mention_stanza);
+		end
+	end
+end
+
+local function get_mentions(stanza)
+	local has_mentions = false
+	local client_mentions = {}
+
+	for element in stanza:childtags("reference", reference_xmlns) do
+		if element.attr.type == "mention" then
+			local user_bare_jid = element.attr.uri:match("^xmpp:(.+)$");
+			if user_bare_jid then
+				client_mentions[user_bare_jid] = user_bare_jid;
+				has_mentions = true
+			end
+		end
+	end
+
+	return has_mentions, client_mentions
+end
+
+module:hook("muc-broadcast-message", function (event)
+	local room, stanza = event.room, event.stanza;
+	local body = stanza:get_child_text("body")
+	if not body or #body < 1 then return; end
+	local correction = stanza:get_child("replace", "urn:xmpp:message-correct:0");
+	if correction then return; end -- Do not notify on message corrections
+
+	local has_mentions, client_mentions = get_mentions(stanza)
+	if not has_mentions then return; end
+
+	-- Notify any users that need to be notified
+	notify_mentioned_users(room, client_mentions, stanza);
+end, -1);