changeset 1386:83be300d17e3

browser (invitations): handle Pubsub invitation
author Goffi <goffi@goffi.org>
date Sat, 20 Feb 2021 13:58:42 +0100
parents 4b6f711b09cb
children a84383c659b4
files libervia/pages/_browser/invitation.py
diffstat 1 files changed, 156 insertions(+), 38 deletions(-) [+]
line wrap: on
line diff
--- 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()