diff sat_pubsub/backend.py @ 331:e93a9fd329d9

affiliations XMPP handling: /!\ PostGreSQL minimal version raised to 9.5 (for upsert support) - affiliations can now be handler after node creation using XMPP: affiliationsGet, affiliationsSet (both for node owner) and affiliations (for an entity to know with which nodes it is affiliated on the service) are implemented - pgsql: getOrCreateEntities helping method has been implemented, it get entity_id and create missing entities when needed.
author Goffi <goffi@goffi.org>
date Sun, 26 Mar 2017 20:58:48 +0200
parents 82d1259b3e36
children 0fcd0ea89c84
line wrap: on
line diff
--- a/sat_pubsub/backend.py	Sun Mar 26 20:52:32 2017 +0200
+++ b/sat_pubsub/backend.py	Sun Mar 26 20:58:48 2017 +0200
@@ -555,8 +555,61 @@
         return node.setConfiguration(options)
 
 
-    def getAffiliations(self, entity):
-        return self.storage.getAffiliations(entity)
+    def getAffiliations(self, entity, nodeIdentifier, pep, recipient):
+        return self.storage.getAffiliations(entity, nodeIdentifier, pep, recipient)
+
+
+    def getAffiliationsOwner(self, nodeIdentifier, requestor, pep, recipient):
+        d = self.storage.getNode(nodeIdentifier, pep, recipient)
+        d.addCallback(_getAffiliation, requestor)
+        d.addCallback(self._doGetAffiliationsOwner)
+        return d
+
+
+    def _doGetAffiliationsOwner(self, result):
+        node, affiliation = result
+
+        if affiliation != 'owner':
+            raise error.Forbidden()
+        return node.getAffiliations()
+
+
+    def setAffiliationsOwner(self, nodeIdentifier, requestor, affiliations, pep, recipient):
+        d = self.storage.getNode(nodeIdentifier, pep, recipient)
+        d.addCallback(_getAffiliation, requestor)
+        d.addCallback(self._doSetAffiliationsOwner, requestor, affiliations)
+        return d
+
+
+    def _doSetAffiliationsOwner(self, result, requestor, affiliations):
+        # Check that requestor is allowed to set affiliations, and delete entities
+        # with "none" affiliation
+
+        # TODO: return error with failed affiliations in case of failure
+        node, requestor_affiliation = result
+
+        if requestor_affiliation != 'owner':
+            raise error.Forbidden()
+
+        # we don't allow requestor to change its own affiliation
+        requestor_bare = requestor.userhostJID()
+        if requestor_bare in affiliations and affiliations[requestor_bare] != 'owner':
+            # FIXME: it may be interesting to allow the owner to ask for ownership removal
+            #        if at least one other entity is owner for this node
+            raise error.Forbidden("You can't change your own affiliation")
+
+        to_delete = [jid_ for jid_, affiliation in affiliations.iteritems() if affiliation == 'none']
+        for jid_ in to_delete:
+            del affiliations[jid_]
+
+        if to_delete:
+            d = node.deleteAffiliations(to_delete)
+            if affiliations:
+                d.addCallback(lambda dummy: node.setAffiliations(affiliations))
+        else:
+            d = node.setAffiliations(affiliations)
+
+        return d
 
 
     def getItems(self, nodeIdentifier, requestor, recipient, maxItems=None,
@@ -1240,8 +1293,14 @@
 
 
     def affiliations(self, request):
-        d = self.backend.getAffiliations(self._isPep(request),
-                                         request.sender)
+        """Retrieve affiliation for normal entity (cf. XEP-0060 §5.7)
+
+        retrieve all node where this jid is affiliated
+        """
+        d = self.backend.getAffiliations(request.sender,
+                                         request.nodeIdentifier,
+                                         self._isPep(request),
+                                         request.recipient)
         return d.addErrback(self._mapErrors)
 
 
@@ -1276,6 +1335,26 @@
         return d.addErrback(self._mapErrors)
 
 
+    def affiliationsGet(self, request):
+        """Retrieve affiliations for owner (cf. XEP-0060 §8.9.1)
+
+        retrieve all affiliations for a node
+        """
+        d = self.backend.getAffiliationsOwner(request.nodeIdentifier,
+                                              request.sender,
+                                              self._isPep(request),
+                                              request.recipient)
+        return d.addErrback(self._mapErrors)
+
+    def affiliationsSet(self, request):
+        d = self.backend.setAffiliationsOwner(request.nodeIdentifier,
+                                              request.sender,
+                                              request.affiliations,
+                                              self._isPep(request),
+                                              request.recipient)
+        return d.addErrback(self._mapErrors)
+
+
     def items(self, request):
         ext_data = {}
         if const.FLAG_ENABLE_RSM and request.rsm is not None: