Mercurial > libervia-backend
comparison sat/plugins/plugin_exp_invitation.py @ 3028:ab2696e34d29
Python 3 port:
/!\ this is a huge commit
/!\ starting from this commit, SàT is needs Python 3.6+
/!\ SàT maybe be instable or some feature may not work anymore, this will improve with time
This patch port backend, bridge and frontends to Python 3.
Roughly this has been done this way:
- 2to3 tools has been applied (with python 3.7)
- all references to python2 have been replaced with python3 (notably shebangs)
- fixed files not handled by 2to3 (notably the shell script)
- several manual fixes
- fixed issues reported by Python 3 that where not handled in Python 2
- replaced "async" with "async_" when needed (it's a reserved word from Python 3.7)
- replaced zope's "implements" with @implementer decorator
- temporary hack to handle data pickled in database, as str or bytes may be returned,
to be checked later
- fixed hash comparison for password
- removed some code which is not needed anymore with Python 3
- deactivated some code which needs to be checked (notably certificate validation)
- tested with jp, fixed reported issues until some basic commands worked
- ported Primitivus (after porting dependencies like urwid satext)
- more manual fixes
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 13 Aug 2019 19:08:41 +0200 |
parents | 83cbd4545274 |
children | 9d0df638c8b4 |
comparison
equal
deleted
inserted
replaced
3027:ff5bcb12ae60 | 3028:ab2696e34d29 |
---|---|
1 #!/usr/bin/env python2 | 1 #!/usr/bin/env python3 |
2 # -*- coding: utf-8 -*- | 2 # -*- coding: utf-8 -*- |
3 | 3 |
4 # SAT plugin to detect language (experimental) | 4 # SAT plugin to detect language (experimental) |
5 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org) | 5 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org) |
6 | 6 |
22 from sat.core.constants import Const as C | 22 from sat.core.constants import Const as C |
23 from sat.core.log import getLogger | 23 from sat.core.log import getLogger |
24 from twisted.internet import defer | 24 from twisted.internet import defer |
25 from twisted.words.protocols.jabber import jid | 25 from twisted.words.protocols.jabber import jid |
26 from wokkel import disco, iwokkel | 26 from wokkel import disco, iwokkel |
27 from zope.interface import implements | 27 from zope.interface import implementer |
28 from twisted.words.protocols.jabber.xmlstream import XMPPHandler | 28 from twisted.words.protocols.jabber.xmlstream import XMPPHandler |
29 | 29 |
30 log = getLogger(__name__) | 30 log = getLogger(__name__) |
31 | 31 |
32 | 32 |
33 PLUGIN_INFO = { | 33 PLUGIN_INFO = { |
34 C.PI_NAME: "Invitation", | 34 C.PI_NAME: "Invitation", |
35 C.PI_IMPORT_NAME: "INVITATION", | 35 C.PI_IMPORT_NAME: "INVITATION", |
36 C.PI_TYPE: "EXP", | 36 C.PI_TYPE: "EXP", |
37 C.PI_PROTOCOLS: [], | 37 C.PI_PROTOCOLS: [], |
38 C.PI_DEPENDENCIES: [u"XEP-0060", u"XEP-0329"], | 38 C.PI_DEPENDENCIES: ["XEP-0060", "XEP-0329"], |
39 C.PI_RECOMMENDATIONS: [], | 39 C.PI_RECOMMENDATIONS: [], |
40 C.PI_MAIN: "Invitation", | 40 C.PI_MAIN: "Invitation", |
41 C.PI_HANDLER: "yes", | 41 C.PI_HANDLER: "yes", |
42 C.PI_DESCRIPTION: _(u"Experimental handling of invitations"), | 42 C.PI_DESCRIPTION: _("Experimental handling of invitations"), |
43 } | 43 } |
44 | 44 |
45 NS_INVITATION = u"https://salut-a-toi/protocol/invitation:0" | 45 NS_INVITATION = "https://salut-a-toi/protocol/invitation:0" |
46 INVITATION = '/message/invitation[@xmlns="{ns_invit}"]'.format( | 46 INVITATION = '/message/invitation[@xmlns="{ns_invit}"]'.format( |
47 ns_invit=NS_INVITATION | 47 ns_invit=NS_INVITATION |
48 ) | 48 ) |
49 NS_INVITATION_LIST = NS_INVITATION + u"#list" | 49 NS_INVITATION_LIST = NS_INVITATION + "#list" |
50 | 50 |
51 | 51 |
52 class Invitation(object): | 52 class Invitation(object): |
53 | 53 |
54 def __init__(self, host): | 54 def __init__(self, host): |
55 log.info(_(u"Invitation plugin initialization")) | 55 log.info(_("Invitation plugin initialization")) |
56 self.host = host | 56 self.host = host |
57 self._p = self.host.plugins["XEP-0060"] | 57 self._p = self.host.plugins["XEP-0060"] |
58 # map from namespace of the invitation to callback handling it | 58 # map from namespace of the invitation to callback handling it |
59 self._ns_cb = {} | 59 self._ns_cb = {} |
60 | 60 |
86 - path(unicode, None): path of the repository | 86 - path(unicode, None): path of the repository |
87 @raise exceptions.ConflictError: this namespace is already registered | 87 @raise exceptions.ConflictError: this namespace is already registered |
88 """ | 88 """ |
89 if namespace in self._ns_cb: | 89 if namespace in self._ns_cb: |
90 raise exceptions.ConflictError( | 90 raise exceptions.ConflictError( |
91 u"invitation namespace {namespace} is already register with {callback}" | 91 "invitation namespace {namespace} is already register with {callback}" |
92 .format(namespace=namespace, callback=self._ns_cb[namespace])) | 92 .format(namespace=namespace, callback=self._ns_cb[namespace])) |
93 self._ns_cb[namespace] = callback | 93 self._ns_cb[namespace] = callback |
94 | 94 |
95 def _generateBaseInvitation(self, client, invitee_jid, name, extra): | 95 def _generateBaseInvitation(self, client, invitee_jid, name, extra): |
96 """Generate common mess_data end invitation_elt | 96 """Generate common mess_data end invitation_elt |
111 "extra": {}, | 111 "extra": {}, |
112 } | 112 } |
113 client.generateMessageXML(mess_data) | 113 client.generateMessageXML(mess_data) |
114 invitation_elt = mess_data["xml"].addElement("invitation", NS_INVITATION) | 114 invitation_elt = mess_data["xml"].addElement("invitation", NS_INVITATION) |
115 if name is not None: | 115 if name is not None: |
116 invitation_elt[u"name"] = name | 116 invitation_elt["name"] = name |
117 thumb_url = extra.get(u'thumb_url') | 117 thumb_url = extra.get('thumb_url') |
118 if thumb_url: | 118 if thumb_url: |
119 if not thumb_url.startswith(u'http'): | 119 if not thumb_url.startswith('http'): |
120 log.warning( | 120 log.warning( |
121 u"only http URLs are allowed for thumbnails, got {url}, ignoring" | 121 "only http URLs are allowed for thumbnails, got {url}, ignoring" |
122 .format(url=thumb_url)) | 122 .format(url=thumb_url)) |
123 else: | 123 else: |
124 invitation_elt[u'thumb_url'] = thumb_url | 124 invitation_elt['thumb_url'] = thumb_url |
125 return mess_data, invitation_elt | 125 return mess_data, invitation_elt |
126 | 126 |
127 def sendPubsubInvitation(self, client, invitee_jid, service, node, | 127 def sendPubsubInvitation(self, client, invitee_jid, service, node, |
128 item_id, name, extra): | 128 item_id, name, extra): |
129 """Send an pubsub invitation in a <message> stanza | 129 """Send an pubsub invitation in a <message> stanza |
137 """ | 137 """ |
138 if extra is None: | 138 if extra is None: |
139 extra = {} | 139 extra = {} |
140 mess_data, invitation_elt = self._generateBaseInvitation( | 140 mess_data, invitation_elt = self._generateBaseInvitation( |
141 client, invitee_jid, name, extra) | 141 client, invitee_jid, name, extra) |
142 pubsub_elt = invitation_elt.addElement(u"pubsub") | 142 pubsub_elt = invitation_elt.addElement("pubsub") |
143 pubsub_elt[u"service"] = service.full() | 143 pubsub_elt["service"] = service.full() |
144 pubsub_elt[u"node"] = node | 144 pubsub_elt["node"] = node |
145 pubsub_elt[u"item"] = item_id | 145 pubsub_elt["item"] = item_id |
146 return client.send(mess_data[u"xml"]) | 146 return client.send(mess_data["xml"]) |
147 | 147 |
148 def sendFileSharingInvitation(self, client, invitee_jid, service, repos_type=None, | 148 def sendFileSharingInvitation(self, client, invitee_jid, service, repos_type=None, |
149 namespace=None, path=None, name=None, extra=None): | 149 namespace=None, path=None, name=None, extra=None): |
150 """Send a file sharing invitation in a <message> stanza | 150 """Send a file sharing invitation in a <message> stanza |
151 | 151 |
161 """ | 161 """ |
162 if extra is None: | 162 if extra is None: |
163 extra = {} | 163 extra = {} |
164 mess_data, invitation_elt = self._generateBaseInvitation( | 164 mess_data, invitation_elt = self._generateBaseInvitation( |
165 client, invitee_jid, name, extra) | 165 client, invitee_jid, name, extra) |
166 file_sharing_elt = invitation_elt.addElement(u"file_sharing") | 166 file_sharing_elt = invitation_elt.addElement("file_sharing") |
167 file_sharing_elt[u"service"] = service.full() | 167 file_sharing_elt["service"] = service.full() |
168 if repos_type is not None: | 168 if repos_type is not None: |
169 if repos_type not in (u"files", "photos"): | 169 if repos_type not in ("files", "photos"): |
170 msg = u"unknown repository type: {repos_type}".format( | 170 msg = "unknown repository type: {repos_type}".format( |
171 repos_type=repos_type) | 171 repos_type=repos_type) |
172 log.warning(msg) | 172 log.warning(msg) |
173 raise exceptions.DateError(msg) | 173 raise exceptions.DateError(msg) |
174 file_sharing_elt[u"type"] = repos_type | 174 file_sharing_elt["type"] = repos_type |
175 if namespace is not None: | 175 if namespace is not None: |
176 file_sharing_elt[u"namespace"] = namespace | 176 file_sharing_elt["namespace"] = namespace |
177 if path is not None: | 177 if path is not None: |
178 file_sharing_elt[u"path"] = path | 178 file_sharing_elt["path"] = path |
179 return client.send(mess_data[u"xml"]) | 179 return client.send(mess_data["xml"]) |
180 | 180 |
181 @defer.inlineCallbacks | 181 @defer.inlineCallbacks |
182 def _parsePubsubElt(self, client, pubsub_elt): | 182 def _parsePubsubElt(self, client, pubsub_elt): |
183 try: | 183 try: |
184 service = jid.JID(pubsub_elt["service"]) | 184 service = jid.JID(pubsub_elt["service"]) |
185 node = pubsub_elt["node"] | 185 node = pubsub_elt["node"] |
186 item_id = pubsub_elt.getAttribute("item") | 186 item_id = pubsub_elt.getAttribute("item") |
187 except (RuntimeError, KeyError): | 187 except (RuntimeError, KeyError): |
188 log.warning(_(u"Bad invitation, ignoring")) | 188 log.warning(_("Bad invitation, ignoring")) |
189 raise exceptions.DataError | 189 raise exceptions.DataError |
190 | 190 |
191 try: | 191 try: |
192 items, metadata = yield self._p.getItems(client, service, node, | 192 items, metadata = yield self._p.getItems(client, service, node, |
193 item_ids=[item_id]) | 193 item_ids=[item_id]) |
194 except Exception as e: | 194 except Exception as e: |
195 log.warning(_(u"Can't get item linked with invitation: {reason}").format( | 195 log.warning(_("Can't get item linked with invitation: {reason}").format( |
196 reason=e)) | 196 reason=e)) |
197 try: | 197 try: |
198 item_elt = items[0] | 198 item_elt = items[0] |
199 except IndexError: | 199 except IndexError: |
200 log.warning(_(u"Invitation was linking to a non existing item")) | 200 log.warning(_("Invitation was linking to a non existing item")) |
201 raise exceptions.DataError | 201 raise exceptions.DataError |
202 | 202 |
203 try: | 203 try: |
204 namespace = item_elt.firstChildElement().uri | 204 namespace = item_elt.firstChildElement().uri |
205 except Exception as e: | 205 except Exception as e: |
206 log.warning(_(u"Can't retrieve namespace of invitation: {reason}").format( | 206 log.warning(_("Can't retrieve namespace of invitation: {reason}").format( |
207 reason = e)) | 207 reason = e)) |
208 raise exceptions.DataError | 208 raise exceptions.DataError |
209 | 209 |
210 args = [service, node, item_id, item_elt] | 210 args = [service, node, item_id, item_elt] |
211 defer.returnValue((namespace, args)) | 211 defer.returnValue((namespace, args)) |
212 | 212 |
213 def _parseFileSharingElt(self, client, file_sharing_elt): | 213 def _parseFileSharingElt(self, client, file_sharing_elt): |
214 try: | 214 try: |
215 service = jid.JID(file_sharing_elt["service"]) | 215 service = jid.JID(file_sharing_elt["service"]) |
216 except (RuntimeError, KeyError): | 216 except (RuntimeError, KeyError): |
217 log.warning(_(u"Bad invitation, ignoring")) | 217 log.warning(_("Bad invitation, ignoring")) |
218 raise exceptions.DataError | 218 raise exceptions.DataError |
219 repos_type = file_sharing_elt.getAttribute(u"type", u"files") | 219 repos_type = file_sharing_elt.getAttribute("type", "files") |
220 namespace = file_sharing_elt.getAttribute(u"namespace") | 220 namespace = file_sharing_elt.getAttribute("namespace") |
221 path = file_sharing_elt.getAttribute(u"path") | 221 path = file_sharing_elt.getAttribute("path") |
222 args = [service, repos_type, namespace, path] | 222 args = [service, repos_type, namespace, path] |
223 ns_fis = self.host.getNamespace(u"fis") | 223 ns_fis = self.host.getNamespace("fis") |
224 return ns_fis, args | 224 return ns_fis, args |
225 | 225 |
226 @defer.inlineCallbacks | 226 @defer.inlineCallbacks |
227 def onInvitation(self, message_elt, client): | 227 def onInvitation(self, message_elt, client): |
228 log.debug(u"invitation received [{profile}]".format(profile=client.profile)) | 228 log.debug("invitation received [{profile}]".format(profile=client.profile)) |
229 invitation_elt = message_elt.invitation | 229 invitation_elt = message_elt.invitation |
230 | 230 |
231 name = invitation_elt.getAttribute(u"name") | 231 name = invitation_elt.getAttribute("name") |
232 extra = {} | 232 extra = {} |
233 if invitation_elt.hasAttribute(u"thumb_url"): | 233 if invitation_elt.hasAttribute("thumb_url"): |
234 extra[u'thumb_url'] = invitation_elt[u'thumb_url'] | 234 extra['thumb_url'] = invitation_elt['thumb_url'] |
235 | 235 |
236 for elt in invitation_elt.elements(): | 236 for elt in invitation_elt.elements(): |
237 if elt.uri != NS_INVITATION: | 237 if elt.uri != NS_INVITATION: |
238 log.warning(u"unexpected element: {xml}".format(xml=elt.toXml())) | 238 log.warning("unexpected element: {xml}".format(xml=elt.toXml())) |
239 continue | 239 continue |
240 if elt.name == u"pubsub": | 240 if elt.name == "pubsub": |
241 method = self._parsePubsubElt | 241 method = self._parsePubsubElt |
242 elif elt.name == u"file_sharing": | 242 elif elt.name == "file_sharing": |
243 method = self._parseFileSharingElt | 243 method = self._parseFileSharingElt |
244 else: | 244 else: |
245 log.warning(u"not implemented invitation element: {xml}".format( | 245 log.warning("not implemented invitation element: {xml}".format( |
246 xml = elt.toXml())) | 246 xml = elt.toXml())) |
247 continue | 247 continue |
248 try: | 248 try: |
249 namespace, args = yield method(client, elt) | 249 namespace, args = yield method(client, elt) |
250 except exceptions.DataError: | 250 except exceptions.DataError: |
251 log.warning(u"Can't parse invitation element: {xml}".format( | 251 log.warning("Can't parse invitation element: {xml}".format( |
252 xml = elt.toXml())) | 252 xml = elt.toXml())) |
253 continue | 253 continue |
254 | 254 |
255 try: | 255 try: |
256 cb = self._ns_cb[namespace] | 256 cb = self._ns_cb[namespace] |
257 except KeyError: | 257 except KeyError: |
258 log.warning(_( | 258 log.warning(_( |
259 u'No handler for namespace "{namespace}", invitation ignored') | 259 'No handler for namespace "{namespace}", invitation ignored') |
260 .format(namespace=namespace)) | 260 .format(namespace=namespace)) |
261 else: | 261 else: |
262 cb(client, name, extra, *args) | 262 cb(client, name, extra, *args) |
263 | 263 |
264 | 264 |
265 @implementer(iwokkel.IDisco) | |
265 class PubsubInvitationHandler(XMPPHandler): | 266 class PubsubInvitationHandler(XMPPHandler): |
266 implements(iwokkel.IDisco) | |
267 | 267 |
268 def __init__(self, plugin_parent): | 268 def __init__(self, plugin_parent): |
269 self.plugin_parent = plugin_parent | 269 self.plugin_parent = plugin_parent |
270 | 270 |
271 def connectionInitialized(self): | 271 def connectionInitialized(self): |