Mercurial > libervia-pubsub
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) |