File

mod_flags/mod_flags.lua @ 6302:06fbbd45ba75

mod_cloud_notify: Readme: fix links and labels that were removed in the last commit diff --git a/mod_cloud_notify/README.md b/mod_cloud_notify/README.md --- a/mod_cloud_notify/README.md +++ b/mod_cloud_notify/README.md @@ -1,3 +1,9 @@ +---- +-labels: +-- 'Stage-Beta' +-summary: 'XEP-0357: Cloud push notifications' +---- + # Introduction This module enables support for sending "push notifications" to clients @@ -32,15 +38,15 @@ notification to your device. When your d it will display it or wake up the app so it can connect to XMPP and receive any pending messages. -This protocol is described for developers in \[XEP-0357: Push -Notifications\]. +This protocol is described for developers in [XEP-0357: Push +Notifications]. -For this module to work reliably, you must have \[mod_smacks\], -\[mod_mam\] and \[mod_carbons\] also enabled on your server. +For this module to work reliably, you must have [mod_smacks], +[mod_mam] and [mod_carbons] also enabled on your server. Some clients, notably Siskin and Snikket iOS need some additional extensions that are not currently defined in a standard XEP. To support -these clients, see \[mod_cloud_notify_extensions\]. +these clients, see [mod_cloud_notify_extensions]. # Configuration @@ -58,18 +64,18 @@ these clients, see \[mod_cloud_notify_ex # Internal design notes App servers are notified about offline messages, messages stored by -\[mod_mam\] or messages waiting in the smacks queue. The business rules +[mod_mam] or messages waiting in the smacks queue. The business rules outlined [here](//mail.jabber.org/pipermail/standards/2016-February/030925.html) are all honored[^2]. -To cooperate with \[mod_smacks\] this module consumes some events: +To cooperate with [mod_smacks] this module consumes some events: `smacks-ack-delayed`, `smacks-hibernation-start` and `smacks-hibernation-end`. These events allow this module to send out notifications for messages received while the session is hibernated by -\[mod_smacks\] or even when smacks acknowledgements for messages are +[mod_smacks] or even when smacks acknowledgements for messages are delayed by a certain amount of seconds configurable with the -\[mod_smacks\] setting `smacks_max_ack_delay`. +[mod_smacks] setting `smacks_max_ack_delay`. The `smacks_max_ack_delay` setting allows to send out notifications to clients which aren't already in smacks hibernation state (because the
author Menel <menel@snikket.de>
date Fri, 13 Jun 2025 10:44:37 +0200
parent 6132:ffec70ddbffc
line wrap: on
line source

-- This module is only for 0.12, later versions have mod_flags bundled
--% conflicts: mod_flags

local flags_map;
if prosody.process_type ~= "prosodyctl" then
	flags_map = module:open_store("account_flags", "map");
end

-- API

function add_flag(username, flag, comment) -- luacheck: ignore 131/add_flag
	local flag_data = {
		when = os.time();
		comment = comment;
	};

	local ok, err = flags_map:set(username, flag, flag_data);
	if not ok then
		return nil, err;
	end

	module:fire_event("user-flag-added/"..flag, {
		user = username;
		flag = flag;
		data = flag_data;
	});

	return true;
end

function remove_flag(username, flag) -- luacheck: ignore 131/remove_flag
	local ok, err = flags_map:set(username, flag, nil);
	if not ok then
		return nil, err;
	end

	module:fire_event("user-flag-removed/"..flag, {
		user = username;
		flag = flag;
	});

	return true;
end

function has_flag(username, flag) -- luacheck: ignore 131/has_flag
	local ok, err = flags_map:get(username, flag);
	if not ok and err then
		error("Failed to check flags for user: "..err);
	end
	return not not ok;
end

function get_flag_info(username, flag) -- luacheck: ignore 131/get_flag_info
	return flags_map:get(username, flag);
end


-- Migration from mod_firewall marks

local function migrate_marks(host)
	local usermanager = require "core.usermanager";

	local flag_storage = module:open_store("account_flags");
	local mark_storage = module:open_store("firewall_marks");

	local migration_comment = "Migrated from mod_firewall marks at "..os.date("%Y-%m-%d %R");

	local migrated, empty, errors = 0, 0, 0;
	for username in usermanager.users(host) do
		local marks, err = mark_storage:get(username);
		if marks then
			local flags = {};
			for mark_name, mark_timestamp in pairs(marks) do
				flags[mark_name] = {
					when = mark_timestamp;
					comment = migration_comment;
				};
			end
			local saved_ok, saved_err = flag_storage:set(username, flags);
			if saved_ok then
				prosody.log("error", "Failed to save flags for %s: %s", username, saved_err);
				migrated = migrated + 1;
			else
				errors = errors + 1;
			end
		elseif err then
			prosody.log("error", "Failed to load marks for %s: %s", username, err);
			errors = errors + 1;
		else
			empty = empty + 1;
		end
	end

	print(("Finished - %d migrated, %d users with no marks, %d errors"):format(migrated, empty, errors));
end

function module.command(arg)
	local storagemanager = require "core.storagemanager";
	local usermanager = require "core.usermanager";
	local jid = require "util.jid";
	local warn = require"util.prosodyctl".show_warning;

	local command = arg[1];
	if not command then
		warn("Valid subcommands: migrate_marks");
		return 0;
	end
	table.remove(arg, 1);

	local node, host = jid.prepped_split(arg[1]);
	if not host then
		warn("Please specify a host or JID after the command");
		return 1;
	elseif not prosody.hosts[host] then
		warn("Unknown host: "..host);
		return 1;
	end

	table.remove(arg, 1);

	module.host = host; -- luacheck: ignore 122
	storagemanager.initialize_host(host);
	usermanager.initialize_host(host);

	flags_map = module:open_store("account_flags", "map");

	if command == "migrate_marks" then
		migrate_marks(host);
		return 0;
	elseif command == "find" then
		local flag = assert(arg[1], "expected argument: flag");
		local flags = module:open_store("account_flags", "map");
		local users_with_flag = flags:get_all(flag);

		local c = 0;
		for user, flag_data in pairs(users_with_flag) do
			print(user, os.date("%Y-%m-%d %R", flag_data.when), flag_data.comment or "");
			c = c + 1;
		end

		print(("%d accounts listed"):format(c));
		return 1;
	elseif command == "add" then
		local username = assert(node, "expected a user JID, got "..host);
		local flag = assert(arg[1], "expected argument: flag");
		local comment = arg[2];

		local ok, err = add_flag(username, flag, comment);
		if not ok then
			print("Failed to add flag: "..err);
			return 1;
		end

		print("Flag added");
		return 1;
	elseif command == "remove" then
		local username = assert(node, "expected a user JID, got "..host);
		local flag = assert(arg[1], "expected argument: flag");

		local ok, err = remove_flag(username, flag);
		if not ok then
			print("Failed to remove flag: "..err);
			return 1;
		end

		print("Flag removed");
		return 1;
	elseif command == "list" then
		local username = assert(node, "expected a user JID, got "..host);

		local c = 0;

		local flags = module:open_store("account_flags");
		local user_flags, err = flags:get(username);

		if not user_flags and err then
			print("Unable to list flags: "..err);
			return 1;
		end

		if user_flags then
			for flag_name, flag_data in pairs(user_flags) do
				print(flag_name, os.date("%Y-%m-%d %R", flag_data.when), flag_data.comment or "");
				c = c + 1;
			end
		end

		print(("%d flags listed"):format(c));
		return 0;
	else
		warn("Unknown command: %s", command);
		return 1;
	end
end