comparison 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
comparison
equal deleted inserted replaced
277:e749401be529 278:8a71486c3e95
71 from twisted.internet import defer, reactor 71 from twisted.internet import defer, reactor
72 from twisted.words.protocols.jabber.error import StanzaError 72 from twisted.words.protocols.jabber.error import StanzaError
73 from twisted.words.protocols.jabber.jid import JID, InvalidFormat 73 from twisted.words.protocols.jabber.jid import JID, InvalidFormat
74 from twisted.words.xish import utility 74 from twisted.words.xish import utility
75 75
76 from wokkel import disco, data_form 76 from wokkel import disco, data_form, rsm
77 from wokkel.iwokkel import IPubSubResource 77 from wokkel.iwokkel import IPubSubResource
78 from wokkel.pubsub import PubSubResource, PubSubError, Subscription 78 from wokkel.pubsub import PubSubResource, PubSubError, Subscription
79 79
80 from sat_pubsub import error, iidavoll, const 80 from sat_pubsub import error, iidavoll, const
81 from sat_pubsub.iidavoll import IBackendService, ILeafNode 81 from sat_pubsub.iidavoll import IBackendService, ILeafNode
498 def getAffiliations(self, entity): 498 def getAffiliations(self, entity):
499 return self.storage.getAffiliations(entity) 499 return self.storage.getAffiliations(entity)
500 500
501 501
502 def getItems(self, nodeIdentifier, requestor, maxItems=None, 502 def getItems(self, nodeIdentifier, requestor, maxItems=None,
503 itemIdentifiers=None): 503 itemIdentifiers=None, ext_data=None):
504 if ext_data is None:
505 ext_data = {}
504 d = self.storage.getNode(nodeIdentifier) 506 d = self.storage.getNode(nodeIdentifier)
505 d.addCallback(_getAffiliation, requestor) 507 d.addCallback(_getAffiliation, requestor)
506 d.addCallback(self._doGetItems, requestor, maxItems, itemIdentifiers) 508 d.addCallback(self._doGetItems, requestor, maxItems, itemIdentifiers,
509 ext_data)
507 return d 510 return d
508 511
509 def checkGroup(self, roster_groups, entity): 512 def checkGroup(self, roster_groups, entity):
510 """Check that entity is authorized and in roster 513 """Check that entity is authorized and in roster
511 @param roster_group: tuple which 2 items: 514 @param roster_group: tuple which 2 items:
525 def _getNodeGroups(self, roster, nodeIdentifier): 528 def _getNodeGroups(self, roster, nodeIdentifier):
526 d = self.storage.getNodeGroups(nodeIdentifier) 529 d = self.storage.getNodeGroups(nodeIdentifier)
527 d.addCallback(lambda groups: (roster, groups)) 530 d.addCallback(lambda groups: (roster, groups))
528 return d 531 return d
529 532
530 def _doGetItems(self, result, requestor, maxItems, itemIdentifiers): 533 def _doGetItems(self, result, requestor, maxItems, itemIdentifiers,
534 ext_data):
531 node, affiliation = result 535 node, affiliation = result
532 536
533 def append_item_config(items_data): 537 def append_item_config(items_data):
534 ret = [] 538 ret = []
535 for data in items_data: 539 for data in items_data:
557 if not authorized: 561 if not authorized:
558 raise error.NotAuthorized() 562 raise error.NotAuthorized()
559 563
560 roster_item = roster.get(requestor.userhostJID()) 564 roster_item = roster.get(requestor.userhostJID())
561 authorized_groups = tuple(roster_item.groups) if roster_item else tuple() 565 authorized_groups = tuple(roster_item.groups) if roster_item else tuple()
566 unrestricted = affiliation == 'owner'
562 567
563 if itemIdentifiers: 568 if itemIdentifiers:
564 return node.getItemsById(authorized_groups, affiliation == 'owner', itemIdentifiers) 569 d = node.getItemsById(authorized_groups, unrestricted, itemIdentifiers)
565 else: 570 else:
566 if affiliation == 'owner': 571 d = node.getItems(authorized_groups, unrestricted, maxItems,
567 d = node.getItems(authorized_groups, True, maxItems) 572 ext_data)
568 return d.addCallback(append_item_config) 573 if unrestricted:
569 else: 574 d.addCallback(append_item_config)
570 return node.getItems(authorized_groups, False, maxItems) 575
571 576 for extension in ext_data:
577 if ext_data[extension] is not None:
578 if hasattr(self, '_items_%s' % extension):
579 method = getattr(self, '_items_%s' % extension)
580 d.addCallback(method, node, authorized_groups,
581 unrestricted, maxItems, itemIdentifiers,
582 ext_data[extension])
583 return d
572 584
573 if not ILeafNode.providedBy(node): 585 if not ILeafNode.providedBy(node):
574 return [] 586 return []
575 587
576 if affiliation == 'outcast': 588 if affiliation == 'outcast':
577 raise error.Forbidden() 589 raise error.Forbidden()
578 590
579 access_model = node.getConfiguration()["pubsub#access_model"] 591 access_model = node.getConfiguration()["pubsub#access_model"]
580 d = node.getNodeOwner() 592 d = node.getNodeOwner()
581 d.addCallback(self.roster.getRoster) 593 d.addCallback(self.roster.getRoster)
582 594
583 if access_model == 'open' or affiliation == 'owner': 595 if access_model == 'open' or affiliation == 'owner':
584 d.addCallback(lambda roster: (True, roster)) 596 d.addCallback(lambda roster: (True, roster))
585 d.addCallback(access_checked) 597 d.addCallback(access_checked)
586 elif access_model == 'roster': 598 elif access_model == 'roster':
587 d.addCallback(self._getNodeGroups,node.nodeIdentifier) 599 d.addCallback(self._getNodeGroups,node.nodeIdentifier)
588 d.addCallback(self.checkGroup, requestor) 600 d.addCallback(self.checkGroup, requestor)
589 d.addCallback(access_checked) 601 d.addCallback(access_checked)
590 602
591 return d 603 return d
604
605 def _items_rsm(self, elts, node, authorized_groups, unrestricted, maxItems,
606 itemIdentifiers, request):
607 response = rsm.RSMResponse()
608
609 d_count = node.countItems(authorized_groups, unrestricted)
610 d_count.addCallback(lambda count: setattr(response, 'count', count))
611 d_list = [d_count]
612
613 if request.index is not None:
614 response.index = request.index
615 elif request.before is not None:
616 if request.before != '':
617 # XXX: getIndex starts with index 1, RSM starts with 0
618 d_index = node.getIndex(authorized_groups, unrestricted, request.before)
619 d_index.addCallback(lambda index: setattr(response, 'index', max(index - request.max - 1, 0)))
620 d_list.append(d_index)
621 elif request.after is not None:
622 d_index = node.getIndex(authorized_groups, unrestricted, request.after)
623 d_index.addCallback(lambda index: setattr(response, 'index', index))
624 d_list.append(d_index)
625 elif itemIdentifiers:
626 d_index = node.getIndex(authorized_groups, unrestricted, itemIdentifiers[0])
627 d_index.addCallback(lambda index: setattr(response, 'index', index - 1))
628 d_list.append(d_index)
629
630
631 def render(result):
632 items = [elt for elt in elts if elt.name == 'item']
633 if len(items) > 0:
634 if response.index is None:
635 if request.before == '': # last page
636 response.index = response.count - request.max
637 else: # first page
638 response.index = 0
639 response.first = items[0]['id']
640 response.last = items[len(items) - 1]['id']
641 if request.before is not None:
642 response.first, response.last = response.last, response.first
643 else:
644 response.index = None
645 elts.append(response.render())
646 return elts
647
648 return defer.DeferredList(d_list).addCallback(render)
592 649
593 def retractItem(self, nodeIdentifier, itemIdentifiers, requestor): 650 def retractItem(self, nodeIdentifier, itemIdentifiers, requestor):
594 d = self.storage.getNode(nodeIdentifier) 651 d = self.storage.getNode(nodeIdentifier)
595 d.addCallback(_getAffiliation, requestor) 652 d.addCallback(_getAffiliation, requestor)
596 if const.FLAG_RETRACT_ALLOW_PUBLISHER: 653 if const.FLAG_RETRACT_ALLOW_PUBLISHER:
1015 request.sender) 1072 request.sender)
1016 return d.addErrback(self._mapErrors) 1073 return d.addErrback(self._mapErrors)
1017 1074
1018 1075
1019 def items(self, request): 1076 def items(self, request):
1077 ext_data = {}
1078 if const.FLAG_ENABLE_RSM:
1079 rsm_ = rsm.RSMRequest.parse(request.element.pubsub)
1080 if not rsm_:
1081 rsm_ = rsm.RSMRequest(const.VAL_RSM_MAX_DEFAULT)
1082 ext_data['rsm'] = rsm_
1020 d = self.backend.getItems(request.nodeIdentifier, 1083 d = self.backend.getItems(request.nodeIdentifier,
1021 request.sender, 1084 request.sender,
1022 request.maxItems, 1085 request.maxItems,
1023 request.itemIdentifiers) 1086 request.itemIdentifiers,
1024 return d.addErrback(self._mapErrors) 1087 ext_data)
1025 1088 return d.addErrback(self._mapErrors)
1026 1089
1027 def retract(self, request): 1090 def retract(self, request):
1028 d = self.backend.retractItem(request.nodeIdentifier, 1091 d = self.backend.retractItem(request.nodeIdentifier,
1029 request.itemIdentifiers, 1092 request.itemIdentifiers,
1030 request.sender) 1093 request.sender)