Mercurial > libervia-backend
comparison libervia/backend/plugins/plugin_misc_email_invitation.py @ 4270:0d7bb4df2343
Reformatted code base using black.
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 19 Jun 2024 18:44:57 +0200 |
parents | 4b842c1fb686 |
children |
comparison
equal
deleted
inserted
replaced
4269:64a85ce8be70 | 4270:0d7bb4df2343 |
---|---|
36 | 36 |
37 PLUGIN_INFO = { | 37 PLUGIN_INFO = { |
38 C.PI_NAME: "Email Invitations", | 38 C.PI_NAME: "Email Invitations", |
39 C.PI_IMPORT_NAME: "EMAIL_INVITATION", | 39 C.PI_IMPORT_NAME: "EMAIL_INVITATION", |
40 C.PI_TYPE: C.PLUG_TYPE_MISC, | 40 C.PI_TYPE: C.PLUG_TYPE_MISC, |
41 C.PI_DEPENDENCIES: ['XEP-0077'], | 41 C.PI_DEPENDENCIES: ["XEP-0077"], |
42 C.PI_RECOMMENDATIONS: ["IDENTITY"], | 42 C.PI_RECOMMENDATIONS: ["IDENTITY"], |
43 C.PI_MAIN: "InvitationsPlugin", | 43 C.PI_MAIN: "InvitationsPlugin", |
44 C.PI_HANDLER: "no", | 44 C.PI_HANDLER: "no", |
45 C.PI_DESCRIPTION: _("""invitation of people without XMPP account""") | 45 C.PI_DESCRIPTION: _("""invitation of people without XMPP account"""), |
46 } | 46 } |
47 | 47 |
48 | 48 |
49 SUFFIX_MAX = 5 | 49 SUFFIX_MAX = 5 |
50 INVITEE_PROFILE_TPL = "guest@@{uuid}" | 50 INVITEE_PROFILE_TPL = "guest@@{uuid}" |
51 KEY_ID = 'id' | 51 KEY_ID = "id" |
52 KEY_JID = 'jid' | 52 KEY_JID = "jid" |
53 KEY_CREATED = 'created' | 53 KEY_CREATED = "created" |
54 KEY_LAST_CONNECTION = 'last_connection' | 54 KEY_LAST_CONNECTION = "last_connection" |
55 KEY_GUEST_PROFILE = 'guest_profile' | 55 KEY_GUEST_PROFILE = "guest_profile" |
56 KEY_PASSWORD = 'password' | 56 KEY_PASSWORD = "password" |
57 KEY_EMAILS_EXTRA = 'emails_extra' | 57 KEY_EMAILS_EXTRA = "emails_extra" |
58 EXTRA_RESERVED = {KEY_ID, KEY_JID, KEY_CREATED, 'jid_', 'jid', KEY_LAST_CONNECTION, | 58 EXTRA_RESERVED = { |
59 KEY_GUEST_PROFILE, KEY_PASSWORD, KEY_EMAILS_EXTRA} | 59 KEY_ID, |
60 KEY_JID, | |
61 KEY_CREATED, | |
62 "jid_", | |
63 "jid", | |
64 KEY_LAST_CONNECTION, | |
65 KEY_GUEST_PROFILE, | |
66 KEY_PASSWORD, | |
67 KEY_EMAILS_EXTRA, | |
68 } | |
60 DEFAULT_SUBJECT = D_("You have been invited by {host_name} to {app_name}") | 69 DEFAULT_SUBJECT = D_("You have been invited by {host_name} to {app_name}") |
61 DEFAULT_BODY = D_("""Hello {name}! | 70 DEFAULT_BODY = D_( |
71 """Hello {name}! | |
62 | 72 |
63 You have received an invitation from {host_name} to participate to "{app_name}". | 73 You have received an invitation from {host_name} to participate to "{app_name}". |
64 To join, you just have to click on the following URL: | 74 To join, you just have to click on the following URL: |
65 {url} | 75 {url} |
66 | 76 |
67 Please note that this URL should not be shared with anybody! | 77 Please note that this URL should not be shared with anybody! |
68 If you want more details on {app_name}, you can check {app_url}. | 78 If you want more details on {app_name}, you can check {app_url}. |
69 | 79 |
70 Welcome! | 80 Welcome! |
71 """) | 81 """ |
82 ) | |
72 | 83 |
73 | 84 |
74 class InvitationsPlugin(object): | 85 class InvitationsPlugin(object): |
75 | 86 |
76 def __init__(self, host): | 87 def __init__(self, host): |
77 log.info(_("plugin Invitations initialization")) | 88 log.info(_("plugin Invitations initialization")) |
78 self.host = host | 89 self.host = host |
79 self.invitations = persistent.LazyPersistentBinaryDict('invitations') | 90 self.invitations = persistent.LazyPersistentBinaryDict("invitations") |
80 host.bridge.add_method("invitation_create", ".plugin", in_sign='sasssssssssa{ss}s', | 91 host.bridge.add_method( |
81 out_sign='a{ss}', | 92 "invitation_create", |
82 method=self._create, | 93 ".plugin", |
83 async_=True) | 94 in_sign="sasssssssssa{ss}s", |
84 host.bridge.add_method("invitation_get", ".plugin", in_sign='s', out_sign='a{ss}', | 95 out_sign="a{ss}", |
85 method=self.get, | 96 method=self._create, |
86 async_=True) | 97 async_=True, |
87 host.bridge.add_method("invitation_delete", ".plugin", in_sign='s', out_sign='', | 98 ) |
88 method=self._delete, | 99 host.bridge.add_method( |
89 async_=True) | 100 "invitation_get", |
90 host.bridge.add_method("invitation_modify", ".plugin", in_sign='sa{ss}b', | 101 ".plugin", |
91 out_sign='', | 102 in_sign="s", |
92 method=self._modify, | 103 out_sign="a{ss}", |
93 async_=True) | 104 method=self.get, |
94 host.bridge.add_method("invitation_list", ".plugin", in_sign='s', | 105 async_=True, |
95 out_sign='a{sa{ss}}', | 106 ) |
96 method=self._list, | 107 host.bridge.add_method( |
97 async_=True) | 108 "invitation_delete", |
98 host.bridge.add_method("invitation_simple_create", ".plugin", in_sign='sssss', | 109 ".plugin", |
99 out_sign='a{ss}', | 110 in_sign="s", |
100 method=self._simple_create, | 111 out_sign="", |
101 async_=True) | 112 method=self._delete, |
113 async_=True, | |
114 ) | |
115 host.bridge.add_method( | |
116 "invitation_modify", | |
117 ".plugin", | |
118 in_sign="sa{ss}b", | |
119 out_sign="", | |
120 method=self._modify, | |
121 async_=True, | |
122 ) | |
123 host.bridge.add_method( | |
124 "invitation_list", | |
125 ".plugin", | |
126 in_sign="s", | |
127 out_sign="a{sa{ss}}", | |
128 method=self._list, | |
129 async_=True, | |
130 ) | |
131 host.bridge.add_method( | |
132 "invitation_simple_create", | |
133 ".plugin", | |
134 in_sign="sssss", | |
135 out_sign="a{ss}", | |
136 method=self._simple_create, | |
137 async_=True, | |
138 ) | |
102 | 139 |
103 def check_extra(self, extra): | 140 def check_extra(self, extra): |
104 if EXTRA_RESERVED.intersection(extra): | 141 if EXTRA_RESERVED.intersection(extra): |
105 raise ValueError( | 142 raise ValueError( |
106 _("You can't use following key(s) in extra, they are reserved: {}") | 143 _( |
107 .format(', '.join(EXTRA_RESERVED.intersection(extra)))) | 144 "You can't use following key(s) in extra, they are reserved: {}" |
108 | 145 ).format(", ".join(EXTRA_RESERVED.intersection(extra))) |
109 def _create(self, email='', emails_extra=None, jid_='', password='', name='', | 146 ) |
110 host_name='', language='', url_template='', message_subject='', | 147 |
111 message_body='', extra=None, profile=''): | 148 def _create( |
149 self, | |
150 email="", | |
151 emails_extra=None, | |
152 jid_="", | |
153 password="", | |
154 name="", | |
155 host_name="", | |
156 language="", | |
157 url_template="", | |
158 message_subject="", | |
159 message_body="", | |
160 extra=None, | |
161 profile="", | |
162 ): | |
112 # XXX: we don't use **kwargs here to keep arguments name for introspection with | 163 # XXX: we don't use **kwargs here to keep arguments name for introspection with |
113 # D-Bus bridge | 164 # D-Bus bridge |
114 if emails_extra is None: | 165 if emails_extra is None: |
115 emails_extra = [] | 166 emails_extra = [] |
116 | 167 |
117 if extra is None: | 168 if extra is None: |
118 extra = {} | 169 extra = {} |
119 else: | 170 else: |
120 extra = {str(k): str(v) for k,v in extra.items()} | 171 extra = {str(k): str(v) for k, v in extra.items()} |
121 | 172 |
122 kwargs = {"extra": extra, | 173 kwargs = {"extra": extra, KEY_EMAILS_EXTRA: [str(e) for e in emails_extra]} |
123 KEY_EMAILS_EXTRA: [str(e) for e in emails_extra] | |
124 } | |
125 | 174 |
126 # we need to be sure that values are unicode, else they won't be pickled correctly | 175 # we need to be sure that values are unicode, else they won't be pickled correctly |
127 # with D-Bus | 176 # with D-Bus |
128 for key in ("jid_", "password", "name", "host_name", "email", "language", | 177 for key in ( |
129 "url_template", "message_subject", "message_body", "profile"): | 178 "jid_", |
179 "password", | |
180 "name", | |
181 "host_name", | |
182 "email", | |
183 "language", | |
184 "url_template", | |
185 "message_subject", | |
186 "message_body", | |
187 "profile", | |
188 ): | |
130 value = locals()[key] | 189 value = locals()[key] |
131 if value: | 190 if value: |
132 kwargs[key] = str(value) | 191 kwargs[key] = str(value) |
133 return defer.ensureDeferred(self.create(**kwargs)) | 192 return defer.ensureDeferred(self.create(**kwargs)) |
134 | 193 |
150 if invitation.get("email") == email: | 209 if invitation.get("email") == email: |
151 invitation[KEY_ID] = id_ | 210 invitation[KEY_ID] = id_ |
152 return invitation | 211 return invitation |
153 | 212 |
154 async def _create_account_and_profile( | 213 async def _create_account_and_profile( |
155 self, | 214 self, id_: str, kwargs: dict, extra: dict |
156 id_: str, | |
157 kwargs: dict, | |
158 extra: dict | |
159 ) -> None: | 215 ) -> None: |
160 """Create XMPP account and Libervia profile for guest""" | 216 """Create XMPP account and Libervia profile for guest""" |
161 ## XMPP account creation | 217 ## XMPP account creation |
162 password = kwargs.pop('password', None) | 218 password = kwargs.pop("password", None) |
163 if password is None: | 219 if password is None: |
164 password = utils.generate_password() | 220 password = utils.generate_password() |
165 assert password | 221 assert password |
166 # XXX: password is here saved in clear in database | 222 # XXX: password is here saved in clear in database |
167 # it is needed for invitation as the same password is used for profile | 223 # it is needed for invitation as the same password is used for profile |
168 # and SàT need to be able to automatically open the profile with the uuid | 224 # and SàT need to be able to automatically open the profile with the uuid |
169 # FIXME: we could add an extra encryption key which would be used with the | 225 # FIXME: we could add an extra encryption key which would be used with the |
170 # uuid when the invitee is connecting (e.g. with URL). This key would | 226 # uuid when the invitee is connecting (e.g. with URL). This key would |
171 # not be saved and could be used to encrypt profile password. | 227 # not be saved and could be used to encrypt profile password. |
172 extra[KEY_PASSWORD] = password | 228 extra[KEY_PASSWORD] = password |
173 | 229 |
174 jid_ = kwargs.pop('jid_', None) | 230 jid_ = kwargs.pop("jid_", None) |
175 if not jid_: | 231 if not jid_: |
176 domain = self.host.memory.config_get(None, 'xmpp_domain') | 232 domain = self.host.memory.config_get(None, "xmpp_domain") |
177 if not domain: | 233 if not domain: |
178 # TODO: fallback to profile's domain | 234 # TODO: fallback to profile's domain |
179 raise ValueError(_("You need to specify xmpp_domain in sat.conf")) | 235 raise ValueError(_("You need to specify xmpp_domain in sat.conf")) |
180 jid_ = "invitation-{uuid}@{domain}".format(uuid=shortuuid.uuid(), | 236 jid_ = "invitation-{uuid}@{domain}".format( |
181 domain=domain) | 237 uuid=shortuuid.uuid(), domain=domain |
238 ) | |
182 jid_ = jid.JID(jid_) | 239 jid_ = jid.JID(jid_) |
183 extra[KEY_JID] = jid_.full() | 240 extra[KEY_JID] = jid_.full() |
184 | 241 |
185 if jid_.user: | 242 if jid_.user: |
186 # we don't register account if there is no user as anonymous login is then | 243 # we don't register account if there is no user as anonymous login is then |
187 # used | 244 # used |
188 try: | 245 try: |
189 await self.host.plugins['XEP-0077'].register_new_account(jid_, password) | 246 await self.host.plugins["XEP-0077"].register_new_account(jid_, password) |
190 except error.StanzaError as e: | 247 except error.StanzaError as e: |
191 prefix = jid_.user | 248 prefix = jid_.user |
192 idx = 0 | 249 idx = 0 |
193 while e.condition == 'conflict': | 250 while e.condition == "conflict": |
194 if idx >= SUFFIX_MAX: | 251 if idx >= SUFFIX_MAX: |
195 raise exceptions.ConflictError(_("Can't create XMPP account")) | 252 raise exceptions.ConflictError(_("Can't create XMPP account")) |
196 jid_.user = prefix + '_' + str(idx) | 253 jid_.user = prefix + "_" + str(idx) |
197 log.info(_("requested jid already exists, trying with {}".format( | 254 log.info( |
198 jid_.full()))) | 255 _( |
256 "requested jid already exists, trying with {}".format( | |
257 jid_.full() | |
258 ) | |
259 ) | |
260 ) | |
199 try: | 261 try: |
200 await self.host.plugins['XEP-0077'].register_new_account( | 262 await self.host.plugins["XEP-0077"].register_new_account( |
201 jid_, | 263 jid_, password |
202 password | |
203 ) | 264 ) |
204 except error.StanzaError: | 265 except error.StanzaError: |
205 idx += 1 | 266 idx += 1 |
206 else: | 267 else: |
207 break | 268 break |
208 if e.condition != 'conflict': | 269 if e.condition != "conflict": |
209 raise e | 270 raise e |
210 | 271 |
211 log.info(_("account {jid_} created").format(jid_=jid_.full())) | 272 log.info(_("account {jid_} created").format(jid_=jid_.full())) |
212 | 273 |
213 ## profile creation | 274 ## profile creation |
214 | 275 |
215 extra[KEY_GUEST_PROFILE] = guest_profile = INVITEE_PROFILE_TPL.format( | 276 extra[KEY_GUEST_PROFILE] = guest_profile = INVITEE_PROFILE_TPL.format(uuid=id_) |
216 uuid=id_ | |
217 ) | |
218 # profile creation should not fail as we generate unique name ourselves | 277 # profile creation should not fail as we generate unique name ourselves |
219 await self.host.memory.create_profile(guest_profile, password) | 278 await self.host.memory.create_profile(guest_profile, password) |
220 await self.host.memory.start_session(password, guest_profile) | 279 await self.host.memory.start_session(password, guest_profile) |
221 await self.host.memory.param_set("JabberID", jid_.full(), "Connection", | 280 await self.host.memory.param_set( |
222 profile_key=guest_profile) | 281 "JabberID", jid_.full(), "Connection", profile_key=guest_profile |
223 await self.host.memory.param_set("Password", password, "Connection", | 282 ) |
224 profile_key=guest_profile) | 283 await self.host.memory.param_set( |
284 "Password", password, "Connection", profile_key=guest_profile | |
285 ) | |
225 | 286 |
226 async def create(self, **kwargs): | 287 async def create(self, **kwargs): |
227 r"""Create an invitation | 288 r"""Create an invitation |
228 | 289 |
229 This will create an XMPP account and a profile, and use a UUID to retrieve them. | 290 This will create an XMPP account and a profile, and use a UUID to retrieve them. |
282 @return (dict[unicode, unicode]): dictionary with: | 343 @return (dict[unicode, unicode]): dictionary with: |
283 - UUID associated with the invitee (key: id) | 344 - UUID associated with the invitee (key: id) |
284 - filled extra dictionary, as saved in the databae | 345 - filled extra dictionary, as saved in the databae |
285 """ | 346 """ |
286 ## initial checks | 347 ## initial checks |
287 extra = kwargs.pop('extra', {}) | 348 extra = kwargs.pop("extra", {}) |
288 if set(kwargs).intersection(extra): | 349 if set(kwargs).intersection(extra): |
289 raise ValueError( | 350 raise ValueError( |
290 _("You can't use following key(s) in both args and extra: {}").format( | 351 _("You can't use following key(s) in both args and extra: {}").format( |
291 ', '.join(set(kwargs).intersection(extra)))) | 352 ", ".join(set(kwargs).intersection(extra)) |
353 ) | |
354 ) | |
292 | 355 |
293 self.check_extra(extra) | 356 self.check_extra(extra) |
294 | 357 |
295 email = kwargs.pop('email', None) | 358 email = kwargs.pop("email", None) |
296 | 359 |
297 existing = await self.get_existing_invitation(email) | 360 existing = await self.get_existing_invitation(email) |
298 if existing is not None: | 361 if existing is not None: |
299 log.info(f"There is already an invitation for {email!r}") | 362 log.info(f"There is already an invitation for {email!r}") |
300 extra.update(existing) | 363 extra.update(existing) |
301 del extra[KEY_ID] | 364 del extra[KEY_ID] |
302 | 365 |
303 emails_extra = kwargs.pop('emails_extra', []) | 366 emails_extra = kwargs.pop("emails_extra", []) |
304 if not email and emails_extra: | 367 if not email and emails_extra: |
305 raise ValueError( | 368 raise ValueError( |
306 _('You need to provide a main email address before using emails_extra')) | 369 _("You need to provide a main email address before using emails_extra") |
307 | 370 ) |
308 if (email is not None | 371 |
309 and not 'url_template' in kwargs | 372 if ( |
310 and not 'message_body' in kwargs): | 373 email is not None |
374 and not "url_template" in kwargs | |
375 and not "message_body" in kwargs | |
376 ): | |
311 raise ValueError( | 377 raise ValueError( |
312 _("You need to provide url_template if you use default message body")) | 378 _("You need to provide url_template if you use default message body") |
379 ) | |
313 | 380 |
314 ## uuid | 381 ## uuid |
315 log.info(_("creating an invitation")) | 382 log.info(_("creating an invitation")) |
316 id_ = existing[KEY_ID] if existing else str(shortuuid.uuid()) | 383 id_ = existing[KEY_ID] if existing else str(shortuuid.uuid()) |
317 | 384 |
318 if existing is None: | 385 if existing is None: |
319 await self._create_account_and_profile(id_, kwargs, extra) | 386 await self._create_account_and_profile(id_, kwargs, extra) |
320 | 387 |
321 profile = kwargs.pop('profile', None) | 388 profile = kwargs.pop("profile", None) |
322 guest_profile = extra[KEY_GUEST_PROFILE] | 389 guest_profile = extra[KEY_GUEST_PROFILE] |
323 jid_ = jid.JID(extra[KEY_JID]) | 390 jid_ = jid.JID(extra[KEY_JID]) |
324 | 391 |
325 ## identity | 392 ## identity |
326 name = kwargs.pop('name', None) | 393 name = kwargs.pop("name", None) |
327 password = extra[KEY_PASSWORD] | 394 password = extra[KEY_PASSWORD] |
328 if name is not None: | 395 if name is not None: |
329 extra['name'] = name | 396 extra["name"] = name |
330 try: | 397 try: |
331 id_plugin = self.host.plugins['IDENTITY'] | 398 id_plugin = self.host.plugins["IDENTITY"] |
332 except KeyError: | 399 except KeyError: |
333 pass | 400 pass |
334 else: | 401 else: |
335 await self.host.connect(guest_profile, password) | 402 await self.host.connect(guest_profile, password) |
336 guest_client = self.host.get_client(guest_profile) | 403 guest_client = self.host.get_client(guest_profile) |
337 await id_plugin.set_identity(guest_client, {'nicknames': [name]}) | 404 await id_plugin.set_identity(guest_client, {"nicknames": [name]}) |
338 await self.host.disconnect(guest_profile) | 405 await self.host.disconnect(guest_profile) |
339 | 406 |
340 ## email | 407 ## email |
341 language = kwargs.pop('language', None) | 408 language = kwargs.pop("language", None) |
342 if language is not None: | 409 if language is not None: |
343 extra['language'] = language.strip() | 410 extra["language"] = language.strip() |
344 | 411 |
345 if email is not None: | 412 if email is not None: |
346 extra['email'] = email | 413 extra["email"] = email |
347 data_format.iter2dict(KEY_EMAILS_EXTRA, extra) | 414 data_format.iter2dict(KEY_EMAILS_EXTRA, extra) |
348 url_template = kwargs.pop('url_template', '') | 415 url_template = kwargs.pop("url_template", "") |
349 format_args = { | 416 format_args = {"uuid": id_, "app_name": C.APP_NAME, "app_url": C.APP_URL} |
350 'uuid': id_, | |
351 'app_name': C.APP_NAME, | |
352 'app_url': C.APP_URL} | |
353 | 417 |
354 if name is None: | 418 if name is None: |
355 format_args['name'] = email | 419 format_args["name"] = email |
356 else: | 420 else: |
357 format_args['name'] = name | 421 format_args["name"] = name |
358 | 422 |
359 if profile is None: | 423 if profile is None: |
360 format_args['profile'] = '' | 424 format_args["profile"] = "" |
361 else: | 425 else: |
362 format_args['profile'] = extra['profile'] = profile | 426 format_args["profile"] = extra["profile"] = profile |
363 | 427 |
364 host_name = kwargs.pop('host_name', None) | 428 host_name = kwargs.pop("host_name", None) |
365 if host_name is None: | 429 if host_name is None: |
366 format_args['host_name'] = profile or _("somebody") | 430 format_args["host_name"] = profile or _("somebody") |
367 else: | 431 else: |
368 format_args['host_name'] = extra['host_name'] = host_name | 432 format_args["host_name"] = extra["host_name"] = host_name |
369 | 433 |
370 invite_url = url_template.format(**format_args) | 434 invite_url = url_template.format(**format_args) |
371 format_args['url'] = invite_url | 435 format_args["url"] = invite_url |
372 | 436 |
373 await sat_email.send_email( | 437 await sat_email.send_email( |
374 self.host.memory.config, | 438 self.host.memory.config, |
375 [email] + emails_extra, | 439 [email] + emails_extra, |
376 (kwargs.pop('message_subject', None) or DEFAULT_SUBJECT).format( | 440 (kwargs.pop("message_subject", None) or DEFAULT_SUBJECT).format( |
377 **format_args), | 441 **format_args |
378 (kwargs.pop('message_body', None) or DEFAULT_BODY).format(**format_args), | 442 ), |
443 (kwargs.pop("message_body", None) or DEFAULT_BODY).format(**format_args), | |
379 ) | 444 ) |
380 | 445 |
381 ## roster | 446 ## roster |
382 | 447 |
383 # we automatically add guest to host roster (if host is specified) | 448 # we automatically add guest to host roster (if host is specified) |
386 try: | 451 try: |
387 client = self.host.get_client(profile) | 452 client = self.host.get_client(profile) |
388 except Exception as e: | 453 except Exception as e: |
389 log.error(f"Can't get host profile: {profile}: {e}") | 454 log.error(f"Can't get host profile: {profile}: {e}") |
390 else: | 455 else: |
391 await self.host.contact_update(client, jid_, name, ['guests']) | 456 await self.host.contact_update(client, jid_, name, ["guests"]) |
392 | 457 |
393 if kwargs: | 458 if kwargs: |
394 log.warning(_("Not all arguments have been consumed: {}").format(kwargs)) | 459 log.warning(_("Not all arguments have been consumed: {}").format(kwargs)) |
395 | 460 |
396 ## extra data saving | 461 ## extra data saving |
408 url_template = str(url_template) | 473 url_template = str(url_template) |
409 extra = data_format.deserialise(extra_s) | 474 extra = data_format.deserialise(extra_s) |
410 d = defer.ensureDeferred( | 475 d = defer.ensureDeferred( |
411 self.simple_create(client, invitee_email, invitee_name, url_template, extra) | 476 self.simple_create(client, invitee_email, invitee_name, url_template, extra) |
412 ) | 477 ) |
413 d.addCallback(lambda data: {k: str(v) for k,v in data.items()}) | 478 d.addCallback(lambda data: {k: str(v) for k, v in data.items()}) |
414 return d | 479 return d |
415 | 480 |
416 async def simple_create( | 481 async def simple_create( |
417 self, client, invitee_email, invitee_name, url_template, extra): | 482 self, client, invitee_email, invitee_name, url_template, extra |
483 ): | |
418 """Simplified method to invite somebody by email""" | 484 """Simplified method to invite somebody by email""" |
419 return await self.create( | 485 return await self.create( |
420 name=invitee_name, | 486 name=invitee_name, |
421 email=invitee_email, | 487 email=invitee_email, |
422 url_template=url_template, | 488 url_template=url_template, |
437 | 503 |
438 async def delete(self, id_): | 504 async def delete(self, id_): |
439 """Delete an invitation data and associated XMPP account""" | 505 """Delete an invitation data and associated XMPP account""" |
440 log.info(f"deleting invitation {id_}") | 506 log.info(f"deleting invitation {id_}") |
441 data = await self.get(id_) | 507 data = await self.get(id_) |
442 guest_profile = data['guest_profile'] | 508 guest_profile = data["guest_profile"] |
443 password = data['password'] | 509 password = data["password"] |
444 try: | 510 try: |
445 await self.host.connect(guest_profile, password) | 511 await self.host.connect(guest_profile, password) |
446 guest_client = self.host.get_client(guest_profile) | 512 guest_client = self.host.get_client(guest_profile) |
447 # XXX: be extra careful to use guest_client and not client below, as this will | 513 # XXX: be extra careful to use guest_client and not client below, as this will |
448 # delete the associated XMPP account | 514 # delete the associated XMPP account |
449 log.debug("deleting XMPP account") | 515 log.debug("deleting XMPP account") |
450 await self.host.plugins['XEP-0077'].unregister(guest_client, None) | 516 await self.host.plugins["XEP-0077"].unregister(guest_client, None) |
451 except (error.StanzaError, sasl.SASLAuthError) as e: | 517 except (error.StanzaError, sasl.SASLAuthError) as e: |
452 log.warning( | 518 log.warning( |
453 f"Can't delete {guest_profile}'s XMPP account, maybe it as already been " | 519 f"Can't delete {guest_profile}'s XMPP account, maybe it as already been " |
454 f"deleted: {e}") | 520 f"deleted: {e}" |
521 ) | |
455 try: | 522 try: |
456 await self.host.memory.profile_delete_async(guest_profile, True) | 523 await self.host.memory.profile_delete_async(guest_profile, True) |
457 except Exception as e: | 524 except Exception as e: |
458 log.warning(f"Can't delete guest profile {guest_profile}: {e}") | 525 log.warning(f"Can't delete guest profile {guest_profile}: {e}") |
459 log.debug("removing guest data") | 526 log.debug("removing guest data") |
460 await self.invitations.adel(id_) | 527 await self.invitations.adel(id_) |
461 log.info(f"{id_} invitation has been deleted") | 528 log.info(f"{id_} invitation has been deleted") |
462 | 529 |
463 def _modify(self, id_, new_extra, replace): | 530 def _modify(self, id_, new_extra, replace): |
464 return self.modify(id_, {str(k): str(v) for k,v in new_extra.items()}, | 531 return self.modify(id_, {str(k): str(v) for k, v in new_extra.items()}, replace) |
465 replace) | |
466 | 532 |
467 def modify(self, id_, new_extra, replace=False): | 533 def modify(self, id_, new_extra, replace=False): |
468 """Modify invitation data | 534 """Modify invitation data |
469 | 535 |
470 @param id_(unicode): UUID linked to an invitation | 536 @param id_(unicode): UUID linked to an invitation |
473 @param replace(bool): if True replace the data | 539 @param replace(bool): if True replace the data |
474 else update them | 540 else update them |
475 @raise KeyError: there is not invitation with this id_ | 541 @raise KeyError: there is not invitation with this id_ |
476 """ | 542 """ |
477 self.check_extra(new_extra) | 543 self.check_extra(new_extra) |
544 | |
478 def got_current_data(current_data): | 545 def got_current_data(current_data): |
479 if replace: | 546 if replace: |
480 new_data = new_extra | 547 new_data = new_extra |
481 for k in EXTRA_RESERVED: | 548 for k in EXTRA_RESERVED: |
482 try: | 549 try: |
483 new_data[k] = current_data[k] | 550 new_data[k] = current_data[k] |
484 except KeyError: | 551 except KeyError: |
485 continue | 552 continue |
486 else: | 553 else: |
487 new_data = current_data | 554 new_data = current_data |
488 for k,v in new_extra.items(): | 555 for k, v in new_extra.items(): |
489 if k in EXTRA_RESERVED: | 556 if k in EXTRA_RESERVED: |
490 log.warning(_("Skipping reserved key {key}").format(key=k)) | 557 log.warning(_("Skipping reserved key {key}").format(key=k)) |
491 continue | 558 continue |
492 if v: | 559 if v: |
493 new_data[k] = v | 560 new_data[k] = v |
513 C.PROF_KEY_NONE: don't filter invitations | 580 C.PROF_KEY_NONE: don't filter invitations |
514 @return list(unicode): invitations uids | 581 @return list(unicode): invitations uids |
515 """ | 582 """ |
516 invitations = await self.invitations.all() | 583 invitations = await self.invitations.all() |
517 if profile != C.PROF_KEY_NONE: | 584 if profile != C.PROF_KEY_NONE: |
518 invitations = {id_:data for id_, data in invitations.items() | 585 invitations = { |
519 if data.get('profile') == profile} | 586 id_: data |
587 for id_, data in invitations.items() | |
588 if data.get("profile") == profile | |
589 } | |
520 | 590 |
521 return invitations | 591 return invitations |