comparison sat/plugins/plugin_exp_events.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 fee60f17ebac
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
27 from sat.tools.common import date_utils 27 from sat.tools.common import date_utils
28 from twisted.internet import defer 28 from twisted.internet import defer
29 from twisted.words.protocols.jabber import jid, error 29 from twisted.words.protocols.jabber import jid, error
30 from twisted.words.xish import domish 30 from twisted.words.xish import domish
31 from wokkel import disco, iwokkel 31 from wokkel import disco, iwokkel
32 from zope.interface import implements 32 from zope.interface import implementer
33 from twisted.words.protocols.jabber.xmlstream import XMPPHandler 33 from twisted.words.protocols.jabber.xmlstream import XMPPHandler
34 from wokkel import pubsub 34 from wokkel import pubsub
35 35
36 log = getLogger(__name__) 36 log = getLogger(__name__)
37 37
39 PLUGIN_INFO = { 39 PLUGIN_INFO = {
40 C.PI_NAME: "Events", 40 C.PI_NAME: "Events",
41 C.PI_IMPORT_NAME: "EVENTS", 41 C.PI_IMPORT_NAME: "EVENTS",
42 C.PI_TYPE: "EXP", 42 C.PI_TYPE: "EXP",
43 C.PI_PROTOCOLS: [], 43 C.PI_PROTOCOLS: [],
44 C.PI_DEPENDENCIES: [u"XEP-0060", u"INVITATION", u"LIST_INTEREST"], 44 C.PI_DEPENDENCIES: ["XEP-0060", "INVITATION", "LIST_INTEREST"],
45 C.PI_RECOMMENDATIONS: ["XEP-0277", "EMAIL_INVITATION"], 45 C.PI_RECOMMENDATIONS: ["XEP-0277", "EMAIL_INVITATION"],
46 C.PI_MAIN: "Events", 46 C.PI_MAIN: "Events",
47 C.PI_HANDLER: "yes", 47 C.PI_HANDLER: "yes",
48 C.PI_DESCRIPTION: _(u"""Experimental implementation of XMPP events management"""), 48 C.PI_DESCRIPTION: _("""Experimental implementation of XMPP events management"""),
49 } 49 }
50 50
51 NS_EVENT = "org.salut-a-toi.event:0" 51 NS_EVENT = "org.salut-a-toi.event:0"
52 52
53 53
54 class Events(object): 54 class Events(object):
55 """Q&D module to handle event attendance answer, experimentation only""" 55 """Q&D module to handle event attendance answer, experimentation only"""
56 56
57 def __init__(self, host): 57 def __init__(self, host):
58 log.info(_(u"Event plugin initialization")) 58 log.info(_("Event plugin initialization"))
59 self.host = host 59 self.host = host
60 self._p = self.host.plugins["XEP-0060"] 60 self._p = self.host.plugins["XEP-0060"]
61 self._i = self.host.plugins.get("EMAIL_INVITATION") 61 self._i = self.host.plugins.get("EMAIL_INVITATION")
62 self._b = self.host.plugins.get("XEP-0277") 62 self._b = self.host.plugins.get("XEP-0277")
63 self.host.registerNamespace(u"event", NS_EVENT) 63 self.host.registerNamespace("event", NS_EVENT)
64 self.host.plugins[u"INVITATION"].registerNamespace(NS_EVENT, 64 self.host.plugins["INVITATION"].registerNamespace(NS_EVENT,
65 self.register) 65 self.register)
66 host.bridge.addMethod( 66 host.bridge.addMethod(
67 "eventGet", 67 "eventGet",
68 ".plugin", 68 ".plugin",
69 in_sign="ssss", 69 in_sign="ssss",
70 out_sign="(ia{ss})", 70 out_sign="(ia{ss})",
71 method=self._eventGet, 71 method=self._eventGet,
72 async=True, 72 async_=True,
73 ) 73 )
74 host.bridge.addMethod( 74 host.bridge.addMethod(
75 "eventCreate", 75 "eventCreate",
76 ".plugin", 76 ".plugin",
77 in_sign="ia{ss}ssss", 77 in_sign="ia{ss}ssss",
78 out_sign="s", 78 out_sign="s",
79 method=self._eventCreate, 79 method=self._eventCreate,
80 async=True, 80 async_=True,
81 ) 81 )
82 host.bridge.addMethod( 82 host.bridge.addMethod(
83 "eventModify", 83 "eventModify",
84 ".plugin", 84 ".plugin",
85 in_sign="sssia{ss}s", 85 in_sign="sssia{ss}s",
86 out_sign="", 86 out_sign="",
87 method=self._eventModify, 87 method=self._eventModify,
88 async=True, 88 async_=True,
89 ) 89 )
90 host.bridge.addMethod( 90 host.bridge.addMethod(
91 "eventsList", 91 "eventsList",
92 ".plugin", 92 ".plugin",
93 in_sign="sss", 93 in_sign="sss",
94 out_sign="aa{ss}", 94 out_sign="aa{ss}",
95 method=self._eventsList, 95 method=self._eventsList,
96 async=True, 96 async_=True,
97 ) 97 )
98 host.bridge.addMethod( 98 host.bridge.addMethod(
99 "eventInviteeGet", 99 "eventInviteeGet",
100 ".plugin", 100 ".plugin",
101 in_sign="sss", 101 in_sign="sss",
102 out_sign="a{ss}", 102 out_sign="a{ss}",
103 method=self._eventInviteeGet, 103 method=self._eventInviteeGet,
104 async=True, 104 async_=True,
105 ) 105 )
106 host.bridge.addMethod( 106 host.bridge.addMethod(
107 "eventInviteeSet", 107 "eventInviteeSet",
108 ".plugin", 108 ".plugin",
109 in_sign="ssa{ss}s", 109 in_sign="ssa{ss}s",
110 out_sign="", 110 out_sign="",
111 method=self._eventInviteeSet, 111 method=self._eventInviteeSet,
112 async=True, 112 async_=True,
113 ) 113 )
114 host.bridge.addMethod( 114 host.bridge.addMethod(
115 "eventInviteesList", 115 "eventInviteesList",
116 ".plugin", 116 ".plugin",
117 in_sign="sss", 117 in_sign="sss",
118 out_sign="a{sa{ss}}", 118 out_sign="a{sa{ss}}",
119 method=self._eventInviteesList, 119 method=self._eventInviteesList,
120 async=True, 120 async_=True,
121 ), 121 ),
122 host.bridge.addMethod( 122 host.bridge.addMethod(
123 "eventInvite", 123 "eventInvite",
124 ".plugin", 124 ".plugin",
125 in_sign="sssss", 125 in_sign="sssss",
126 out_sign="", 126 out_sign="",
127 method=self._invite, 127 method=self._invite,
128 async=True, 128 async_=True,
129 ) 129 )
130 host.bridge.addMethod( 130 host.bridge.addMethod(
131 "eventInviteByEmail", 131 "eventInviteByEmail",
132 ".plugin", 132 ".plugin",
133 in_sign="ssssassssssss", 133 in_sign="ssssassssssss",
134 out_sign="", 134 out_sign="",
135 method=self._inviteByEmail, 135 method=self._inviteByEmail,
136 async=True, 136 async_=True,
137 ) 137 )
138 138
139 def getHandler(self, client): 139 def getHandler(self, client):
140 return EventsHandler(self) 140 return EventsHandler(self)
141 141
150 except StopIteration: 150 except StopIteration:
151 timestamp = -1 151 timestamp = -1
152 152
153 data = {} 153 data = {}
154 154
155 for key in (u"name",): 155 for key in ("name",):
156 try: 156 try:
157 data[key] = event_elt[key] 157 data[key] = event_elt[key]
158 except KeyError: 158 except KeyError:
159 continue 159 continue
160 160
161 for elt_name in (u"description",): 161 for elt_name in ("description",):
162 try: 162 try:
163 elt = next(event_elt.elements(NS_EVENT, elt_name)) 163 elt = next(event_elt.elements(NS_EVENT, elt_name))
164 except StopIteration: 164 except StopIteration:
165 continue 165 continue
166 else: 166 else:
167 data[elt_name] = unicode(elt) 167 data[elt_name] = str(elt)
168 168
169 for elt_name in (u"image", "background-image"): 169 for elt_name in ("image", "background-image"):
170 try: 170 try:
171 image_elt = next(event_elt.elements(NS_EVENT, elt_name)) 171 image_elt = next(event_elt.elements(NS_EVENT, elt_name))
172 data[elt_name] = image_elt["src"] 172 data[elt_name] = image_elt["src"]
173 except StopIteration: 173 except StopIteration:
174 continue 174 continue
175 except KeyError: 175 except KeyError:
176 log.warning(_(u"no src found for image")) 176 log.warning(_("no src found for image"))
177 177
178 for uri_type in (u"invitees", u"blog"): 178 for uri_type in ("invitees", "blog"):
179 try: 179 try:
180 elt = next(event_elt.elements(NS_EVENT, uri_type)) 180 elt = next(event_elt.elements(NS_EVENT, uri_type))
181 uri = data[uri_type + u"_uri"] = elt["uri"] 181 uri = data[uri_type + "_uri"] = elt["uri"]
182 uri_data = xmpp_uri.parseXMPPUri(uri) 182 uri_data = xmpp_uri.parseXMPPUri(uri)
183 if uri_data[u"type"] != u"pubsub": 183 if uri_data["type"] != "pubsub":
184 raise ValueError 184 raise ValueError
185 except StopIteration: 185 except StopIteration:
186 log.warning(_(u"no {uri_type} element found!").format(uri_type=uri_type)) 186 log.warning(_("no {uri_type} element found!").format(uri_type=uri_type))
187 except KeyError: 187 except KeyError:
188 log.warning(_(u"incomplete {uri_type} element").format(uri_type=uri_type)) 188 log.warning(_("incomplete {uri_type} element").format(uri_type=uri_type))
189 except ValueError: 189 except ValueError:
190 log.warning(_(u"bad {uri_type} element").format(uri_type=uri_type)) 190 log.warning(_("bad {uri_type} element").format(uri_type=uri_type))
191 else: 191 else:
192 data[uri_type + u"_service"] = uri_data[u"path"] 192 data[uri_type + "_service"] = uri_data["path"]
193 data[uri_type + u"_node"] = uri_data[u"node"] 193 data[uri_type + "_node"] = uri_data["node"]
194 194
195 for meta_elt in event_elt.elements(NS_EVENT, "meta"): 195 for meta_elt in event_elt.elements(NS_EVENT, "meta"):
196 key = meta_elt[u"name"] 196 key = meta_elt["name"]
197 if key in data: 197 if key in data:
198 log.warning( 198 log.warning(
199 u"Ignoring conflicting meta element: {xml}".format( 199 "Ignoring conflicting meta element: {xml}".format(
200 xml=meta_elt.toXml() 200 xml=meta_elt.toXml()
201 ) 201 )
202 ) 202 )
203 continue 203 continue
204 data[key] = unicode(meta_elt) 204 data[key] = str(meta_elt)
205 if event_elt.link: 205 if event_elt.link:
206 link_elt = event_elt.link 206 link_elt = event_elt.link
207 data["service"] = link_elt["service"] 207 data["service"] = link_elt["service"]
208 data["node"] = link_elt["node"] 208 data["node"] = link_elt["node"]
209 data["item"] = link_elt["item"] 209 data["item"] = link_elt["item"]
223 """ 223 """
224 if not id_: 224 if not id_:
225 id_ = NS_EVENT 225 id_ = NS_EVENT
226 items, metadata = yield self._p.getItems(client, service, node, item_ids=[id_]) 226 items, metadata = yield self._p.getItems(client, service, node, item_ids=[id_])
227 try: 227 try:
228 event_elt = next(items[0].elements(NS_EVENT, u"event")) 228 event_elt = next(items[0].elements(NS_EVENT, "event"))
229 except StopIteration: 229 except StopIteration:
230 raise exceptions.NotFound(_(u"No event element has been found")) 230 raise exceptions.NotFound(_("No event element has been found"))
231 except IndexError: 231 except IndexError:
232 raise exceptions.NotFound(_(u"No event with this id has been found")) 232 raise exceptions.NotFound(_("No event with this id has been found"))
233 defer.returnValue(event_elt) 233 defer.returnValue(event_elt)
234 234
235 def register(self, client, name, extra, service, node, event_id, item_elt, 235 def register(self, client, name, extra, service, node, event_id, item_elt,
236 creator=False): 236 creator=False):
237 """Register evenement in personal events list 237 """Register evenement in personal events list
247 link_elt = event_elt.addElement("link") 247 link_elt = event_elt.addElement("link")
248 link_elt["service"] = service.full() 248 link_elt["service"] = service.full()
249 link_elt["node"] = node 249 link_elt["node"] = node
250 link_elt["item"] = event_id 250 link_elt["item"] = event_id
251 __, event_data = self._parseEventElt(event_elt) 251 __, event_data = self._parseEventElt(event_elt)
252 name = event_data.get(u'name') 252 name = event_data.get('name')
253 if u'image' in event_data: 253 if 'image' in event_data:
254 extra = {u'thumb_url': event_data[u'image']} 254 extra = {'thumb_url': event_data['image']}
255 else: 255 else:
256 extra = None 256 extra = None
257 return self.host.plugins[u'LIST_INTEREST'].registerPubsub( 257 return self.host.plugins['LIST_INTEREST'].registerPubsub(
258 client, NS_EVENT, service, node, event_id, creator, 258 client, NS_EVENT, service, node, event_id, creator,
259 name=name, element=event_elt, extra=extra) 259 name=name, element=event_elt, extra=extra)
260 260
261 def _eventGet(self, service, node, id_=u"", profile_key=C.PROF_KEY_NONE): 261 def _eventGet(self, service, node, id_="", profile_key=C.PROF_KEY_NONE):
262 service = jid.JID(service) if service else None 262 service = jid.JID(service) if service else None
263 node = node if node else NS_EVENT 263 node = node if node else NS_EVENT
264 client = self.host.getClient(profile_key) 264 client = self.host.getClient(profile_key)
265 return self.eventGet(client, service, node, id_) 265 return self.eventGet(client, service, node, id_)
266 266
281 event_elt = yield self.getEventElement(client, service, node, id_) 281 event_elt = yield self.getEventElement(client, service, node, id_)
282 282
283 defer.returnValue(self._parseEventElt(event_elt)) 283 defer.returnValue(self._parseEventElt(event_elt))
284 284
285 def _eventCreate( 285 def _eventCreate(
286 self, timestamp, data, service, node, id_=u"", profile_key=C.PROF_KEY_NONE 286 self, timestamp, data, service, node, id_="", profile_key=C.PROF_KEY_NONE
287 ): 287 ):
288 service = jid.JID(service) if service else None 288 service = jid.JID(service) if service else None
289 node = node or None 289 node = node or None
290 client = self.host.getClient(profile_key) 290 client = self.host.getClient(profile_key)
291 data[u"register"] = C.bool(data.get(u"register", C.BOOL_FALSE)) 291 data["register"] = C.bool(data.get("register", C.BOOL_FALSE))
292 return self.eventCreate(client, timestamp, data, service, node, id_ or NS_EVENT) 292 return self.eventCreate(client, timestamp, data, service, node, id_ or NS_EVENT)
293 293
294 @defer.inlineCallbacks 294 @defer.inlineCallbacks
295 def eventCreate(self, client, timestamp, data, service, node=None, event_id=NS_EVENT): 295 def eventCreate(self, client, timestamp, data, service, node=None, event_id=NS_EVENT):
296 """Create or replace an event 296 """Create or replace an event
309 - background-image: image to use as background 309 - background-image: image to use as background
310 - register: bool, True if we want to register the event in our local list 310 - register: bool, True if we want to register the event in our local list
311 @return (unicode): created node 311 @return (unicode): created node
312 """ 312 """
313 if not event_id: 313 if not event_id:
314 raise ValueError(_(u"event_id must be set")) 314 raise ValueError(_("event_id must be set"))
315 if not service: 315 if not service:
316 service = client.jid.userhostJID() 316 service = client.jid.userhostJID()
317 if not node: 317 if not node:
318 node = NS_EVENT + u"__" + shortuuid.uuid() 318 node = NS_EVENT + "__" + shortuuid.uuid()
319 event_elt = domish.Element((NS_EVENT, "event")) 319 event_elt = domish.Element((NS_EVENT, "event"))
320 if timestamp is not None and timestamp != -1: 320 if timestamp is not None and timestamp != -1:
321 formatted_date = utils.xmpp_date(timestamp) 321 formatted_date = utils.xmpp_date(timestamp)
322 event_elt.addElement((NS_EVENT, "date"), content=formatted_date) 322 event_elt.addElement((NS_EVENT, "date"), content=formatted_date)
323 register = data.pop("register", False) 323 register = data.pop("register", False)
324 for key in (u"name",): 324 for key in ("name",):
325 if key in data: 325 if key in data:
326 event_elt[key] = data.pop(key) 326 event_elt[key] = data.pop(key)
327 for key in (u"description",): 327 for key in ("description",):
328 if key in data: 328 if key in data:
329 event_elt.addElement((NS_EVENT, key), content=data.pop(key)) 329 event_elt.addElement((NS_EVENT, key), content=data.pop(key))
330 for key in (u"image", u"background-image"): 330 for key in ("image", "background-image"):
331 if key in data: 331 if key in data:
332 elt = event_elt.addElement((NS_EVENT, key)) 332 elt = event_elt.addElement((NS_EVENT, key))
333 elt["src"] = data.pop(key) 333 elt["src"] = data.pop(key)
334 334
335 # we first create the invitees and blog nodes (if not specified in data) 335 # we first create the invitees and blog nodes (if not specified in data)
336 for uri_type in (u"invitees", u"blog"): 336 for uri_type in ("invitees", "blog"):
337 key = uri_type + u"_uri" 337 key = uri_type + "_uri"
338 for to_delete in (u"service", u"node"): 338 for to_delete in ("service", "node"):
339 k = uri_type + u"_" + to_delete 339 k = uri_type + "_" + to_delete
340 if k in data: 340 if k in data:
341 del data[k] 341 del data[k]
342 if key not in data: 342 if key not in data:
343 # FIXME: affiliate invitees 343 # FIXME: affiliate invitees
344 uri_node = yield self._p.createNode(client, service) 344 uri_node = yield self._p.createNode(client, service)
350 ) 350 )
351 uri_service = service 351 uri_service = service
352 else: 352 else:
353 uri = data.pop(key) 353 uri = data.pop(key)
354 uri_data = xmpp_uri.parseXMPPUri(uri) 354 uri_data = xmpp_uri.parseXMPPUri(uri)
355 if uri_data[u"type"] != u"pubsub": 355 if uri_data["type"] != "pubsub":
356 raise ValueError( 356 raise ValueError(
357 _(u"The given URI is not valid: {uri}").format(uri=uri) 357 _("The given URI is not valid: {uri}").format(uri=uri)
358 ) 358 )
359 uri_service = jid.JID(uri_data[u"path"]) 359 uri_service = jid.JID(uri_data["path"])
360 uri_node = uri_data[u"node"] 360 uri_node = uri_data["node"]
361 361
362 elt = event_elt.addElement((NS_EVENT, uri_type)) 362 elt = event_elt.addElement((NS_EVENT, uri_type))
363 elt["uri"] = xmpp_uri.buildXMPPUri( 363 elt["uri"] = xmpp_uri.buildXMPPUri(
364 "pubsub", path=uri_service.full(), node=uri_node 364 "pubsub", path=uri_service.full(), node=uri_node
365 ) 365 )
366 366
367 # remaining data are put in <meta> elements 367 # remaining data are put in <meta> elements
368 for key in data.keys(): 368 for key in list(data.keys()):
369 elt = event_elt.addElement((NS_EVENT, "meta"), content=data.pop(key)) 369 elt = event_elt.addElement((NS_EVENT, "meta"), content=data.pop(key))
370 elt["name"] = key 370 elt["name"] = key
371 371
372 item_elt = pubsub.Item(id=event_id, payload=event_elt) 372 item_elt = pubsub.Item(id=event_id, payload=event_elt)
373 try: 373 try:
374 # TODO: check auto-create, no need to create node first if available 374 # TODO: check auto-create, no need to create node first if available
375 node = yield self._p.createNode(client, service, nodeIdentifier=node) 375 node = yield self._p.createNode(client, service, nodeIdentifier=node)
376 except error.StanzaError as e: 376 except error.StanzaError as e:
377 if e.condition == u"conflict": 377 if e.condition == "conflict":
378 log.debug(_(u"requested node already exists")) 378 log.debug(_("requested node already exists"))
379 379
380 yield self._p.publish(client, service, node, items=[item_elt]) 380 yield self._p.publish(client, service, node, items=[item_elt])
381 381
382 if register: 382 if register:
383 yield self.register( 383 yield self.register(
386 386
387 def _eventModify(self, service, node, id_, timestamp_update, data_update, 387 def _eventModify(self, service, node, id_, timestamp_update, data_update,
388 profile_key=C.PROF_KEY_NONE): 388 profile_key=C.PROF_KEY_NONE):
389 service = jid.JID(service) if service else None 389 service = jid.JID(service) if service else None
390 if not node: 390 if not node:
391 raise ValueError(_(u"missing node")) 391 raise ValueError(_("missing node"))
392 client = self.host.getClient(profile_key) 392 client = self.host.getClient(profile_key)
393 return self.eventModify( 393 return self.eventModify(
394 client, service, node, id_ or NS_EVENT, timestamp_update or None, data_update 394 client, service, node, id_ or NS_EVENT, timestamp_update or None, data_update
395 ) 395 )
396 396
405 """ 405 """
406 event_timestamp, event_metadata = yield self.eventGet(client, service, node, id_) 406 event_timestamp, event_metadata = yield self.eventGet(client, service, node, id_)
407 new_timestamp = event_timestamp if timestamp_update is None else timestamp_update 407 new_timestamp = event_timestamp if timestamp_update is None else timestamp_update
408 new_data = event_metadata 408 new_data = event_metadata
409 if data_update: 409 if data_update:
410 for k, v in data_update.iteritems(): 410 for k, v in data_update.items():
411 new_data[k] = v 411 new_data[k] = v
412 yield self.eventCreate(client, new_timestamp, new_data, service, node, id_) 412 yield self.eventCreate(client, new_timestamp, new_data, service, node, id_)
413 413
414 def _eventsListSerialise(self, events): 414 def _eventsListSerialise(self, events):
415 for timestamp, data in events: 415 for timestamp, data in events:
416 data["date"] = unicode(timestamp) 416 data["date"] = str(timestamp)
417 data["creator"] = C.boolConst(data.get("creator", False)) 417 data["creator"] = C.boolConst(data.get("creator", False))
418 return [e[1] for e in events] 418 return [e[1] for e in events]
419 419
420 def _eventsList(self, service, node, profile): 420 def _eventsList(self, service, node, profile):
421 service = jid.JID(service) if service else None 421 service = jid.JID(service) if service else None
429 def eventsList(self, client, service, node=None): 429 def eventsList(self, client, service, node=None):
430 """Retrieve list of registered events 430 """Retrieve list of registered events
431 431
432 @return list(tuple(int, dict)): list of events (timestamp + metadata) 432 @return list(tuple(int, dict)): list of events (timestamp + metadata)
433 """ 433 """
434 items, metadata = yield self.host.plugins[u'LIST_INTEREST'].listInterests( 434 items, metadata = yield self.host.plugins['LIST_INTEREST'].listInterests(
435 client, service, node, namespace=NS_EVENT) 435 client, service, node, namespace=NS_EVENT)
436 events = [] 436 events = []
437 for item in items: 437 for item in items:
438 try: 438 try:
439 event_elt = next(item.interest.pubsub.elements(NS_EVENT, u"event")) 439 event_elt = next(item.interest.pubsub.elements(NS_EVENT, "event"))
440 except StopIteration: 440 except StopIteration:
441 log.warning( 441 log.warning(
442 _(u"No event found in item {item_id}, ignoring").format( 442 _("No event found in item {item_id}, ignoring").format(
443 item_id=item["id"]) 443 item_id=item["id"])
444 ) 444 )
445 else: 445 else:
446 timestamp, data = self._parseEventElt(event_elt) 446 timestamp, data = self._parseEventElt(event_elt)
447 events.append((timestamp, data)) 447 events.append((timestamp, data))
464 """ 464 """
465 try: 465 try:
466 items, metadata = yield self._p.getItems( 466 items, metadata = yield self._p.getItems(
467 client, service, node, item_ids=[client.jid.userhost()] 467 client, service, node, item_ids=[client.jid.userhost()]
468 ) 468 )
469 event_elt = next(items[0].elements(NS_EVENT, u"invitee")) 469 event_elt = next(items[0].elements(NS_EVENT, "invitee"))
470 except (exceptions.NotFound, IndexError): 470 except (exceptions.NotFound, IndexError):
471 # no item found, event data are not set yet 471 # no item found, event data are not set yet
472 defer.returnValue({}) 472 defer.returnValue({})
473 data = {} 473 data = {}
474 for key in (u"attend", u"guests"): 474 for key in ("attend", "guests"):
475 try: 475 try:
476 data[key] = event_elt[key] 476 data[key] = event_elt[key]
477 except KeyError: 477 except KeyError:
478 continue 478 continue
479 defer.returnValue(data) 479 defer.returnValue(data)
493 key can be: 493 key can be:
494 attend: one of "yes", "no", "maybe" 494 attend: one of "yes", "no", "maybe"
495 guests: an int 495 guests: an int
496 """ 496 """
497 event_elt = domish.Element((NS_EVENT, "invitee")) 497 event_elt = domish.Element((NS_EVENT, "invitee"))
498 for key in (u"attend", u"guests"): 498 for key in ("attend", "guests"):
499 try: 499 try:
500 event_elt[key] = data.pop(key) 500 event_elt[key] = data.pop(key)
501 except KeyError: 501 except KeyError:
502 pass 502 pass
503 item_elt = pubsub.Item(id=client.jid.userhost(), payload=event_elt) 503 item_elt = pubsub.Item(id=client.jid.userhost(), payload=event_elt)
520 """ 520 """
521 items, metadata = yield self._p.getItems(client, service, node) 521 items, metadata = yield self._p.getItems(client, service, node)
522 invitees = {} 522 invitees = {}
523 for item in items: 523 for item in items:
524 try: 524 try:
525 event_elt = next(item.elements(NS_EVENT, u"invitee")) 525 event_elt = next(item.elements(NS_EVENT, "invitee"))
526 except StopIteration: 526 except StopIteration:
527 # no item found, event data are not set yet 527 # no item found, event data are not set yet
528 log.warning(_( 528 log.warning(_(
529 u"no data found for {item_id} (service: {service}, node: {node})" 529 "no data found for {item_id} (service: {service}, node: {node})"
530 .format(item_id=item["id"], service=service, node=node))) 530 .format(item_id=item["id"], service=service, node=node)))
531 else: 531 else:
532 data = {} 532 data = {}
533 for key in (u"attend", u"guests"): 533 for key in ("attend", "guests"):
534 try: 534 try:
535 data[key] = event_elt[key] 535 data[key] = event_elt[key]
536 except KeyError: 536 except KeyError:
537 continue 537 continue
538 invitees[item["id"]] = data 538 invitees[item["id"]] = data
556 None to use client's PEP 556 None to use client's PEP
557 @param node(unicode): event node 557 @param node(unicode): event node
558 @param item_id(unicode): event id 558 @param item_id(unicode): event id
559 """ 559 """
560 # FIXME: handle name and extra 560 # FIXME: handle name and extra
561 name = u'' 561 name = ''
562 extra = {} 562 extra = {}
563 if self._b is None: 563 if self._b is None:
564 raise exceptions.FeatureNotFound( 564 raise exceptions.FeatureNotFound(
565 _(u'"XEP-0277" (blog) plugin is needed for this feature') 565 _('"XEP-0277" (blog) plugin is needed for this feature')
566 ) 566 )
567 if item_id is None: 567 if item_id is None:
568 item_id = NS_EVENT 568 item_id = NS_EVENT
569 569
570 # first we authorize our invitee to see the nodes of interest 570 # first we authorize our invitee to see the nodes of interest
571 yield self._p.setNodeAffiliations(client, service, node, {invitee_jid: u"member"}) 571 yield self._p.setNodeAffiliations(client, service, node, {invitee_jid: "member"})
572 log.debug(_(u"affiliation set on event node")) 572 log.debug(_("affiliation set on event node"))
573 __, event_data = yield self.eventGet(client, service, node, item_id) 573 __, event_data = yield self.eventGet(client, service, node, item_id)
574 log.debug(_(u"got event data")) 574 log.debug(_("got event data"))
575 invitees_service = jid.JID(event_data["invitees_service"]) 575 invitees_service = jid.JID(event_data["invitees_service"])
576 invitees_node = event_data["invitees_node"] 576 invitees_node = event_data["invitees_node"]
577 blog_service = jid.JID(event_data["blog_service"]) 577 blog_service = jid.JID(event_data["blog_service"])
578 blog_node = event_data["blog_node"] 578 blog_node = event_data["blog_node"]
579 yield self._p.setNodeAffiliations( 579 yield self._p.setNodeAffiliations(
580 client, invitees_service, invitees_node, {invitee_jid: u"publisher"} 580 client, invitees_service, invitees_node, {invitee_jid: "publisher"}
581 ) 581 )
582 log.debug(_(u"affiliation set on invitee node")) 582 log.debug(_("affiliation set on invitee node"))
583 yield self._p.setNodeAffiliations( 583 yield self._p.setNodeAffiliations(
584 client, blog_service, blog_node, {invitee_jid: u"member"} 584 client, blog_service, blog_node, {invitee_jid: "member"}
585 ) 585 )
586 blog_items, __ = yield self._b.mbGet(client, blog_service, blog_node, None) 586 blog_items, __ = yield self._b.mbGet(client, blog_service, blog_node, None)
587 587
588 for item in blog_items: 588 for item in blog_items:
589 try: 589 try:
590 comments_service = jid.JID(item["comments_service"]) 590 comments_service = jid.JID(item["comments_service"])
591 comments_node = item["comments_node"] 591 comments_node = item["comments_node"]
592 except KeyError: 592 except KeyError:
593 log.debug( 593 log.debug(
594 u"no comment service set for item {item_id}".format( 594 "no comment service set for item {item_id}".format(
595 item_id=item["id"] 595 item_id=item["id"]
596 ) 596 )
597 ) 597 )
598 else: 598 else:
599 yield self._p.setNodeAffiliations( 599 yield self._p.setNodeAffiliations(
600 client, comments_service, comments_node, {invitee_jid: u"publisher"} 600 client, comments_service, comments_node, {invitee_jid: "publisher"}
601 ) 601 )
602 log.debug(_(u"affiliation set on blog and comments nodes")) 602 log.debug(_("affiliation set on blog and comments nodes"))
603 603
604 # now we send the invitation 604 # now we send the invitation
605 pubsub_invitation = self.host.plugins[u'INVITATION'] 605 pubsub_invitation = self.host.plugins['INVITATION']
606 pubsub_invitation.sendPubsubInvitation(client, invitee_jid, service, node, 606 pubsub_invitation.sendPubsubInvitation(client, invitee_jid, service, node,
607 item_id, name, extra) 607 item_id, name, extra)
608 608
609 def _inviteByEmail(self, service, node, id_=NS_EVENT, email=u"", emails_extra=None, 609 def _inviteByEmail(self, service, node, id_=NS_EVENT, email="", emails_extra=None,
610 name=u"", host_name=u"", language=u"", url_template=u"", 610 name="", host_name="", language="", url_template="",
611 message_subject=u"", message_body=u"", 611 message_subject="", message_body="",
612 profile_key=C.PROF_KEY_NONE): 612 profile_key=C.PROF_KEY_NONE):
613 client = self.host.getClient(profile_key) 613 client = self.host.getClient(profile_key)
614 kwargs = { 614 kwargs = {
615 u"profile": client.profile, 615 "profile": client.profile,
616 u"emails_extra": [unicode(e) for e in emails_extra], 616 "emails_extra": [str(e) for e in emails_extra],
617 } 617 }
618 for key in ( 618 for key in (
619 "email", 619 "email",
620 "name", 620 "name",
621 "host_name", 621 "host_name",
623 "url_template", 623 "url_template",
624 "message_subject", 624 "message_subject",
625 "message_body", 625 "message_body",
626 ): 626 ):
627 value = locals()[key] 627 value = locals()[key]
628 kwargs[key] = unicode(value) 628 kwargs[key] = str(value)
629 return self.inviteByEmail( 629 return self.inviteByEmail(
630 client, jid.JID(service) if service else None, node, id_ or NS_EVENT, **kwargs 630 client, jid.JID(service) if service else None, node, id_ or NS_EVENT, **kwargs
631 ) 631 )
632 632
633 @defer.inlineCallbacks 633 @defer.inlineCallbacks
638 @param node(unicode): PubSub node of the event 638 @param node(unicode): PubSub node of the event
639 @param id_(unicode): id_ with even data 639 @param id_(unicode): id_ with even data
640 """ 640 """
641 if self._i is None: 641 if self._i is None:
642 raise exceptions.FeatureNotFound( 642 raise exceptions.FeatureNotFound(
643 _(u'"Invitations" plugin is needed for this feature') 643 _('"Invitations" plugin is needed for this feature')
644 ) 644 )
645 if self._b is None: 645 if self._b is None:
646 raise exceptions.FeatureNotFound( 646 raise exceptions.FeatureNotFound(
647 _(u'"XEP-0277" (blog) plugin is needed for this feature') 647 _('"XEP-0277" (blog) plugin is needed for this feature')
648 ) 648 )
649 service = service or client.jid.userhostJID() 649 service = service or client.jid.userhostJID()
650 event_uri = xmpp_uri.buildXMPPUri( 650 event_uri = xmpp_uri.buildXMPPUri(
651 "pubsub", path=service.full(), node=node, item=id_ 651 "pubsub", path=service.full(), node=node, item=id_
652 ) 652 )
653 kwargs["extra"] = {u"event_uri": event_uri} 653 kwargs["extra"] = {"event_uri": event_uri}
654 invitation_data = yield self._i.create(**kwargs) 654 invitation_data = yield self._i.create(**kwargs)
655 invitee_jid = invitation_data[u"jid"] 655 invitee_jid = invitation_data["jid"]
656 log.debug(_(u"invitation created")) 656 log.debug(_("invitation created"))
657 # now that we have a jid, we can send normal invitation 657 # now that we have a jid, we can send normal invitation
658 yield self.invite(client, invitee_jid, service, node, id_) 658 yield self.invite(client, invitee_jid, service, node, id_)
659 659
660 660
661 @implementer(iwokkel.IDisco)
661 class EventsHandler(XMPPHandler): 662 class EventsHandler(XMPPHandler):
662 implements(iwokkel.IDisco)
663 663
664 def __init__(self, plugin_parent): 664 def __init__(self, plugin_parent):
665 self.plugin_parent = plugin_parent 665 self.plugin_parent = plugin_parent
666 666
667 def getDiscoInfo(self, requestor, target, nodeIdentifier=""): 667 def getDiscoInfo(self, requestor, target, nodeIdentifier=""):