Moderation delay WIP (#132):

* mod_muc_moderation_delay, first shot.
This commit is contained in:
John Livingston 2024-07-09 11:16:58 +02:00
parent 7606a0ec7e
commit f870aa6cfb
No known key found for this signature in database
GPG Key ID: B17B5640CE66CDBC
5 changed files with 178 additions and 0 deletions

View File

@ -0,0 +1,25 @@
<!--
SPDX-FileCopyrightText: 2024 John Livingston <https://www.john-livingston.fr/>
SPDX-License-Identifier: AGPL-3.0-only
-->
# mod_muc_moderation_delay
With this module, you can apply a delay to groupchat messages delivery, so that room moderators can moderate them before other participants receives them.
This module is part of peertube-plugin-livechat, and is under the same LICENSE.
This module can work on any Prosody server (version >= 0.12.x).
## Configuration
Just enable the module on your MUC component.
The feature will be accessible throught the room configuration form.
The position in the room config form can be changed be setting the option `moderation_delay_form_position`.
This value will be passed as priority for the "muc-config-form" hook.
By default, the field will be between muc#roomconfig_changesubject and muc#roomconfig_moderatedroom.
``` lua
VirtualHost "muc.example.com"
modules_enabled = { "muc_moderation_delay" }
moderation_delay_form_position = 96
```

View File

@ -0,0 +1,61 @@
-- SPDX-FileCopyrightText: 2024 John Livingston <https://www.john-livingston.fr/>
-- SPDX-License-Identifier: AGPL-3.0-only
-- Getter/Setter
local function get_moderation_delay(room)
return room._data.moderation_delay or nil;
end
local function set_moderation_delay(room, delay)
if delay == 0 then
delay = nil;
end
if delay ~= nil then
delay = assert(tonumber(delay), "Moderation delay is not a valid number");
if delay < 0 then
delay = nil;
end
end
if get_moderation_delay(room) == delay then return false; end
room._data.moderation_delay = delay;
return true;
end
-- Discovering support
local function add_disco_form(event)
table.insert(event.form, {
name = "muc#roominfo_moderation_delay";
value = "";
});
event.formdata["muc#roominfo_moderation_delay"] = get_moderation_delay(event.room);
end
-- Config form declaration
local function add_form_option(event)
table.insert(event.form, {
name = "muc#roomconfig_moderation_delay";
type = "text-single";
datatype = "xs:integer";
range_min = 0;
range_max = 60; -- do not allow too big values, it does not make sense.
label = "Moderation delay (0=disabled, any positive integer= messages will be delayed for X seconds for non-moderator participants.)";
-- desc = "";
value = get_moderation_delay(event.room);
});
end
local function config_submitted(event)
set_moderation_delay(event.room, event.value);
-- no need to 104 status, this feature is invisible for regular participants.
end
return {
set_moderation_delay = set_moderation_delay;
get_moderation_delay = get_moderation_delay;
add_disco_form = add_disco_form;
add_form_option = add_form_option;
config_submitted = config_submitted;
}

View File

@ -0,0 +1,59 @@
-- SPDX-FileCopyrightText: 2024 John Livingston <https://www.john-livingston.fr/>
-- SPDX-License-Identifier: AGPL-3.0-only
local async = require "util.async";
local get_moderation_delay = module:require("config").get_moderation_delay;
local muc_util = module:require "muc/util";
local valid_roles = muc_util.valid_roles;
local function handle_broadcast_message(event)
local room, stanza = event.room, event.stanza;
local delay = get_moderation_delay(room);
if delay == nil then
return;
end
-- only delay groupchat messages with body.
if stanza.attr.type ~= "groupchat" then
return;
end
if not stanza:get_child("body") then
return;
end
local id = stanza.attr.id;
if not id then
-- message should alway have an id, but just in case...
module:log("warn", "Message has no id, wont delay it.");
return;
end
-- TODO: detect message retractation, and stop broadcast for any waiting message.
-- Message must be delayed, except for:
-- * room moderators
-- * the user that sent the message (if they don't get the echo quickly, their clients could have weird behaviours)
module:log("debug", "Message must be delayed by %i seconds, sending first broadcast wave.", delay);
local moderator_role_value = valid_roles["moderator"];
local func = function (nick, occupant)
if valid_roles[occupant.role or "none"] >= moderator_role_value then
return true;
end
if nick == stanza.attr.from then
return true;
end
return false;
end;
room:broadcast(stanza, func);
async.sleep(delay);
module:log("debug", "Message has been delayed, sending to remaining participants.");
room:broadcast(stanza, function (nick, occupant)
return not func(nick, occupant);
end);
return true; -- stop the default process
end
return {
handle_broadcast_message = handle_broadcast_message;
};

View File

@ -0,0 +1,30 @@
-- mod_muc_moderation_delay
--
-- SPDX-FileCopyrightText: 2024 John Livingston <https://www.john-livingston.fr/>
-- SPDX-License-Identifier: AGPL-3.0-only
--
-- This file is AGPL-v3 licensed.
-- Please see the Peertube livechat plugin copyright information.
-- https://livingston.frama.io/peertube-plugin-livechat/credits/
--
local add_disco_form = module:require("config").add_disco_form;
local config_submitted = module:require("config").config_submitted;
local add_form_option = module:require("config").add_form_option;
local handle_broadcast_message = module:require("delay").handle_broadcast_message;
-- form_position: the position in the room config form (this value will be passed as priority for the "muc-config-form" hook).
-- By default, field will be between muc#roomconfig_changesubject and muc#roomconfig_moderatedroom
local form_position = module:get_option_number("moderation_delay_form_position") or 80-2;
-- Plugin dependencies
local mod_muc = module:depends "muc";
-- muc-disco and muc-config to configure the feature:
module:hook("muc-disco#info", add_disco_form);
module:hook("muc-config-submitted/muc#roomconfig_moderation_delay", config_submitted);
module:hook("muc-config-form", add_form_option, form_position);
-- intercept muc-broadcast-message, and broadcast with delay if required.
-- Priority is negative, as we want it to be the last handler.
module:hook("muc-broadcast-message", handle_broadcast_message, -1000);

View File

@ -249,6 +249,9 @@ class ProsodyConfigContent {
if (chatTerms) {
this.muc.set('muc_terms_global', new ConfigEntryValueMultiLineString(chatTerms))
}
this.muc.add('modules_enabled', 'muc_moderation_delay')
this.muc.add('moderation_delay_form_position', 118)
}
useAnonymous (autoBanIP: boolean): void {