Mercurial > libervia-backend
comparison sat/plugins/plugin_misc_email_invitation.py @ 3335:83bc9d46a417
plugin email invitation: fixed create/simpleCreate + invitee_name:
- fixed invitationSimpleCreate signature
- fixed nicknames settings in create
- use async coroutines
- guest jid is now stored (as a string), avoiding the need to check profile to retrieve it
- invitee_name is now needed in invitationSimpleCreate
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 13 Aug 2020 23:46:18 +0200 |
parents | 44a9438d6608 |
children | e38ddaf477bd |
comparison
equal
deleted
inserted
replaced
3334:2cd54c72fae4 | 3335:83bc9d46a417 |
---|---|
31 | 31 |
32 log = getLogger(__name__) | 32 log = getLogger(__name__) |
33 | 33 |
34 | 34 |
35 PLUGIN_INFO = { | 35 PLUGIN_INFO = { |
36 C.PI_NAME: "Invitations", | 36 C.PI_NAME: "Email Invitations", |
37 C.PI_IMPORT_NAME: "EMAIL_INVITATION", | 37 C.PI_IMPORT_NAME: "EMAIL_INVITATION", |
38 C.PI_TYPE: C.PLUG_TYPE_MISC, | 38 C.PI_TYPE: C.PLUG_TYPE_MISC, |
39 C.PI_DEPENDENCIES: ['XEP-0077'], | 39 C.PI_DEPENDENCIES: ['XEP-0077'], |
40 C.PI_RECOMMENDATIONS: ["IDENTITY"], | 40 C.PI_RECOMMENDATIONS: ["IDENTITY"], |
41 C.PI_MAIN: "InvitationsPlugin", | 41 C.PI_MAIN: "InvitationsPlugin", |
88 async_=True) | 88 async_=True) |
89 host.bridge.addMethod("invitationList", ".plugin", in_sign='s', | 89 host.bridge.addMethod("invitationList", ".plugin", in_sign='s', |
90 out_sign='a{sa{ss}}', | 90 out_sign='a{sa{ss}}', |
91 method=self._list, | 91 method=self._list, |
92 async_=True) | 92 async_=True) |
93 host.bridge.addMethod("invitationSimpleCreate", ".plugin", in_sign='', | 93 host.bridge.addMethod("invitationSimpleCreate", ".plugin", in_sign='sssss', |
94 out_sign='a{ss}', | 94 out_sign='a{ss}', |
95 method=self._simpleCreate, | 95 method=self._simpleCreate, |
96 async_=True) | 96 async_=True) |
97 | 97 |
98 def checkExtra(self, extra): | 98 def checkExtra(self, extra): |
123 for key in ("jid_", "password", "name", "host_name", "email", "language", | 123 for key in ("jid_", "password", "name", "host_name", "email", "language", |
124 "url_template", "message_subject", "message_body", "profile"): | 124 "url_template", "message_subject", "message_body", "profile"): |
125 value = locals()[key] | 125 value = locals()[key] |
126 if value: | 126 if value: |
127 kwargs[key] = str(value) | 127 kwargs[key] = str(value) |
128 d = self.create(**kwargs) | 128 return defer.ensureDeferred(self.create(**kwargs)) |
129 def serialize(data): | 129 |
130 data[KEY_JID] = data[KEY_JID].full() | 130 async def create(self, **kwargs): |
131 return data | |
132 d.addCallback(serialize) | |
133 return d | |
134 | |
135 @defer.inlineCallbacks | |
136 def create(self, **kwargs): | |
137 r"""Create an invitation | 131 r"""Create an invitation |
138 | 132 |
139 This will create an XMPP account and a profile, and use a UUID to retrieve them. | 133 This will create an XMPP account and a profile, and use a UUID to retrieve them. |
140 The profile is automatically generated in the form guest@@[UUID], this way they | 134 The profile is automatically generated in the form guest@@[UUID], this way they |
141 can be retrieved easily | 135 can be retrieved easily |
242 jid_ = jid.JID(jid_) | 236 jid_ = jid.JID(jid_) |
243 if jid_.user: | 237 if jid_.user: |
244 # we don't register account if there is no user as anonymous login is then | 238 # we don't register account if there is no user as anonymous login is then |
245 # used | 239 # used |
246 try: | 240 try: |
247 yield self.host.plugins['XEP-0077'].registerNewAccount(jid_, password) | 241 await self.host.plugins['XEP-0077'].registerNewAccount(jid_, password) |
248 except error.StanzaError as e: | 242 except error.StanzaError as e: |
249 prefix = jid_.user | 243 prefix = jid_.user |
250 idx = 0 | 244 idx = 0 |
251 while e.condition == 'conflict': | 245 while e.condition == 'conflict': |
252 if idx >= SUFFIX_MAX: | 246 if idx >= SUFFIX_MAX: |
253 raise exceptions.ConflictError(_("Can't create XMPP account")) | 247 raise exceptions.ConflictError(_("Can't create XMPP account")) |
254 jid_.user = prefix + '_' + str(idx) | 248 jid_.user = prefix + '_' + str(idx) |
255 log.info(_("requested jid already exists, trying with {}".format( | 249 log.info(_("requested jid already exists, trying with {}".format( |
256 jid_.full()))) | 250 jid_.full()))) |
257 try: | 251 try: |
258 yield self.host.plugins['XEP-0077'].registerNewAccount(jid_, | 252 await self.host.plugins['XEP-0077'].registerNewAccount(jid_, |
259 password) | 253 password) |
260 except error.StanzaError: | 254 except error.StanzaError: |
261 idx += 1 | 255 idx += 1 |
262 else: | 256 else: |
263 break | 257 break |
268 | 262 |
269 ## profile creation | 263 ## profile creation |
270 | 264 |
271 extra[KEY_GUEST_PROFILE] = guest_profile = INVITEE_PROFILE_TPL.format(uuid=id_) | 265 extra[KEY_GUEST_PROFILE] = guest_profile = INVITEE_PROFILE_TPL.format(uuid=id_) |
272 # profile creation should not fail as we generate unique name ourselves | 266 # profile creation should not fail as we generate unique name ourselves |
273 yield self.host.memory.createProfile(guest_profile, password) | 267 await self.host.memory.createProfile(guest_profile, password) |
274 yield self.host.memory.startSession(password, guest_profile) | 268 await self.host.memory.startSession(password, guest_profile) |
275 yield self.host.memory.setParam("JabberID", jid_.full(), "Connection", | 269 await self.host.memory.setParam("JabberID", jid_.full(), "Connection", |
276 profile_key=guest_profile) | 270 profile_key=guest_profile) |
277 yield self.host.memory.setParam("Password", password, "Connection", | 271 await self.host.memory.setParam("Password", password, "Connection", |
278 profile_key=guest_profile) | 272 profile_key=guest_profile) |
279 name = kwargs.pop('name', None) | 273 name = kwargs.pop('name', None) |
280 if name is not None: | 274 if name is not None: |
281 extra['name'] = name | 275 extra['name'] = name |
282 try: | 276 try: |
283 id_plugin = self.host.plugins['IDENTITY'] | 277 id_plugin = self.host.plugins['IDENTITY'] |
284 except KeyError: | 278 except KeyError: |
285 pass | 279 pass |
286 else: | 280 else: |
287 yield defer.ensureDeferred(self.host.connect(guest_profile, password)) | 281 await self.host.connect(guest_profile, password) |
288 guest_client = self.host.getClient(guest_profile) | 282 guest_client = self.host.getClient(guest_profile) |
289 yield id_plugin.setIdentity(guest_client, {'nick': name}) | 283 await id_plugin.setIdentity(guest_client, {'nicknames': [name]}) |
290 yield self.host.disconnect(guest_profile) | 284 await self.host.disconnect(guest_profile) |
291 | 285 |
292 ## email | 286 ## email |
293 language = kwargs.pop('language', None) | 287 language = kwargs.pop('language', None) |
294 if language is not None: | 288 if language is not None: |
295 extra['language'] = language.strip() | 289 extra['language'] = language.strip() |
321 format_args['host_name'] = extra['host_name'] = host_name | 315 format_args['host_name'] = extra['host_name'] = host_name |
322 | 316 |
323 invite_url = url_template.format(**format_args) | 317 invite_url = url_template.format(**format_args) |
324 format_args['url'] = invite_url | 318 format_args['url'] = invite_url |
325 | 319 |
326 yield sat_email.sendEmail( | 320 await sat_email.sendEmail( |
327 self.host.memory.config, | 321 self.host.memory.config, |
328 [email] + emails_extra, | 322 [email] + emails_extra, |
329 (kwargs.pop('message_subject', None) or DEFAULT_SUBJECT).format( | 323 (kwargs.pop('message_subject', None) or DEFAULT_SUBJECT).format( |
330 **format_args), | 324 **format_args), |
331 (kwargs.pop('message_body', None) or DEFAULT_BODY).format(**format_args), | 325 (kwargs.pop('message_body', None) or DEFAULT_BODY).format(**format_args), |
332 ) | 326 ) |
333 | 327 |
328 | |
329 if kwargs: | |
330 log.warning(_("Not all arguments have been consumed: {}").format(kwargs)) | |
331 | |
332 extra[KEY_JID] = jid_.full() | |
333 | |
334 ## extra data saving | 334 ## extra data saving |
335 self.invitations[id_] = extra | 335 self.invitations[id_] = extra |
336 | 336 |
337 if kwargs: | |
338 log.warning(_("Not all arguments have been consumed: {}").format(kwargs)) | |
339 | |
340 extra[KEY_ID] = id_ | 337 extra[KEY_ID] = id_ |
341 extra[KEY_JID] = jid_ | 338 |
342 defer.returnValue(extra) | 339 return extra |
343 | 340 |
344 def _simpleCreate(self, invitee_email, url_template, extra_s, profile): | 341 def _simpleCreate(self, invitee_email, invitee_name, url_template, extra_s, profile): |
345 client = self.host.getClient(profile) | 342 client = self.host.getClient(profile) |
346 # FIXME: needed because python-dbus use a specific string class | 343 # FIXME: needed because python-dbus use a specific string class |
347 invitee_email = str(invitee_email) | 344 invitee_email = str(invitee_email) |
345 invitee_name = str(invitee_name) | |
348 url_template = str(url_template) | 346 url_template = str(url_template) |
349 extra = data_format.deserialise(extra_s) | 347 extra = data_format.deserialise(extra_s) |
350 d = defer.ensureDeferred( | 348 d = defer.ensureDeferred( |
351 self.simpleCreate(client, invitee_email, url_template, extra) | 349 self.simpleCreate(client, invitee_email, invitee_name, url_template, extra) |
352 ) | 350 ) |
353 d.addCallback(lambda data: {k: str(v) for k,v in data.items()}) | 351 d.addCallback(lambda data: {k: str(v) for k,v in data.items()}) |
354 return d | 352 return d |
355 | 353 |
356 async def simpleCreate(self, client, invitee_email, url_template, extra): | 354 async def simpleCreate( |
355 self, client, invitee_email, invitee_name, url_template, extra): | |
357 """Simplified method to invite somebody by email""" | 356 """Simplified method to invite somebody by email""" |
358 return await self.create( | 357 return await self.create( |
358 name=invitee_name, | |
359 email=invitee_email, | 359 email=invitee_email, |
360 url_template=url_template, | 360 url_template=url_template, |
361 profile=client.profile, | 361 profile=client.profile, |
362 ) | 362 ) |
363 | 363 |
412 d = self.invitations[id_] | 412 d = self.invitations[id_] |
413 d.addCallback(gotCurrentData) | 413 d.addCallback(gotCurrentData) |
414 return d | 414 return d |
415 | 415 |
416 def _list(self, profile=C.PROF_KEY_NONE): | 416 def _list(self, profile=C.PROF_KEY_NONE): |
417 return self.list(profile) | 417 return defer.ensureDeferred(self.list(profile)) |
418 | 418 |
419 @defer.inlineCallbacks | 419 async def list(self, profile=C.PROF_KEY_NONE): |
420 def list(self, profile=C.PROF_KEY_NONE): | |
421 """List invitations | 420 """List invitations |
422 | 421 |
423 @param profile(unicode): return invitation linked to this profile only | 422 @param profile(unicode): return invitation linked to this profile only |
424 C.PROF_KEY_NONE: don't filter invitations | 423 C.PROF_KEY_NONE: don't filter invitations |
425 @return list(unicode): invitations uids | 424 @return list(unicode): invitations uids |
426 """ | 425 """ |
427 invitations = yield self.invitations.all() | 426 invitations = await self.invitations.all() |
428 if profile != C.PROF_KEY_NONE: | 427 if profile != C.PROF_KEY_NONE: |
429 invitations = {id_:data for id_, data in invitations.items() | 428 invitations = {id_:data for id_, data in invitations.items() |
430 if data.get('profile') == profile} | 429 if data.get('profile') == profile} |
431 | 430 |
432 defer.returnValue(invitations) | 431 return invitations |