Coverage for slidge/core/dispatcher/muc/admin.py: 94%
53 statements
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-10 09:11 +0000
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-10 09:11 +0000
1from slixmpp import JID, CoroutineCallback, Iq, StanzaPath
2from slixmpp.exceptions import XMPPError
3from slixmpp.xmlstream import StanzaBase
5from ..util import DispatcherMixin, exceptions_to_xmpp_errors
8class MucAdminMixin(DispatcherMixin):
9 def __init__(self, xmpp) -> None:
10 super().__init__(xmpp)
11 self.xmpp.register_handler(
12 CoroutineCallback(
13 "MUCModerate",
14 StanzaPath("iq/moderate"),
15 self.on_user_moderation,
16 )
17 )
18 self.xmpp.register_handler(
19 CoroutineCallback(
20 "MUCSetAffiliation",
21 StanzaPath("iq@type=set/mucadmin_query"),
22 self.on_user_set_affiliation,
23 )
24 )
25 self.xmpp.register_handler(
26 CoroutineCallback(
27 "MUCGetAffiliation",
28 StanzaPath("iq@type=get/mucadmin_query"),
29 self.on_muc_admin_query_get,
30 )
31 )
33 @exceptions_to_xmpp_errors
34 async def on_user_moderation(self, iq: StanzaBase) -> None:
35 assert isinstance(iq, Iq)
36 muc = await self.get_muc_from_stanza(iq)
38 moderate = iq["moderate"]
39 xmpp_id = iq["moderate"]["id"]
40 if not xmpp_id:
41 raise XMPPError("bad-request", "Missing moderated message ID")
43 if not moderate["retract"]:
44 raise XMPPError(
45 "feature-not-implemented",
46 "Slidge only implements moderation/retraction",
47 )
49 legacy_id = self._xmpp_msg_id_to_legacy(muc.session, xmpp_id)
50 await muc.session.on_moderate(muc, legacy_id, moderate["reason"] or None)
51 iq.reply(clear=True).send()
53 @exceptions_to_xmpp_errors
54 async def on_user_set_affiliation(self, iq: StanzaBase) -> None:
55 assert isinstance(iq, Iq)
56 muc = await self.get_muc_from_stanza(iq)
58 item = iq["mucadmin_query"]["item"]
59 if item["jid"]:
60 contact = await muc.session.contacts.by_jid(JID(item["jid"]))
61 else:
62 part = await muc.get_participant(
63 item["nick"], fill_first=True, raise_if_not_found=True
64 )
65 assert part.contact is not None
66 contact = part.contact
68 if item["affiliation"]:
69 await muc.on_set_affiliation(
70 contact,
71 item["affiliation"],
72 item["reason"] or None,
73 item["nick"] or None,
74 )
75 elif item["role"] == "none":
76 await muc.on_kick(contact, item["reason"] or None)
78 iq.reply(clear=True).send()
80 @exceptions_to_xmpp_errors
81 async def on_muc_admin_query_get(self, iq: StanzaBase) -> None:
82 assert isinstance(iq, Iq)
83 affiliation = iq["mucadmin_query"]["item"]["affiliation"]
85 if not affiliation:
86 raise XMPPError("bad-request")
88 session = await self._get_session(iq, 1, logged=True)
89 muc = await session.bookmarks.by_jid(iq.get_to())
91 reply = iq.reply()
92 reply.enable("mucadmin_query")
93 async for participant in muc.get_participants():
94 if not participant.affiliation == affiliation:
95 continue
96 reply["mucadmin_query"].append(participant.mucadmin_item())
97 reply.send()