Coverage for slidge/core/dispatcher/muc/admin.py: 94%
52 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-04 08:17 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-04 08:17 +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 __slots__: list[str] = []
11 def __init__(self, xmpp) -> None:
12 super().__init__(xmpp)
13 self.xmpp.register_handler(
14 CoroutineCallback(
15 "MUCModerate",
16 StanzaPath("iq/moderate"),
17 self.on_user_moderation,
18 )
19 )
20 self.xmpp.register_handler(
21 CoroutineCallback(
22 "MUCSetAffiliation",
23 StanzaPath("iq@type=set/mucadmin_query"),
24 self.on_user_set_affiliation,
25 )
26 )
27 self.xmpp.register_handler(
28 CoroutineCallback(
29 "MUCGetAffiliation",
30 StanzaPath("iq@type=get/mucadmin_query"),
31 self.on_muc_admin_query_get,
32 )
33 )
35 @exceptions_to_xmpp_errors
36 async def on_user_moderation(self, iq: StanzaBase) -> None:
37 assert isinstance(iq, Iq)
38 muc = await self.get_muc_from_stanza(iq)
40 moderate = iq["moderate"]
41 xmpp_id = iq["moderate"]["id"]
42 if not xmpp_id:
43 raise XMPPError("bad-request", "Missing moderated message ID")
45 if not moderate["retract"]:
46 raise XMPPError(
47 "feature-not-implemented",
48 "Slidge only implements moderation/retraction",
49 )
51 legacy_id = self._xmpp_msg_id_to_legacy(muc.session, xmpp_id, muc)
52 await muc.session.on_moderate(muc, legacy_id, moderate["reason"] or None)
53 iq.reply(clear=True).send()
55 @exceptions_to_xmpp_errors
56 async def on_user_set_affiliation(self, iq: StanzaBase) -> None:
57 assert isinstance(iq, Iq)
58 muc = await self.get_muc_from_stanza(iq)
60 item = iq["mucadmin_query"]["item"]
61 if item["jid"]:
62 contact = await muc.session.contacts.by_jid(JID(item["jid"]))
63 else:
64 part = await muc.get_participant(
65 item["nick"], fill_first=True, raise_if_not_found=True
66 )
67 assert part.contact is not None
68 contact = part.contact
70 if item["affiliation"]:
71 await muc.on_set_affiliation(
72 contact,
73 item["affiliation"],
74 item["reason"] or None,
75 item["nick"] or None,
76 )
77 elif item["role"] == "none":
78 await muc.on_kick(contact, item["reason"] or None)
80 iq.reply(clear=True).send()
82 @exceptions_to_xmpp_errors
83 async def on_muc_admin_query_get(self, iq: StanzaBase) -> None:
84 assert isinstance(iq, Iq)
85 affiliation = iq["mucadmin_query"]["item"]["affiliation"]
87 if not affiliation:
88 raise XMPPError("bad-request")
90 session = await self._get_session(iq, 1, logged=True)
91 muc = await session.bookmarks.by_jid(iq.get_to())
93 reply = iq.reply()
94 reply.enable("mucadmin_query")
95 async for participant in muc.get_participants(affiliation):
96 reply["mucadmin_query"].append(participant.mucadmin_item())
97 reply.send()