diff sat_pubsub/backend.py @ 278:8a71486c3e95

implements RSM (XEP-0059)
author souliane <souliane@mailoo.org>
date Mon, 13 Oct 2014 14:53:42 +0200
parents 9dfd3890e646
children 7c820a8e4b00
line wrap: on
line diff
--- a/sat_pubsub/backend.py	Mon Dec 15 13:14:53 2014 +0100
+++ b/sat_pubsub/backend.py	Mon Oct 13 14:53:42 2014 +0200
@@ -73,7 +73,7 @@
 from twisted.words.protocols.jabber.jid import JID, InvalidFormat
 from twisted.words.xish import utility
 
-from wokkel import disco, data_form
+from wokkel import disco, data_form, rsm
 from wokkel.iwokkel import IPubSubResource
 from wokkel.pubsub import PubSubResource, PubSubError, Subscription
 
@@ -500,10 +500,13 @@
 
 
     def getItems(self, nodeIdentifier, requestor, maxItems=None,
-                       itemIdentifiers=None):
+                       itemIdentifiers=None, ext_data=None):
+        if ext_data is None:
+            ext_data = {}
         d = self.storage.getNode(nodeIdentifier)
         d.addCallback(_getAffiliation, requestor)
-        d.addCallback(self._doGetItems, requestor, maxItems, itemIdentifiers)
+        d.addCallback(self._doGetItems, requestor, maxItems, itemIdentifiers,
+                      ext_data)
         return d
 
     def checkGroup(self, roster_groups, entity):
@@ -527,7 +530,8 @@
         d.addCallback(lambda groups: (roster, groups))
         return d
 
-    def _doGetItems(self, result, requestor, maxItems, itemIdentifiers):
+    def _doGetItems(self, result, requestor, maxItems, itemIdentifiers,
+                    ext_data):
         node, affiliation = result
 
         def append_item_config(items_data):
@@ -559,16 +563,24 @@
 
             roster_item = roster.get(requestor.userhostJID())
             authorized_groups = tuple(roster_item.groups) if roster_item else tuple()
+            unrestricted = affiliation == 'owner'
 
             if itemIdentifiers:
-                return node.getItemsById(authorized_groups, affiliation == 'owner', itemIdentifiers)
+                d = node.getItemsById(authorized_groups, unrestricted, itemIdentifiers)
             else:
-                if affiliation == 'owner':
-                    d = node.getItems(authorized_groups, True, maxItems)
-                    return d.addCallback(append_item_config)
-                else:
-                    return node.getItems(authorized_groups, False, maxItems)
+                d = node.getItems(authorized_groups, unrestricted, maxItems,
+                                  ext_data)
+                if unrestricted:
+                    d.addCallback(append_item_config)
 
+            for extension in ext_data:
+                if ext_data[extension] is not None:
+                    if hasattr(self, '_items_%s' % extension):
+                        method = getattr(self, '_items_%s' % extension)
+                        d.addCallback(method, node, authorized_groups,
+                                      unrestricted, maxItems, itemIdentifiers,
+                                      ext_data[extension])
+            return d
 
         if not ILeafNode.providedBy(node):
             return []
@@ -579,7 +591,7 @@
         access_model = node.getConfiguration()["pubsub#access_model"]
         d = node.getNodeOwner()
         d.addCallback(self.roster.getRoster)
-        
+
         if access_model == 'open' or affiliation == 'owner':
             d.addCallback(lambda roster: (True, roster))
             d.addCallback(access_checked)
@@ -590,6 +602,51 @@
 
         return d
 
+    def _items_rsm(self, elts, node, authorized_groups, unrestricted, maxItems,
+                   itemIdentifiers, request):
+        response = rsm.RSMResponse()
+
+        d_count = node.countItems(authorized_groups, unrestricted)
+        d_count.addCallback(lambda count: setattr(response, 'count', count))
+        d_list = [d_count]
+
+        if request.index is not None:
+            response.index = request.index
+        elif request.before is not None:
+            if request.before != '':
+                # XXX: getIndex starts with index 1, RSM starts with 0
+                d_index = node.getIndex(authorized_groups, unrestricted, request.before)
+                d_index.addCallback(lambda index: setattr(response, 'index', max(index - request.max - 1, 0)))
+                d_list.append(d_index)
+        elif request.after is not None:
+            d_index = node.getIndex(authorized_groups, unrestricted, request.after)
+            d_index.addCallback(lambda index: setattr(response, 'index', index))
+            d_list.append(d_index)
+        elif itemIdentifiers:
+            d_index = node.getIndex(authorized_groups, unrestricted, itemIdentifiers[0])
+            d_index.addCallback(lambda index: setattr(response, 'index', index - 1))
+            d_list.append(d_index)
+
+
+        def render(result):
+            items = [elt for elt in elts if elt.name == 'item']
+            if len(items) > 0:
+                if response.index is None:
+                    if request.before == '': # last page
+                        response.index = response.count - request.max
+                    else:  # first page
+                        response.index = 0
+                response.first = items[0]['id']
+                response.last = items[len(items) - 1]['id']
+                if request.before is not None:
+                    response.first, response.last = response.last, response.first
+            else:
+                response.index = None
+            elts.append(response.render())
+            return elts
+
+        return defer.DeferredList(d_list).addCallback(render)
+
     def retractItem(self, nodeIdentifier, itemIdentifiers, requestor):
         d = self.storage.getNode(nodeIdentifier)
         d.addCallback(_getAffiliation, requestor)
@@ -1017,13 +1074,19 @@
 
 
     def items(self, request):
+        ext_data = {}
+        if const.FLAG_ENABLE_RSM:
+            rsm_ = rsm.RSMRequest.parse(request.element.pubsub)
+            if not rsm_:
+                rsm_ = rsm.RSMRequest(const.VAL_RSM_MAX_DEFAULT)
+            ext_data['rsm'] = rsm_
         d = self.backend.getItems(request.nodeIdentifier,
                                   request.sender,
                                   request.maxItems,
-                                  request.itemIdentifiers)
+                                  request.itemIdentifiers,
+                                  ext_data)
         return d.addErrback(self._mapErrors)
 
-
     def retract(self, request):
         d = self.backend.retractItem(request.nodeIdentifier,
                                      request.itemIdentifiers,