Changeset 226:2532cfb12c7c
- Timestamp:
- Oct 4, 2016, 9:53:27 AM (6 years ago)
- Branch:
- default
- Parents:
- 225:58dd11c3ddd5 (diff), 224:16fca7e4806f (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent. - hg-git-rename-source:
- git
- Location:
- wokkel
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
wokkel/pubsub.py
r223 r226 43 43 'pubsub[@xmlns="' + NS_PUBSUB + '" or ' + \ 44 44 '@xmlns="' + NS_PUBSUB_OWNER + '"]' 45 46 BOOL_TRUE = ('1','true') 47 BOOL_FALSE = ('0','false') 45 48 46 49 class SubscriptionPending(Exception): … … 253 256 subscriptions = None 254 257 affiliations = None 258 notify = None 255 259 256 260 # Map request iq type and subelement name to request verb … … 294 298 'configureSet': ['nodeOrEmpty', 'configure'], 295 299 'items': ['node', 'maxItems', 'itemIdentifiers', 'subidOrNone'], 296 'retract': ['node', ' itemIdentifiers'],300 'retract': ['node', 'notify', 'itemIdentifiers'], 297 301 'purge': ['node'], 298 302 'delete': ['node'], … … 567 571 568 572 573 def _parse_notify(self, verbElement): 574 value = verbElement.getAttribute('notify') 575 576 if value: 577 if value in BOOL_TRUE: 578 self.notify = True 579 elif value in BOOL_FALSE: 580 self.notify = False 581 else: 582 raise BadRequest(text="Field notify must be a boolean value") 583 584 585 def _render_notify(self, verbElement): 586 if self.notify is not None: 587 verbElement['notify'] = "true" if self.notify else "false" 588 589 569 590 def parseElement(self, element): 570 591 """ … … 956 977 return d 957 978 979 def retractItems(self, service, nodeIdentifier, itemIdentifiers, notify=None, sender=None): 980 """ 981 Retract items from a publish subscribe node. 982 983 @param service: The publish subscribe service to delete the node from. 984 @type service: L{JID<twisted.words.protocols.jabber.jid.JID>} 985 @param nodeIdentifier: The identifier of the node. 986 @type nodeIdentifier: C{unicode} 987 @param itemIdentifiers: Identifiers of the items to be retracted. 988 @type itemIdentifiers: C{set} 989 @param notify: True if notification is required 990 @type notify: C{unicode} 991 """ 992 request = self._request_class('retract') 993 request.recipient = service 994 request.nodeIdentifier = nodeIdentifier 995 request.itemIdentifiers = itemIdentifiers 996 request.notify = notify 997 request.sender = sender 998 return request.send(self.xmlstream) 958 999 959 1000 def getOptions(self, service, nodeIdentifier, subscriber, … … 1378 1419 1379 1420 1421 def notifyRetract(self, service, nodeIdentifier, notifications): 1422 for subscriber, subscriptions, items in notifications: 1423 message = self._createNotification('items', service, 1424 nodeIdentifier, subscriber, 1425 subscriptions) 1426 for item in items: 1427 retract = domish.Element((None, "retract")) 1428 retract['id'] = item['id'] 1429 message.event.items.addChild(retract) 1430 self.send(message) 1431 1432 1380 1433 def notifyDelete(self, service, nodeIdentifier, subscribers, 1381 1434 redirectURI=None): -
wokkel/pubsub.py
r225 r226 11 11 """ 12 12 13 from zope.interface import implements 13 from __future__ import division, absolute_import 14 15 from zope.interface import implementer 14 16 15 17 from twisted.internet import defer 16 18 from twisted.python import log 19 from twisted.python.compat import StringType, iteritems, unicode 17 20 from twisted.words.protocols.jabber import jid, error 18 21 from twisted.words.xish import domish … … 107 110 108 111 @ivar nodeIdentifier: The identifier of the node subscribed to. The root 109 node is denoted by C{None}.110 @type nodeIdentifier: C{unicode}112 node is denoted by L{None}. 113 @type nodeIdentifier: L{unicode} 111 114 112 115 @ivar subscriber: The subscribing entity. … … 115 118 @ivar state: The subscription state. One of C{'subscribed'}, C{'pending'}, 116 119 C{'unconfigured'}. 117 @type state: C{unicode}120 @type state: L{unicode} 118 121 119 122 @ivar options: Optional list of subscription options. 120 @type options: C{dict}123 @type options: L{dict} 121 124 122 125 @ivar subscriptionIdentifier: Optional subscription identifier. 123 @type subscriptionIdentifier: C{unicode}126 @type subscriptionIdentifier: L{unicode} 124 127 """ 125 128 … … 172 175 """ 173 176 @param id: optional item identifier 174 @type id: C{unicode}177 @type id: L{unicode} 175 178 @param payload: optional item payload. Either as a domish element, or 176 179 as serialized XML. 177 @type payload: object providing L{domish.IElement} or C{unicode}.180 @type payload: object providing L{domish.IElement} or L{unicode}. 178 181 """ 179 182 … … 182 185 self['id'] = id 183 186 if payload is not None: 184 if isinstance(payload, basestring):187 if isinstance(payload, StringType): 185 188 self.addRawXml(payload) 186 189 else: … … 195 198 The set of instance variables used depends on the type of request. If 196 199 a variable is not applicable or not passed in the request, its value is 197 C{None}.200 L{None}. 198 201 199 202 @ivar verb: The type of publish-subscribe request. See C{_requestVerbMap}. 200 @type verb: C{str}.203 @type verb: L{str}. 201 204 202 205 @ivar affiliations: Affiliations to be modified. 203 @type affiliations: C{set}206 @type affiliations: L{set} 204 207 205 208 @ivar items: The items to be published, as L{domish.Element}s. 206 @type items: C{list}209 @type items: L{list} 207 210 208 211 @ivar itemIdentifiers: Identifiers of the items to be retrieved or 209 212 retracted. 210 @type itemIdentifiers: C{set}213 @type itemIdentifiers: L{set} 211 214 212 215 @ivar maxItems: Maximum number of items to retrieve. 213 @type maxItems: C{int}.216 @type maxItems: L{int}. 214 217 215 218 @ivar nodeIdentifier: Identifier of the node the request is about. 216 @type nodeIdentifier: C{unicode}219 @type nodeIdentifier: L{unicode} 217 220 218 221 @ivar nodeType: The type of node that should be created, or for which the 219 222 configuration is retrieved. C{'leaf'} or C{'collection'}. 220 @type nodeType: C{str}223 @type nodeType: L{str} 221 224 222 225 @ivar options: Configurations options for nodes, subscriptions and publish … … 228 231 229 232 @ivar subscriptionIdentifier: Identifier for a specific subscription. 230 @type subscriptionIdentifier: C{unicode}233 @type subscriptionIdentifier: L{unicode} 231 234 232 235 @ivar subscriptions: Subscriptions to be modified, as a set of 233 236 L{Subscription}. 234 @type subscriptions: C{set}237 @type subscriptions: L{set} 235 238 236 239 @ivar affiliations: Affiliations to be modified, as a dictionary of entity 237 240 (L{JID<twisted.words.protocols.jabber.jid.JID>} to affiliation 238 ( C{unicode}).239 @type affiliations: C{dict}241 (L{unicode}). 242 @type affiliations: L{dict} 240 243 """ 241 244 … … 279 282 280 283 # Map request verb to request iq type and subelement name 281 _verbRequestMap = dict(((v, k) for k, v in _requestVerbMap.iteritems()))284 _verbRequestMap = dict(((v, k) for k, v in iteritems(_requestVerbMap))) 282 285 283 286 # Map request verb to parameter handler names … … 667 670 @type recipient: L{wokkel.pubsub.ItemsEvent} 668 671 @param nodeIdentifier: Identifier of the node the event pertains to. 669 @type nodeIdentifier: C{unicode}672 @type nodeIdentifier: L{unicode} 670 673 @param headers: SHIM headers, see L{wokkel.shim.extractHeaders}. 671 @type headers: C{dict}674 @type headers: L{dict} 672 675 """ 673 676 … … 685 688 686 689 @param items: List of received items as domish elements. 687 @type items: C{list} of L{domish.Element}690 @type items: L{list} of L{domish.Element} 688 691 """ 689 692 … … 710 713 711 714 715 @implementer(IPubSubClient) 712 716 class PubSubClient(XMPPHandler): 713 717 """ 714 718 Publish subscribe client protocol. 715 719 """ 716 717 implements(IPubSubClient)718 720 719 721 def connectionInitialized(self): … … 792 794 @type service: L{JID<twisted.words.protocols.jabber.jid.JID>} 793 795 @param nodeIdentifier: Optional suggestion for the id of the node. 794 @type nodeIdentifier: C{unicode}796 @type nodeIdentifier: L{unicode} 795 797 @param options: Optional node configuration options. 796 @type options: C{dict}798 @type options: L{dict} 797 799 """ 798 800 request = PubSubRequest('create') … … 827 829 @type service: L{JID<twisted.words.protocols.jabber.jid.JID>} 828 830 @param nodeIdentifier: The identifier of the node. 829 @type nodeIdentifier: C{unicode}831 @type nodeIdentifier: L{unicode} 830 832 """ 831 833 request = PubSubRequest('delete') … … 845 847 846 848 @param nodeIdentifier: The identifier of the node. 847 @type nodeIdentifier: C{unicode}849 @type nodeIdentifier: L{unicode} 848 850 849 851 @param subscriber: The entity to subscribe to the node. This entity … … 852 854 853 855 @param options: Subscription options. 854 @type options: C{dict}856 @type options: L{dict} 855 857 856 858 @return: Deferred that fires with L{Subscription} or errbacks with … … 897 899 898 900 @param nodeIdentifier: The identifier of the node. 899 @type nodeIdentifier: C{unicode}901 @type nodeIdentifier: L{unicode} 900 902 901 903 @param subscriber: The entity to unsubscribe from the node. … … 903 905 904 906 @param subscriptionIdentifier: Optional subscription identifier. 905 @type subscriptionIdentifier: C{unicode}907 @type subscriptionIdentifier: L{unicode} 906 908 """ 907 909 request = PubSubRequest('unsubscribe') … … 921 923 @type service: L{JID<twisted.words.protocols.jabber.jid.JID>} 922 924 @param nodeIdentifier: The identifier of the node. 923 @type nodeIdentifier: C{unicode}925 @type nodeIdentifier: L{unicode} 924 926 @param items: Optional list of L{Item}s to publish. 925 @type items: C{list}927 @type items: L{list} 926 928 """ 927 929 request = PubSubRequest('publish') … … 934 936 935 937 def items(self, service, nodeIdentifier, maxItems=None, 936 subscriptionIdentifier=None, sender=None ):938 subscriptionIdentifier=None, sender=None, itemIdentifiers=None): 937 939 """ 938 940 Retrieve previously published items from a publish subscribe node. … … 942 944 943 945 @param nodeIdentifier: The identifier of the node. 944 @type nodeIdentifier: C{unicode}946 @type nodeIdentifier: L{unicode} 945 947 946 948 @param maxItems: Optional limit on the number of retrieved items. 947 @type maxItems: C{int}949 @type maxItems: L{int} 948 950 949 951 @param subscriptionIdentifier: Optional subscription identifier. In 950 952 case the node has been subscribed to multiple times, this narrows 951 953 the results to the specific subscription. 952 @type subscriptionIdentifier: C{unicode} 954 @type subscriptionIdentifier: L{unicode} 955 956 @param itemIdentifiers: Identifiers of the items to be retrieved. 957 @type itemIdentifiers: L{set} of L{unicode} 953 958 """ 954 959 request = PubSubRequest('items') … … 959 964 request.subscriptionIdentifier = subscriptionIdentifier 960 965 request.sender = sender 966 request.itemIdentifiers = itemIdentifiers 961 967 962 968 def cb(iq): … … 1001 1007 1002 1008 @param nodeIdentifier: The identifier of the node. 1003 @type nodeIdentifier: C{unicode}1009 @type nodeIdentifier: L{unicode} 1004 1010 1005 1011 @param subscriber: The entity subscribed to the node. … … 1007 1013 1008 1014 @param subscriptionIdentifier: Optional subscription identifier. 1009 @type subscriptionIdentifier: C{unicode}1015 @type subscriptionIdentifier: L{unicode} 1010 1016 1011 1017 @rtype: L{data_form.Form} … … 1038 1044 1039 1045 @param nodeIdentifier: The identifier of the node. 1040 @type nodeIdentifier: C{unicode}1046 @type nodeIdentifier: L{unicode} 1041 1047 1042 1048 @param subscriber: The entity subscribed to the node. … … 1044 1050 1045 1051 @param options: Subscription options. 1046 @type options: C{dict}.1052 @type options: L{dict}. 1047 1053 1048 1054 @param subscriptionIdentifier: Optional subscription identifier. 1049 @type subscriptionIdentifier: C{unicode}1055 @type subscriptionIdentifier: L{unicode} 1050 1056 """ 1051 1057 request = PubSubRequest('optionsSet') … … 1066 1072 1067 1073 1074 @implementer(IPubSubService, disco.IDisco) 1068 1075 class PubSubService(XMPPHandler, IQHandlerMixin): 1069 1076 """ … … 1090 1097 keys C{'category'}, C{'type'} and C{'name'}. 1091 1098 @ivar pubSubFeatures: List of supported publish-subscribe features for 1092 service discovery, as C{str}. 1093 @type pubSubFeatures: C{list} or C{None} 1094 """ 1095 1096 implements(IPubSubService, disco.IDisco) 1099 service discovery, as L{str}. 1100 @type pubSubFeatures: L{list} or L{None} 1101 """ 1097 1102 1098 1103 iqHandlers = { … … 1393 1398 affiliations['node'] = request.nodeIdentifier 1394 1399 1395 for entity, affiliation in result.iteritems():1400 for entity, affiliation in iteritems(result): 1396 1401 item = affiliations.addElement('affiliation') 1397 1402 item['jid'] = entity.full() … … 1504 1509 1505 1510 1511 @implementer(IPubSubResource) 1506 1512 class PubSubResource(object): 1507 1508 implements(IPubSubResource)1509 1513 1510 1514 features = [] -
wokkel/test/test_pubsub.py
r222 r226 907 907 908 908 909 def test_retractItems(self): 910 """ 911 Test sending items retraction. 912 """ 913 d = self.protocol.retractItems(JID('pubsub.example.org'), 'test', 914 itemIdentifiers=['item1', 'item2']) 915 916 iq = self.stub.output[-1] 917 self.assertEquals('pubsub.example.org', iq.getAttribute('to')) 918 self.assertEquals('set', iq.getAttribute('type')) 919 self.assertEquals('pubsub', iq.pubsub.name) 920 self.assertEquals(NS_PUBSUB, iq.pubsub.uri) 921 children = list(domish.generateElementsQNamed(iq.pubsub.children, 922 'retract', NS_PUBSUB)) 923 self.assertEquals(1, len(children)) 924 child = children[0] 925 self.assertEquals('test', child['node']) 926 itemIdentifiers = [item.getAttribute('id') for item in 927 domish.generateElementsQNamed(child.children, 'item', 928 NS_PUBSUB)] 929 self.assertEquals(['item1', 'item2'], itemIdentifiers) 930 931 self.stub.send(toResponse(iq, 'result')) 932 return d 933 934 935 def test_retractItemsWithSender(self): 936 """ 937 Test retracting items request from a specific JID. 938 """ 939 d = self.protocol.retractItems(JID('pubsub.example.org'), 'test', 940 itemIdentifiers=['item1', 'item2'], 941 sender=JID('user@example.org')) 942 943 iq = self.stub.output[-1] 944 self.assertEquals('user@example.org', iq['from']) 945 946 self.stub.send(toResponse(iq, 'result')) 947 return d 948 949 909 950 def test_getOptions(self): 910 951 def cb(form): -
wokkel/test/test_pubsub.py
r225 r226 5 5 Tests for L{wokkel.pubsub} 6 6 """ 7 8 from __future__ import division, absolute_import 7 9 8 10 from zope.interface import verify … … 113 115 element = subscription.toElement() 114 116 self.assertEqual('1234', element.getAttribute('subid')) 117 118 119 120 class ItemTests(unittest.TestCase): 121 """ 122 Tests for L{pubsub.Item}. 123 """ 124 125 def test_payloadRaw(self): 126 """ 127 Adding a payload as a string assumes serialized XML. 128 """ 129 payload = "<test xmlns='foo'/>" 130 item = pubsub.Item(payload=payload) 131 self.assertEqual(payload, item.children[0]) 132 133 134 def test_payloadElement(self): 135 """ 136 Adding a payload as an domish Element, just adds that element as child. 137 """ 138 payload = domish.Element(('foo', 'test')) 139 item = pubsub.Item(payload=payload) 140 self.assertIs(payload, item.children[0]) 115 141 116 142 … … 802 828 803 829 830 def test_itemsWithItemIdentifiers(self): 831 """ 832 Test sending items request with item identifiers. 833 """ 834 def cb(items): 835 self.assertEquals(2, len(items)) 836 self.assertEquals([item1, item2], items) 837 838 d = self.protocol.items(JID('pubsub.example.org'), 'test', 839 itemIdentifiers=['item1', 'item2']) 840 d.addCallback(cb) 841 842 iq = self.stub.output[-1] 843 self.assertEquals('pubsub.example.org', iq.getAttribute('to')) 844 self.assertEquals('get', iq.getAttribute('type')) 845 self.assertEquals('pubsub', iq.pubsub.name) 846 self.assertEquals(NS_PUBSUB, iq.pubsub.uri) 847 children = list(domish.generateElementsQNamed(iq.pubsub.children, 848 'items', NS_PUBSUB)) 849 self.assertEquals(1, len(children)) 850 child = children[0] 851 self.assertEquals('test', child['node']) 852 itemIdentifiers = [item.getAttribute('id') for item in 853 domish.generateElementsQNamed(child.children, 'item', 854 NS_PUBSUB)] 855 self.assertEquals(['item1', 'item2'], itemIdentifiers) 856 857 response = toResponse(iq, 'result') 858 items = response.addElement((NS_PUBSUB, 'pubsub')).addElement('items') 859 items['node'] = 'test' 860 item1 = items.addElement('item') 861 item1['id'] = 'item1' 862 item2 = items.addElement('item') 863 item2['id'] = 'item2' 864 865 self.stub.send(response) 866 867 return d 868 869 804 870 def test_itemsWithSubscriptionIdentifier(self): 805 871 """ … … 2955 3021 def configureSet(request): 2956 3022 self.assertEquals(['pubsub#deliver_payloads'], 2957 request.options.keys())3023 list(request.options.keys())) 2958 3024 2959 3025 self.resource.getConfigurationOptions = getConfigurationOptions
Note: See TracChangeset
for help on using the changeset viewer.