3462
|
1 #!/usr/bin/env python3 |
|
2 |
|
3 # SàT plugin to send invitations for Pubsub |
|
4 # Copyright (C) 2009-2021 Jérôme Poisson (goffi@goffi.org) |
|
5 |
|
6 # This program is free software: you can redistribute it and/or modify |
|
7 # it under the terms of the GNU Affero General Public License as published by |
|
8 # the Free Software Foundation, either version 3 of the License, or |
|
9 # (at your option) any later version. |
|
10 |
|
11 # This program is distributed in the hope that it will be useful, |
|
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
14 # GNU Affero General Public License for more details. |
|
15 |
|
16 # You should have received a copy of the GNU Affero General Public License |
|
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
18 |
|
19 from typing import Optional |
|
20 from twisted.internet import defer |
|
21 from twisted.words.protocols.jabber import jid |
|
22 from twisted.words.xish import domish |
|
23 from sat.core.i18n import _ |
|
24 from sat.core.constants import Const as C |
|
25 from sat.core.log import getLogger |
|
26 from sat.core.xmpp import SatXMPPEntity |
|
27 from sat.tools import utils |
|
28 from sat.tools.common import data_format |
|
29 |
|
30 log = getLogger(__name__) |
|
31 |
|
32 |
|
33 PLUGIN_INFO = { |
|
34 C.PI_NAME: "Pubsub Invitation", |
|
35 C.PI_IMPORT_NAME: "PUBSUB_INVITATION", |
|
36 C.PI_TYPE: "EXP", |
|
37 C.PI_PROTOCOLS: [], |
|
38 C.PI_DEPENDENCIES: ["XEP-0060", "INVITATION"], |
|
39 C.PI_RECOMMENDATIONS: [], |
|
40 C.PI_MAIN: "PubsubInvitation", |
|
41 C.PI_HANDLER: "no", |
|
42 C.PI_DESCRIPTION: _("Invitations for pubsub based features"), |
|
43 } |
|
44 |
|
45 |
|
46 class PubsubInvitation: |
|
47 |
|
48 def __init__(self, host): |
|
49 log.info(_("Pubsub Invitation plugin initialization")) |
|
50 self.host = host |
|
51 self._p = host.plugins["XEP-0060"] |
|
52 # namespace to handler map |
|
53 self._ns_handler = {} |
|
54 host.bridge.addMethod( |
|
55 "psInvite", |
|
56 ".plugin", |
|
57 in_sign="sssssss", |
|
58 out_sign="", |
|
59 method=self._sendPubsubInvitation, |
|
60 async_=True |
|
61 ) |
|
62 |
|
63 def register( |
|
64 self, |
|
65 namespace: str, |
|
66 handler |
|
67 ) -> None: |
|
68 self._ns_handler[namespace] = handler |
|
69 self.host.plugins["INVITATION"].registerNamespace(namespace, self.onInvitation) |
|
70 |
|
71 def _sendPubsubInvitation( |
|
72 self, invitee_jid_s, service_s, node, item_id=None, |
|
73 name=None, extra_s='', profile_key=C.PROF_KEY_NONE): |
|
74 client = self.host.getClient(profile_key) |
|
75 invitee_jid = jid.JID(invitee_jid_s) |
|
76 service = jid.JID(service_s) |
|
77 extra = data_format.deserialise(extra_s) |
|
78 return defer.ensureDeferred( |
|
79 self.invite( |
|
80 client, |
|
81 invitee_jid, |
|
82 service, |
|
83 node, |
|
84 item_id or None, |
|
85 name=name or None, |
|
86 extra=extra |
|
87 ) |
|
88 ) |
|
89 |
|
90 async def invite( |
|
91 self, |
|
92 client: SatXMPPEntity, |
|
93 invitee_jid: jid.JID, |
|
94 service: jid.JID, |
|
95 node: str, |
|
96 item_id: Optional[str] = None, |
|
97 name: str = '', |
|
98 extra: Optional[dict] = None, |
|
99 ) -> None: |
|
100 if extra is None: |
|
101 extra = {} |
|
102 else: |
|
103 namespace = extra.get("namespace") |
|
104 if namespace: |
|
105 try: |
|
106 handler = self._ns_handler[namespace] |
|
107 preflight = handler.invitePreflight |
|
108 except KeyError: |
|
109 pass |
|
110 except AttributeError: |
|
111 log.debug(f"no invitePreflight method found for {namespace!r}") |
|
112 else: |
|
113 await utils.asDeferred( |
|
114 preflight, |
|
115 client, invitee_jid, service, node, item_id, name, extra |
|
116 ) |
|
117 if item_id is None: |
|
118 item_id = extra.pop("default_item_id", None) |
|
119 |
|
120 # we authorize our invitee to see the nodes of interest |
|
121 await self._p.setNodeAffiliations(client, service, node, {invitee_jid: "member"}) |
|
122 log.debug(f"affiliation set on {service}'s {node!r} node") |
|
123 |
|
124 # now we send the invitation |
|
125 self.host.plugins["INVITATION"].sendPubsubInvitation( |
|
126 client, |
|
127 invitee_jid, |
|
128 service, |
|
129 node, |
|
130 item_id, |
|
131 name=name or None, |
|
132 extra=extra |
|
133 ) |
|
134 |
|
135 async def onInvitation( |
|
136 self, |
|
137 client: SatXMPPEntity, |
|
138 namespace: str, |
|
139 name: str, |
|
140 extra: dict, |
|
141 service: jid.JID, |
|
142 node: str, |
|
143 item_id: Optional[str], |
|
144 item_elt: domish.Element |
|
145 ) -> None: |
|
146 if extra is None: |
|
147 extra = {} |
|
148 try: |
|
149 handler = self._ns_handler[namespace] |
|
150 preflight = handler.onInvitationPreflight |
|
151 except KeyError: |
|
152 pass |
|
153 except AttributeError: |
|
154 log.debug(f"no onInvitationPreflight method found for {namespace!r}") |
|
155 else: |
|
156 await utils.asDeferred( |
|
157 preflight, |
|
158 client, namespace, name, extra, service, node, item_id, item_elt |
|
159 ) |
|
160 if item_id is None: |
|
161 item_id = extra.pop("default_item_id", None) |
|
162 creator = extra.pop("creator", False) |
|
163 element = extra.pop("element", None) |
|
164 if not name: |
|
165 name = extra.pop("name", "") |
|
166 |
|
167 return self.host.plugins['LIST_INTEREST'].registerPubsub( |
|
168 client, namespace, service, node, item_id, creator, |
|
169 name, element, extra) |