comparison mod_muc_moderation/mod_muc_moderation.lua @ 5169:1071a420ff6f

mod_muc_moderation: Refactor to prepare for new version of XEP-0425 Plan is to add support for both versions concurrently for a transition period while clients upgrade.
author Kim Alvefur <zash@zash.se>
date Sun, 19 Feb 2023 17:51:45 +0100
parents 5f12c75fd210
children 4d6af8950016
comparison
equal deleted inserted replaced
5168:e00dc913d965 5169:1071a420ff6f
32 -- Discovering support 32 -- Discovering support
33 module:hook("muc-disco#info", function (event) 33 module:hook("muc-disco#info", function (event)
34 event.reply:tag("feature", { var = xmlns_moderate }):up(); 34 event.reply:tag("feature", { var = xmlns_moderate }):up();
35 end); 35 end);
36 36
37 -- Main handling 37 -- TODO error registry, requires Prosody 0.12+
38 module:hook("iq-set/bare/" .. xmlns_fasten .. ":apply-to", function (event)
39 local stanza, origin = event.stanza, event.origin;
40 38
41 -- Collect info we need 39 -- moderate : function (string, string, string, boolean, string) : boolean, enum, enum, string
42 local apply_to = stanza.tags[1]; 40 local function moderate(actor, room_jid, stanza_id, retract, reason)
43 local moderate_tag = apply_to:get_child("moderate", xmlns_moderate);
44 if not moderate_tag then return end -- some other kind of fastening?
45
46 local reason = moderate_tag:get_child_text("reason");
47 local retract = moderate_tag:get_child("retract", xmlns_retract);
48
49 local room_jid = stanza.attr.to;
50 local room_node = jid.split(room_jid); 41 local room_node = jid.split(room_jid);
51 local room = mod_muc.get_room_from_jid(room_jid); 42 local room = mod_muc.get_room_from_jid(room_jid);
52 43
53 local stanza_id = apply_to.attr.id;
54
55 -- Permissions 44 -- Permissions
56 local actor = stanza.attr.from;
57 local actor_nick = room:get_occupant_jid(actor); 45 local actor_nick = room:get_occupant_jid(actor);
58 local affiliation = room:get_affiliation(actor); 46 local affiliation = room:get_affiliation(actor);
59 -- Retrieve their current role, iff they are in the room, otherwise what they 47 -- Retrieve their current role, iff they are in the room, otherwise what they
60 -- would have based on affiliation. 48 -- would have based on affiliation.
61 local role = room:get_role(actor_nick) or room:get_default_role(affiliation); 49 local role = room:get_role(actor_nick) or room:get_default_role(affiliation);
62 if valid_roles[role or "none"] < valid_roles.moderator then 50 if valid_roles[role or "none"] < valid_roles.moderator then
63 origin.send(st.error_reply(stanza, "auth", "forbidden", "You need a role of at least 'moderator'")); 51 return false, "auth", "forbidden", "You need a role of at least 'moderator'";
64 return true;
65 end 52 end
66 53
67 if not actor_nick then 54 if not actor_nick then
68 local reserved_nickname = room:get_affiliation_data(jid.bare(actor), "reserved_nickname"); 55 local reserved_nickname = room:get_affiliation_data(jid.bare(actor), "reserved_nickname");
69 if reserved_nickname then 56 if reserved_nickname then
82 if i == stanza_id then 69 if i == stanza_id then
83 original, err = item, nil; 70 original, err = item, nil;
84 end 71 end
85 end 72 end
86 end 73 end
74
87 if not original then 75 if not original then
88 if err == "item-not-found" then 76 if err == "item-not-found" then
89 origin.send(st.error_reply(stanza, "modify", "item-not-found")); 77 return false, "modify", "item-not-found";
90 else 78 else
91 origin.send(st.error_reply(stanza, "wait", "internal-server-error")); 79 return false, "wait", "internal-server-error";
92 end 80 end
93 return true;
94 end 81 end
95 82
96 83
97 local announcement = st.message({ from = room_jid, type = "groupchat", id = id.medium(), }) 84 local announcement = st.message({ from = room_jid, type = "groupchat", id = id.medium(), })
98 :tag("apply-to", { xmlns = xmlns_fasten, id = stanza_id }) 85 :tag("apply-to", { xmlns = xmlns_fasten, id = stanza_id })
112 :tag("retracted", { xmlns = xmlns_retract, stamp = dt.datetime() }):up(); 99 :tag("retracted", { xmlns = xmlns_retract, stamp = dt.datetime() }):up();
113 100
114 if reason then 101 if reason then
115 tombstone:text_tag("reason", reason); 102 tombstone:text_tag("reason", reason);
116 end 103 end
104 tombstone:reset();
117 105
118 local was_replaced = muc_log_archive:set(room_node, stanza_id, tombstone); 106 local was_replaced = muc_log_archive:set(room_node, stanza_id, tombstone);
119 if not was_replaced then 107 if not was_replaced then
120 origin.send(st.error_reply(stanza, "wait", "internal-server-error")); 108 return false, "wait", "internal-server-error";
121 return true;
122 end 109 end
123 end 110 end
124 111
125 -- Done, tell people about it 112 -- Done, tell people about it
126 module:log("info", "Message with id '%s' in room %s moderated by %s, reason: %s", stanza_id, room_jid, actor, reason); 113 module:log("info", "Message with id '%s' in room %s moderated by %s, reason: %s", stanza_id, room_jid, actor, reason);
127 room:broadcast_message(announcement); 114 room:broadcast_message(announcement);
115
116 return true;
117 end
118
119 -- Main handling
120 module:hook("iq-set/bare/" .. xmlns_fasten .. ":apply-to", function (event)
121 local stanza, origin = event.stanza, event.origin;
122
123 local actor = stanza.attr.from;
124 local room_jid = stanza.attr.to;
125
126 -- Collect info we need
127 local apply_to = stanza.tags[1];
128 local moderate_tag = apply_to:get_child("moderate", xmlns_moderate);
129 if not moderate_tag then return end -- some other kind of fastening?
130
131 local reason = moderate_tag:get_child_text("reason");
132 local retract = moderate_tag:get_child("retract", xmlns_retract);
133
134 local stanza_id = apply_to.attr.id;
135
136 local ok, error_type, error_condition, error_text = moderate(actor, room_jid, stanza_id, retract, reason);
137 if not ok then
138 origin.send(st.error_reply(stanza, error_type, error_condition, error_text));
139 return true;
140 end
128 141
129 origin.send(st.reply(stanza)); 142 origin.send(st.reply(stanza));
130 return true; 143 return true;
131 end); 144 end);
132 145