Mercurial > libervia-web
comparison libervia/pages/_browser/invitation.py @ 1386:83be300d17e3
browser (invitations): handle Pubsub invitation
author | Goffi <goffi@goffi.org> |
---|---|
date | Sat, 20 Feb 2021 13:58:42 +0100 |
parents | e3e303a30a74 |
children | 5a132b85e1ac |
comparison
equal
deleted
inserted
replaced
1385:4b6f711b09cb | 1386:83be300d17e3 |
---|---|
1 from browser import document, window, timer | 1 from browser import document, window, timer |
2 from bridge import Bridge | 2 from bridge import Bridge |
3 from template import Template | 3 from template import Template |
4 from dialog import notification | 4 import dialog |
5 from cache import cache | 5 from cache import cache |
6 import javascript | |
7 | |
8 bridge = Bridge() | |
6 # we use JS RegExp because Python's re is really long to import in Brython | 9 # we use JS RegExp because Python's re is really long to import in Brython |
7 from javascript import RegExp | |
8 | |
9 bridge = Bridge() | |
10 # FIXME: this is a naive JID regex, a more accurate should be used instead | 10 # FIXME: this is a naive JID regex, a more accurate should be used instead |
11 jid_re = RegExp.new(r"^\w+@\w+\.\w+") | 11 jid_re = javascript.RegExp.new(r"^\w+@\w+\.\w+") |
12 | 12 |
13 | 13 |
14 class InvitationManager: | 14 class InvitationManager: |
15 | 15 |
16 def __init__(self, invitation_type, invitation_data): | 16 def __init__(self, invitation_type, invitation_data): |
68 """Hide the panel""" | 68 """Hide the panel""" |
69 document.body.style.height, document.body.style.overflow = self._body_ori_style | 69 document.body.style.height, document.body.style.overflow = self._body_ori_style |
70 self.side_panel.classList.remove('open') | 70 self.side_panel.classList.remove('open') |
71 self.side_panel.bind("transitionend", self._on_close_transition_end) | 71 self.side_panel.bind("transitionend", self._on_close_transition_end) |
72 | 72 |
73 def invite_by_jid(self, entity_jid): | 73 def _invite_jid(self, entity_jid, callback, errback=None): |
74 if errback is None: | |
75 errback = lambda e: dialog.notification.show(f"invitation failed: {e}", "error") | |
74 if self.invitation_type == 'photos': | 76 if self.invitation_type == 'photos': |
77 service = self.invitation_data["service"] | |
75 path = self.invitation_data["path"] | 78 path = self.invitation_data["path"] |
76 service = self.invitation_data["service"] | |
77 album_name = path.rsplit('/')[-1] | 79 album_name = path.rsplit('/')[-1] |
78 print(f"inviting {entity_jid}") | 80 print(f"inviting {entity_jid}") |
79 bridge.FISInvite( | 81 bridge.FISInvite( |
80 entity_jid, | 82 entity_jid, |
81 service, | 83 service, |
82 "photos", | 84 "photos", |
83 "", | 85 "", |
84 path, | 86 path, |
85 album_name, | 87 album_name, |
86 '', | 88 '', |
87 callback=lambda entity_jid=entity_jid: | 89 callback=callback, |
88 self._on_jid_invitation_success(entity_jid), | 90 errback=errback |
89 errback=lambda e: notification.show(f"invitation failed: {e}", "error") | 91 ) |
90 ) | 92 elif self.invitation_type == 'pubsub': |
93 service = self.invitation_data["service"] | |
94 node = self.invitation_data["node"] | |
95 name = self.invitation_data.get("name") | |
96 namespace = self.invitation_data.get("namespace") | |
97 extra = {} | |
98 if namespace: | |
99 extra["namespace"] = namespace | |
100 print(f"inviting {entity_jid}") | |
101 bridge.psInvite( | |
102 entity_jid, | |
103 service, | |
104 node, | |
105 '', | |
106 name, | |
107 javascript.JSON.stringify(extra), | |
108 callback=callback, | |
109 errback=errback | |
110 ) | |
111 else: | |
112 print(f"error: unknown invitation type: {self.invitation_type}") | |
113 | |
114 def invite_by_jid(self, entity_jid): | |
115 self._invite_jid( | |
116 entity_jid, | |
117 callback=lambda entity_jid=entity_jid: self._on_jid_invitation_success(entity_jid), | |
118 ) | |
91 | 119 |
92 def on_manager_close(self, evt): | 120 def on_manager_close(self, evt): |
93 self.close() | 121 self.close() |
94 | 122 |
95 def _on_jid_invitation_success(self, entity_jid): | 123 def _on_jid_invitation_success(self, entity_jid): |
96 form_elt = document['invitation_form'] | 124 form_elt = document['invitation_form'] |
97 contact_elt = form_elt.select_one('input[name="contact"]') | 125 contact_elt = form_elt.select_one('input[name="contact"]') |
98 contact_elt.value = "" | 126 contact_elt.value = "" |
99 contact_elt.dispatchEvent(window.Event.new('input')) | 127 contact_elt.dispatchEvent(window.Event.new('input')) |
100 notification.show( | 128 dialog.notification.show( |
101 f"{entity_jid} has been invited", | 129 f"{entity_jid} has been invited", |
102 level="success", | 130 level="success", |
103 ) | 131 ) |
104 if entity_jid not in self.affiliations: | 132 if entity_jid not in self.affiliations: |
105 self.set_affiliation(entity_jid, "member") | 133 self.set_affiliation(entity_jid, "member") |
206 # active item has been filtered out | 234 # active item has been filtered out |
207 self._active_new_item = None | 235 self._active_new_item = None |
208 | 236 |
209 def _on_email_invitation_success(self, invitee_jid, email, name): | 237 def _on_email_invitation_success(self, invitee_jid, email, name): |
210 self.set_affiliation(invitee_jid, "member") | 238 self.set_affiliation(invitee_jid, "member") |
211 notification.show( | 239 dialog.notification.show( |
212 f"{name} has been invited, he/she has received an email with a link", | 240 f"{name} has been invited, he/she has received an email with a link", |
213 level="success", | 241 level="success", |
214 ) | 242 ) |
215 | 243 |
216 def invitationSimpleCreateCb(self, invitation_data, email, name): | 244 def invitationSimpleCreateCb(self, invitation_data, email, name): |
217 if self.invitation_type == 'photos': | 245 invitee_jid = invitation_data['jid'] |
218 path = self.invitation_data["path"] | 246 self._invite_jid( |
219 service = self.invitation_data["service"] | 247 invitee_jid, |
220 invitee_jid = invitation_data['jid'] | 248 callback=lambda: self._on_email_invitation_success(invitee_jid, email, name), |
221 album_name = path.rsplit('/')[-1] | 249 errback=lambda e: dialog.notification.show( |
222 bridge.FISInvite( | 250 f"invitation failed for {email}: {e}", |
223 invitee_jid, | 251 "error" |
224 service, | 252 ) |
225 "photos", | 253 ) |
226 "", | 254 |
227 path, | 255 # we update identities to have the name instead of the invitation jid in |
228 album_name, | 256 # affiliations |
229 '', | 257 cache.identities[invitee_jid] = {'nicknames': [name]} |
230 callback=lambda: self._on_email_invitation_success(invitee_jid, email, name), | 258 cache.update() |
231 errback=lambda e: window.alert(f"invitation failed for {email}: {e}") | |
232 ) | |
233 | |
234 # we update identities to have the name instead of the invitation jid in | |
235 # affiliations | |
236 cache.identities[invitee_jid] = {'nicknames': [name]} | |
237 cache.update() | |
238 | 259 |
239 def invite_by_email(self, email, name): | 260 def invite_by_email(self, email, name): |
240 guest_url_tpl = f'{window.URL.new("/g", document.baseURI).href}/{{uuid}}' | 261 guest_url_tpl = f'{window.URL.new("/g", document.baseURI).href}/{{uuid}}' |
241 bridge.invitationSimpleCreate( | 262 bridge.invitationSimpleCreate( |
242 email, | 263 email, |
283 "click", lambda evt: self.on_invite_email_close(evt, invite_email_elt)) | 304 "click", lambda evt: self.on_invite_email_close(evt, invite_email_elt)) |
284 self.close() | 305 self.close() |
285 | 306 |
286 ## affiliations | 307 ## affiliations |
287 | 308 |
309 def _addAffiliationBindings(self, entity_jid, affiliation_elt): | |
310 for elt in affiliation_elt.select(".click_to_delete"): | |
311 elt.bind( | |
312 "click", | |
313 lambda evt, entity_jid=entity_jid, affiliation_elt=affiliation_elt: | |
314 self.on_affiliation_remove(entity_jid, affiliation_elt) | |
315 ) | |
316 for elt in affiliation_elt.select(".click_to_set_publisher"): | |
317 try: | |
318 name = cache.identities[entity_jid]["nicknames"][0] | |
319 except (KeyError, IndexError): | |
320 name = entity_jid | |
321 elt.bind( | |
322 "click", | |
323 lambda evt, entity_jid=entity_jid, name=name, affiliation_elt=affiliation_elt: | |
324 self.on_affiliation_set( | |
325 entity_jid, name, affiliation_elt, "publisher" | |
326 ), | |
327 ) | |
328 for elt in affiliation_elt.select(".click_to_set_member"): | |
329 try: | |
330 name = cache.identities[entity_jid]["nicknames"][0] | |
331 except (KeyError, IndexError): | |
332 name = entity_jid | |
333 elt.bind( | |
334 "click", | |
335 lambda evt, entity_jid=entity_jid, name=name, | |
336 affiliation_elt=affiliation_elt: | |
337 self.on_affiliation_set( | |
338 entity_jid, name, affiliation_elt, "member" | |
339 ), | |
340 ) | |
341 | |
288 def set_affiliation(self, entity_jid, affiliation): | 342 def set_affiliation(self, entity_jid, affiliation): |
289 if affiliation not in ('owner', 'member'): | 343 if affiliation not in ('owner', 'member', 'publisher'): |
290 raise NotImplementedError( | 344 raise NotImplementedError( |
291 f'{affiliation} affiliation can not be set with this method for the ' | 345 f'{affiliation} affiliation can not be set with this method for the ' |
292 'moment') | 346 'moment') |
293 if entity_jid not in self.affiliations: | 347 if entity_jid not in self.affiliations: |
294 self.affiliations[entity_jid] = affiliation | 348 self.affiliations[entity_jid] = affiliation |
296 "entity_jid": entity_jid, | 350 "entity_jid": entity_jid, |
297 "affiliation": affiliation, | 351 "affiliation": affiliation, |
298 "identities": cache.identities, | 352 "identities": cache.identities, |
299 }) | 353 }) |
300 document['affiliations'] <= affiliation_elt | 354 document['affiliations'] <= affiliation_elt |
301 for elt in affiliation_elt.select(".click_to_delete"): | 355 self._addAffiliationBindings(entity_jid, affiliation_elt) |
302 elt.bind( | |
303 "click", | |
304 lambda evt, entity_jid=entity_jid, affiliation_elt=affiliation_elt: | |
305 self.on_affiliation_remove(entity_jid, affiliation_elt) | |
306 ) | |
307 | 356 |
308 def _on_affiliation_remove_success(self, affiliation_elt, entity_jid): | 357 def _on_affiliation_remove_success(self, affiliation_elt, entity_jid): |
309 affiliation_elt.remove() | 358 affiliation_elt.remove() |
310 del self.affiliations[entity_jid] | 359 del self.affiliations[entity_jid] |
311 | 360 |
318 "", | 367 "", |
319 path, | 368 path, |
320 {entity_jid: "none"}, | 369 {entity_jid: "none"}, |
321 callback=lambda: self._on_affiliation_remove_success( | 370 callback=lambda: self._on_affiliation_remove_success( |
322 affiliation_elt, entity_jid), | 371 affiliation_elt, entity_jid), |
323 errback=lambda e: notification.show( | 372 errback=lambda e: dialog.notification.show( |
324 f"can't remove affiliation: {e}", "error") | 373 f"can't remove affiliation: {e}", "error") |
325 ) | 374 ) |
375 elif self.invitation_type == 'pubsub': | |
376 service = self.invitation_data["service"] | |
377 node = self.invitation_data["node"] | |
378 bridge.psNodeAffiliationsSet( | |
379 service, | |
380 node, | |
381 {entity_jid: "none"}, | |
382 callback=lambda: self._on_affiliation_remove_success( | |
383 affiliation_elt, entity_jid), | |
384 errback=lambda e: dialog.notification.show( | |
385 f"can't remove affiliation: {e}", "error") | |
386 ) | |
387 else: | |
388 dialog.notification.show( | |
389 f"error: unknown invitation type: {self.invitation_type}", | |
390 "error" | |
391 ) | |
392 | |
393 def _on_affiliation_set_success(self, entity_jid, name, affiliation_elt, affiliation): | |
394 dialog.notification.show(f"permission updated for {name}") | |
395 self.affiliations[entity_jid] = affiliation | |
396 new_affiliation_elt = self.affiliation_tpl.get_elt({ | |
397 "entity_jid": entity_jid, | |
398 "affiliation": affiliation, | |
399 "identities": cache.identities, | |
400 }) | |
401 affiliation_elt.replaceWith(new_affiliation_elt) | |
402 self._addAffiliationBindings(entity_jid, new_affiliation_elt) | |
403 | |
404 def _on_affiliation_set_ok(self, entity_jid, name, affiliation_elt, affiliation): | |
405 if self.invitation_type == 'pubsub': | |
406 service = self.invitation_data["service"] | |
407 node = self.invitation_data["node"] | |
408 bridge.psNodeAffiliationsSet( | |
409 service, | |
410 node, | |
411 {entity_jid: affiliation}, | |
412 callback=lambda: self._on_affiliation_set_success( | |
413 entity_jid, name, affiliation_elt, affiliation | |
414 ), | |
415 errback=lambda e: dialog.notification.show( | |
416 f"can't set affiliation: {e}", "error") | |
417 ) | |
418 else: | |
419 dialog.notification.show( | |
420 f"error: unknown invitation type: {self.invitation_type}", | |
421 "error" | |
422 ) | |
423 | |
424 def _on_affiliation_set_cancel(self, evt, notif_elt): | |
425 notif_elt.remove() | |
426 self.open() | |
427 | |
428 def on_affiliation_set(self, entity_jid, name, affiliation_elt, affiliation): | |
429 if affiliation == "publisher": | |
430 message = f"Give autorisation to publish to {name}?" | |
431 elif affiliation == "member": | |
432 message = f"Remove autorisation to publish from {name}?" | |
433 else: | |
434 dialog.notification.show(f"unmanaged affiliation: {affiliation}", "error") | |
435 return | |
436 dialog.Confirm(message).show( | |
437 ok_cb=lambda evt, notif_elt: | |
438 self._on_affiliation_set_ok( | |
439 entity_jid, name, affiliation_elt, affiliation | |
440 ), | |
441 cancel_cb=self._on_affiliation_set_cancel | |
442 ) | |
443 self.close() |