# HG changeset patch # User Goffi # Date 1613825922 -3600 # Node ID 83be300d17e30b213a81bb5de970fb953f39cf91 # Parent 4b6f711b09cbc3405c650fa1110f30248b1092e0 browser (invitations): handle Pubsub invitation diff -r 4b6f711b09cb -r 83be300d17e3 libervia/pages/_browser/invitation.py --- a/libervia/pages/_browser/invitation.py Sat Feb 20 13:58:01 2021 +0100 +++ b/libervia/pages/_browser/invitation.py Sat Feb 20 13:58:42 2021 +0100 @@ -1,14 +1,14 @@ from browser import document, window, timer from bridge import Bridge from template import Template -from dialog import notification +import dialog from cache import cache -# we use JS RegExp because Python's re is really long to import in Brython -from javascript import RegExp +import javascript bridge = Bridge() +# we use JS RegExp because Python's re is really long to import in Brython # FIXME: this is a naive JID regex, a more accurate should be used instead -jid_re = RegExp.new(r"^\w+@\w+\.\w+") +jid_re = javascript.RegExp.new(r"^\w+@\w+\.\w+") class InvitationManager: @@ -70,10 +70,12 @@ self.side_panel.classList.remove('open') self.side_panel.bind("transitionend", self._on_close_transition_end) - def invite_by_jid(self, entity_jid): + def _invite_jid(self, entity_jid, callback, errback=None): + if errback is None: + errback = lambda e: dialog.notification.show(f"invitation failed: {e}", "error") if self.invitation_type == 'photos': + service = self.invitation_data["service"] path = self.invitation_data["path"] - service = self.invitation_data["service"] album_name = path.rsplit('/')[-1] print(f"inviting {entity_jid}") bridge.FISInvite( @@ -84,10 +86,36 @@ path, album_name, '', - callback=lambda entity_jid=entity_jid: - self._on_jid_invitation_success(entity_jid), - errback=lambda e: notification.show(f"invitation failed: {e}", "error") + callback=callback, + errback=errback ) + elif self.invitation_type == 'pubsub': + service = self.invitation_data["service"] + node = self.invitation_data["node"] + name = self.invitation_data.get("name") + namespace = self.invitation_data.get("namespace") + extra = {} + if namespace: + extra["namespace"] = namespace + print(f"inviting {entity_jid}") + bridge.psInvite( + entity_jid, + service, + node, + '', + name, + javascript.JSON.stringify(extra), + callback=callback, + errback=errback + ) + else: + print(f"error: unknown invitation type: {self.invitation_type}") + + def invite_by_jid(self, entity_jid): + self._invite_jid( + entity_jid, + callback=lambda entity_jid=entity_jid: self._on_jid_invitation_success(entity_jid), + ) def on_manager_close(self, evt): self.close() @@ -97,7 +125,7 @@ contact_elt = form_elt.select_one('input[name="contact"]') contact_elt.value = "" contact_elt.dispatchEvent(window.Event.new('input')) - notification.show( + dialog.notification.show( f"{entity_jid} has been invited", level="success", ) @@ -208,33 +236,26 @@ def _on_email_invitation_success(self, invitee_jid, email, name): self.set_affiliation(invitee_jid, "member") - notification.show( + dialog.notification.show( f"{name} has been invited, he/she has received an email with a link", level="success", ) def invitationSimpleCreateCb(self, invitation_data, email, name): - if self.invitation_type == 'photos': - path = self.invitation_data["path"] - service = self.invitation_data["service"] - invitee_jid = invitation_data['jid'] - album_name = path.rsplit('/')[-1] - bridge.FISInvite( - invitee_jid, - service, - "photos", - "", - path, - album_name, - '', - callback=lambda: self._on_email_invitation_success(invitee_jid, email, name), - errback=lambda e: window.alert(f"invitation failed for {email}: {e}") + invitee_jid = invitation_data['jid'] + self._invite_jid( + invitee_jid, + callback=lambda: self._on_email_invitation_success(invitee_jid, email, name), + errback=lambda e: dialog.notification.show( + f"invitation failed for {email}: {e}", + "error" ) + ) - # we update identities to have the name instead of the invitation jid in - # affiliations - cache.identities[invitee_jid] = {'nicknames': [name]} - cache.update() + # we update identities to have the name instead of the invitation jid in + # affiliations + cache.identities[invitee_jid] = {'nicknames': [name]} + cache.update() def invite_by_email(self, email, name): guest_url_tpl = f'{window.URL.new("/g", document.baseURI).href}/{{uuid}}' @@ -285,8 +306,41 @@ ## affiliations + def _addAffiliationBindings(self, entity_jid, affiliation_elt): + for elt in affiliation_elt.select(".click_to_delete"): + elt.bind( + "click", + lambda evt, entity_jid=entity_jid, affiliation_elt=affiliation_elt: + self.on_affiliation_remove(entity_jid, affiliation_elt) + ) + for elt in affiliation_elt.select(".click_to_set_publisher"): + try: + name = cache.identities[entity_jid]["nicknames"][0] + except (KeyError, IndexError): + name = entity_jid + elt.bind( + "click", + lambda evt, entity_jid=entity_jid, name=name, affiliation_elt=affiliation_elt: + self.on_affiliation_set( + entity_jid, name, affiliation_elt, "publisher" + ), + ) + for elt in affiliation_elt.select(".click_to_set_member"): + try: + name = cache.identities[entity_jid]["nicknames"][0] + except (KeyError, IndexError): + name = entity_jid + elt.bind( + "click", + lambda evt, entity_jid=entity_jid, name=name, + affiliation_elt=affiliation_elt: + self.on_affiliation_set( + entity_jid, name, affiliation_elt, "member" + ), + ) + def set_affiliation(self, entity_jid, affiliation): - if affiliation not in ('owner', 'member'): + if affiliation not in ('owner', 'member', 'publisher'): raise NotImplementedError( f'{affiliation} affiliation can not be set with this method for the ' 'moment') @@ -298,12 +352,7 @@ "identities": cache.identities, }) document['affiliations'] <= affiliation_elt - for elt in affiliation_elt.select(".click_to_delete"): - elt.bind( - "click", - lambda evt, entity_jid=entity_jid, affiliation_elt=affiliation_elt: - self.on_affiliation_remove(entity_jid, affiliation_elt) - ) + self._addAffiliationBindings(entity_jid, affiliation_elt) def _on_affiliation_remove_success(self, affiliation_elt, entity_jid): affiliation_elt.remove() @@ -320,6 +369,75 @@ {entity_jid: "none"}, callback=lambda: self._on_affiliation_remove_success( affiliation_elt, entity_jid), - errback=lambda e: notification.show( + errback=lambda e: dialog.notification.show( + f"can't remove affiliation: {e}", "error") + ) + elif self.invitation_type == 'pubsub': + service = self.invitation_data["service"] + node = self.invitation_data["node"] + bridge.psNodeAffiliationsSet( + service, + node, + {entity_jid: "none"}, + callback=lambda: self._on_affiliation_remove_success( + affiliation_elt, entity_jid), + errback=lambda e: dialog.notification.show( f"can't remove affiliation: {e}", "error") ) + else: + dialog.notification.show( + f"error: unknown invitation type: {self.invitation_type}", + "error" + ) + + def _on_affiliation_set_success(self, entity_jid, name, affiliation_elt, affiliation): + dialog.notification.show(f"permission updated for {name}") + self.affiliations[entity_jid] = affiliation + new_affiliation_elt = self.affiliation_tpl.get_elt({ + "entity_jid": entity_jid, + "affiliation": affiliation, + "identities": cache.identities, + }) + affiliation_elt.replaceWith(new_affiliation_elt) + self._addAffiliationBindings(entity_jid, new_affiliation_elt) + + def _on_affiliation_set_ok(self, entity_jid, name, affiliation_elt, affiliation): + if self.invitation_type == 'pubsub': + service = self.invitation_data["service"] + node = self.invitation_data["node"] + bridge.psNodeAffiliationsSet( + service, + node, + {entity_jid: affiliation}, + callback=lambda: self._on_affiliation_set_success( + entity_jid, name, affiliation_elt, affiliation + ), + errback=lambda e: dialog.notification.show( + f"can't set affiliation: {e}", "error") + ) + else: + dialog.notification.show( + f"error: unknown invitation type: {self.invitation_type}", + "error" + ) + + def _on_affiliation_set_cancel(self, evt, notif_elt): + notif_elt.remove() + self.open() + + def on_affiliation_set(self, entity_jid, name, affiliation_elt, affiliation): + if affiliation == "publisher": + message = f"Give autorisation to publish to {name}?" + elif affiliation == "member": + message = f"Remove autorisation to publish from {name}?" + else: + dialog.notification.show(f"unmanaged affiliation: {affiliation}", "error") + return + dialog.Confirm(message).show( + ok_cb=lambda evt, notif_elt: + self._on_affiliation_set_ok( + entity_jid, name, affiliation_elt, affiliation + ), + cancel_cb=self._on_affiliation_set_cancel + ) + self.close()