Changeset 30:68535ae85c8d for wokkel
- Timestamp:
- Aug 4, 2008, 3:44:57 PM (14 years ago)
- Branch:
- default
- Convert:
- svn:b33ecbfc-034c-dc11-8662-000475d9059e/trunk@60
- Location:
- wokkel
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
wokkel/disco.py
r6 r30 54 54 """ 55 55 56 def __init__(self, jid, node = None, name =None):56 def __init__(self, jid, node='', name=None): 57 57 domish.Element.__init__(self, (NS_ITEMS, 'item'), 58 58 attribs={'jid': jid.full()}) … … 87 87 requestor = jid.internJID(iq["from"]) 88 88 target = jid.internJID(iq["to"]) 89 nodeIdentifier = iq.query.getAttribute("node" )89 nodeIdentifier = iq.query.getAttribute("node", '') 90 90 91 91 def toResponse(results): … … 117 117 requestor = jid.internJID(iq["from"]) 118 118 target = jid.internJID(iq["to"]) 119 nodeIdentifier = iq.query.getAttribute("node" )119 nodeIdentifier = iq.query.getAttribute("node", '') 120 120 121 121 def toResponse(results): -
wokkel/generic.py
r24 r30 42 42 elementStream.parse(string) 43 43 return results and results[0] or None 44 45 46 47 def stripNamespace(rootElement): 48 namespace = rootElement.uri 49 50 def strip(element): 51 if element.uri == namespace: 52 element.uri = None 53 if element.defaultUri == namespace: 54 element.defaultUri = None 55 for child in element.elements(): 56 strip(child) 57 58 if namespace is not None: 59 strip(rootElement) 60 61 return rootElement 44 62 45 63 -
wokkel/iwokkel.py
r27 r30 107 107 """ 108 108 109 def getDiscoInfo(requestor, target, nodeIdentifier= None):109 def getDiscoInfo(requestor, target, nodeIdentifier=''): 110 110 """ 111 111 Get identity and features from this entity, node. … … 117 117 @param nodeIdentifier: The optional identifier of the node at this 118 118 entity to retrieve the identify and features of. 119 The default is C{ None}, meaning the root node.120 @type nodeIdentifier: C{unicode} 121 """ 122 123 def getDiscoItems(requestor, target, nodeIdentifier= None):119 The default is C{''}, meaning the root node. 120 @type nodeIdentifier: C{unicode} 121 """ 122 123 def getDiscoItems(requestor, target, nodeIdentifier=''): 124 124 """ 125 125 Get contained items for this entity, node. … … 131 131 @param nodeIdentifier: The optional identifier of the node at this 132 132 entity to retrieve the identify and features of. 133 The default is C{ None}, meaning the root node.133 The default is C{''}, meaning the root node. 134 134 @type nodeIdentifier: C{unicode} 135 135 """ -
wokkel/pubsub.py
r29 r30 70 70 PUBSUB_DELETE = PUBSUB_OWNER_SET + '/delete' + IN_NS_PUBSUB_OWNER 71 71 72 class BadRequest(error.StanzaError):73 """74 Bad request stanza error.75 """76 def __init__(self):77 error.StanzaError.__init__(self, 'bad-request')78 79 80 81 72 class SubscriptionPending(Exception): 82 73 """ … … 108 99 109 100 101 class BadRequest(PubSubError): 102 """ 103 Bad request stanza error. 104 """ 105 def __init__(self, pubsubCondition=None, text=None): 106 PubSubError.__init__(self, 'bad-request', pubsubCondition, text) 107 108 109 110 110 class Unsupported(PubSubError): 111 111 def __init__(self, feature, text=None): … … 117 117 118 118 119 class OptionsUnavailable(Unsupported): 120 def __init__(self): 121 Unsupported.__init__(self, 'subscription-options-unavailable') 119 class Subscription(object): 120 """ 121 A subscription to a node. 122 123 @ivar nodeIdentifier: The identifier of the node subscribed to. 124 The root node is denoted by C{None}. 125 @ivar subscriber: The subscribing entity. 126 @ivar state: The subscription state. One of C{'subscribed'}, C{'pending'}, 127 C{'unconfigured'}. 128 @ivar options: Optional list of subscription options. 129 @type options: C{dict}. 130 """ 131 132 def __init__(self, nodeIdentifier, subscriber, state, options=None): 133 self.nodeIdentifier = nodeIdentifier 134 self.subscriber = subscriber 135 self.state = state 136 self.options = options or {} 122 137 123 138 … … 274 289 message.handled = True 275 290 291 276 292 def _onEvent_items(self, sender, recipient, action, headers): 277 293 nodeIdentifier = action["node"] … … 282 298 event = ItemsEvent(sender, recipient, nodeIdentifier, items, headers) 283 299 self.itemsReceived(event) 300 284 301 285 302 def _onEvent_delete(self, sender, recipient, action, headers): … … 288 305 self.deleteReceived(event) 289 306 307 290 308 def _onEvent_purge(self, sender, recipient, action, headers): 291 309 nodeIdentifier = action["node"] … … 293 311 self.purgeReceived(event) 294 312 313 295 314 def itemsReceived(self, event): 296 315 pass 297 316 317 298 318 def deleteReceived(self, event): 299 319 pass 300 320 321 301 322 def purgeReceived(self, event): 302 323 pass 324 303 325 304 326 def createNode(self, service, nodeIdentifier=None): … … 355 377 """ 356 378 request = _PubSubRequest(self.xmlstream, 'subscribe') 357 request.command['node'] = nodeIdentifier 379 if nodeIdentifier: 380 request.command['node'] = nodeIdentifier 358 381 request.command['jid'] = subscriber.full() 359 382 … … 386 409 """ 387 410 request = _PubSubRequest(self.xmlstream, 'unsubscribe') 388 request.command['node'] = nodeIdentifier 411 if nodeIdentifier: 412 request.command['node'] = nodeIdentifier 389 413 request.command['jid'] = subscriber.full() 390 414 return request.send(service) … … 423 447 """ 424 448 request = _PubSubRequest(self.xmlstream, 'items', method='get') 425 request.command['node'] = nodeIdentifier 449 if nodeIdentifier: 450 request.command['node'] = nodeIdentifier 426 451 if maxItems: 427 452 request.command["max_items"] = str(int(maxItems)) … … 573 598 574 599 575 def _onPublish(self, iq): 600 def _getParameter_node(self, commandElement): 601 try: 602 return commandElement["node"] 603 except KeyError: 604 raise BadRequest('nodeid-required') 605 606 607 def _getParameter_nodeOrEmpty(self, commandElement): 608 return commandElement.getAttribute("node", '') 609 610 611 def _getParameter_jid(self, commandElement): 612 try: 613 return jid.internJID(commandElement["jid"]) 614 except KeyError: 615 raise BadRequest('jid-required') 616 617 618 def _getParameter_max_items(self, commandElement): 619 value = commandElement.getAttribute('max_items') 620 621 if value: 622 try: 623 return int(value) 624 except ValueError: 625 raise BadRequest(text="Field max_items requires a positive " + 626 "integer value") 627 else: 628 return None 629 630 631 def _getParameters(self, iq, *names): 576 632 requestor = jid.internJID(iq["from"]).userhostJID() 577 633 service = jid.internJID(iq["to"]) 578 634 579 try: 580 nodeIdentifier = iq.pubsub.publish["node"] 581 except KeyError: 582 raise BadRequest 635 params = [requestor, service] 636 637 if names: 638 command = names[0] 639 commandElement = getattr(iq.pubsub, command) 640 if not commandElement: 641 raise Exception("Could not find command element %r" % command) 642 643 for name in names[1:]: 644 try: 645 getter = getattr(self, '_getParameter_' + name) 646 except KeyError: 647 raise Exception("No parameter getter for this name") 648 649 params.append(getter(commandElement)) 650 651 return params 652 653 654 def _onPublish(self, iq): 655 requestor, service, nodeIdentifier = self._getParameters( 656 iq, 'publish', 'node') 583 657 584 658 items = [] … … 591 665 592 666 def _onSubscribe(self, iq): 593 requestor = jid.internJID(iq["from"]).userhostJID() 594 service = jid.internJID(iq["to"]) 595 596 try: 597 nodeIdentifier = iq.pubsub.subscribe["node"] 598 subscriber = jid.internJID(iq.pubsub.subscribe["jid"]) 599 except KeyError: 600 raise BadRequest 601 602 def toResponse(subscription): 603 nodeIdentifier, state = subscription 667 requestor, service, nodeIdentifier, subscriber = self._getParameters( 668 iq, 'subscribe', 'nodeOrEmpty', 'jid') 669 670 def toResponse(result): 604 671 response = domish.Element((NS_PUBSUB, "pubsub")) 605 672 subscription = response.addElement("subscription") 606 subscription["node"] = nodeIdentifier 607 subscription["jid"] = subscriber.full() 608 subscription["subscription"] = state 673 if result.nodeIdentifier: 674 subscription["node"] = result.nodeIdentifier 675 subscription["jid"] = result.subscriber.full() 676 subscription["subscription"] = result.state 609 677 return response 610 678 … … 615 683 616 684 def _onUnsubscribe(self, iq): 617 requestor = jid.internJID(iq["from"]).userhostJID() 618 service = jid.internJID(iq["to"]) 619 620 try: 621 nodeIdentifier = iq.pubsub.unsubscribe["node"] 622 subscriber = jid.internJID(iq.pubsub.unsubscribe["jid"]) 623 except KeyError: 624 raise BadRequest 685 requestor, service, nodeIdentifier, subscriber = self._getParameters( 686 iq, 'unsubscribe', 'nodeOrEmpty', 'jid') 625 687 626 688 return self.unsubscribe(requestor, service, nodeIdentifier, subscriber) … … 628 690 629 691 def _onOptionsGet(self, iq): 630 raise Unsupported('subscription-options -unavailable')692 raise Unsupported('subscription-options') 631 693 632 694 633 695 def _onOptionsSet(self, iq): 634 raise Unsupported('subscription-options -unavailable')696 raise Unsupported('subscription-options') 635 697 636 698 637 699 def _onSubscriptions(self, iq): 638 requestor = jid.internJID(iq["from"]).userhostJID() 639 service = jid.internJID(iq["to"]) 700 requestor, service = self._getParameters(iq) 640 701 641 702 def toResponse(result): … … 655 716 656 717 def _onAffiliations(self, iq): 657 requestor = jid.internJID(iq["from"]).userhostJID() 658 service = jid.internJID(iq["to"]) 718 requestor, service = self._getParameters(iq) 659 719 660 720 def toResponse(result): … … 675 735 676 736 def _onCreate(self, iq): 677 requestor = jid.internJID(iq["from"]).userhostJID() 678 service = jid.internJID(iq["to"]) 737 requestor, service = self._getParameters(iq) 679 738 nodeIdentifier = iq.pubsub.create.getAttribute("node") 680 739 … … 743 802 744 803 def _onDefault(self, iq): 745 requestor = jid.internJID(iq["from"]).userhostJID() 746 service = jid.internJID(iq["to"]) 804 requestor, service = self._getParameters(iq) 747 805 748 806 def toResponse(options): … … 752 810 return response 753 811 754 d = self.getDefaultConfiguration(requestor, service) 812 form = self._findForm(iq.pubsub.config, NS_PUBSUB_NODE_CONFIG) 813 values = form and form.formType == 'result' and form.getValues() or {} 814 nodeType = values.get('pubsub#node_type', 'leaf') 815 816 if nodeType not in ('leaf', 'collections'): 817 return defer.fail(error.StanzaError('not-acceptable')) 818 819 d = self.getDefaultConfiguration(requestor, service, nodeType) 755 820 d.addCallback(toResponse) 756 821 return d … … 758 823 759 824 def _onConfigureGet(self, iq): 760 requestor = jid.internJID(iq["from"]).userhostJID() 761 service = jid.internJID(iq["to"]) 762 nodeIdentifier = iq.pubsub.configure.getAttribute("node") 825 requestor, service, nodeIdentifier = self._getParameters( 826 iq, 'configure', 'nodeOrEmpty') 763 827 764 828 def toResponse(options): … … 778 842 779 843 def _onConfigureSet(self, iq): 780 requestor = jid.internJID(iq["from"]).userhostJID() 781 service = jid.internJID(iq["to"]) 782 nodeIdentifier = iq.pubsub.configure["node"] 844 requestor, service, nodeIdentifier = self._getParameters( 845 iq, 'configure', 'nodeOrEmpty') 783 846 784 847 # Search configuration form with correct FORM_TYPE and process it … … 799 862 800 863 def _onItems(self, iq): 801 requestor = jid.internJID(iq["from"]).userhostJID() 802 service = jid.internJID(iq["to"]) 803 804 try: 805 nodeIdentifier = iq.pubsub.items["node"] 806 except KeyError: 807 raise BadRequest 808 809 maxItems = iq.pubsub.items.getAttribute('max_items') 810 811 if maxItems: 812 try: 813 maxItems = int(maxItems) 814 except ValueError: 815 raise BadRequest 864 requestor, service, nodeIdentifier, maxItems = self._getParameters( 865 iq, 'items', 'nodeOrEmpty', 'max_items') 816 866 817 867 itemIdentifiers = [] … … 821 871 itemIdentifiers.append(child["id"]) 822 872 except KeyError: 823 raise BadRequest 873 raise BadRequest() 824 874 825 875 def toResponse(result): 826 876 response = domish.Element((NS_PUBSUB, 'pubsub')) 827 877 items = response.addElement('items') 828 items["node"] = nodeIdentifier 878 if nodeIdentifier: 879 items["node"] = nodeIdentifier 829 880 830 881 for item in result: … … 840 891 841 892 def _onRetract(self, iq): 842 requestor = jid.internJID(iq["from"]).userhostJID() 843 service = jid.internJID(iq["to"]) 844 845 try: 846 nodeIdentifier = iq.pubsub.retract["node"] 847 except KeyError: 848 raise BadRequest 893 requestor, service, nodeIdentifier = self._getParameters( 894 iq, 'retract', 'node') 849 895 850 896 itemIdentifiers = [] 851 897 for child in iq.pubsub.retract.elements(): 852 if child.uri == NS_PUBSUB _OWNERand child.name == 'item':898 if child.uri == NS_PUBSUB and child.name == 'item': 853 899 try: 854 900 itemIdentifiers.append(child["id"]) 855 901 except KeyError: 856 raise BadRequest 902 raise BadRequest() 857 903 858 904 return self.retract(requestor, service, nodeIdentifier, … … 861 907 862 908 def _onPurge(self, iq): 863 requestor = jid.internJID(iq["from"]).userhostJID() 864 service = jid.internJID(iq["to"]) 865 866 try: 867 nodeIdentifier = iq.pubsub.purge["node"] 868 except KeyError: 869 raise BadRequest 870 909 requestor, service, nodeIdentifier = self._getParameters( 910 iq, 'purge', 'node') 871 911 return self.purge(requestor, service, nodeIdentifier) 872 912 873 913 874 914 def _onDelete(self, iq): 875 requestor = jid.internJID(iq["from"]).userhostJID() 876 service = jid.internJID(iq["to"]) 877 878 try: 879 nodeIdentifier = iq.pubsub.delete["node"] 880 except KeyError: 881 raise BadRequest 882 915 requestor, service, nodeIdentifier = self._getParameters( 916 iq, 'delete', 'node') 883 917 return self.delete(requestor, service, nodeIdentifier) 884 918 … … 901 935 # public methods 902 936 937 def _createNotification(self, eventType, service, nodeIdentifier, 938 subscriber, subscriptions=None): 939 headers = [] 940 941 if subscriptions: 942 for subscription in subscriptions: 943 if nodeIdentifier != subscription.nodeIdentifier: 944 headers.append(('Collection', subscription.nodeIdentifier)) 945 946 message = domish.Element((None, "message")) 947 message["from"] = service.full() 948 message["to"] = subscriber.full() 949 event = message.addElement((NS_PUBSUB_EVENT, "event")) 950 951 element = event.addElement(eventType) 952 element["node"] = nodeIdentifier 953 954 if headers: 955 message.addChild(shim.Headers(headers)) 956 957 return message 958 903 959 def notifyPublish(self, service, nodeIdentifier, notifications): 904 for recipient, items in notifications: 905 message = domish.Element((None, "message")) 906 message["from"] = service.full() 907 message["to"] = recipient.full() 908 event = message.addElement((NS_PUBSUB_EVENT, "event")) 909 element = event.addElement("items") 910 element["node"] = nodeIdentifier 911 element.children = items 960 for subscriber, subscriptions, items in notifications: 961 message = self._createNotification('items', service, 962 nodeIdentifier, subscriber, 963 subscriptions) 964 message.event.items.children = items 912 965 self.send(message) 913 966 914 967 915 def notifyDelete(self, service, nodeIdentifier, recipients): 916 for recipient in recipients: 917 message = domish.Element((None, "message")) 918 message["from"] = service.full() 919 message["to"] = recipient.full() 920 event = message.addElement((NS_PUBSUB_EVENT, "event")) 921 element = event.addElement("delete") 922 element["node"] = nodeIdentifier 968 def notifyDelete(self, service, nodeIdentifier, subscriptions): 969 for subscription in subscriptions: 970 message = self._createNotification('delete', service, 971 nodeIdentifier, 972 subscription.subscriber) 923 973 self.send(message) 924 974 -
wokkel/test/test_disco.py
r6 r30 22 22 23 23 def getDiscoInfo(self, requestor, target, nodeIdentifier): 24 if no deIdentifier is None:24 if not nodeIdentifier: 25 25 return defer.succeed([ 26 26 disco.DiscoIdentity('dummy', 'generic', 'Generic Dummy Entity'), -
wokkel/test/test_pubsub.py
r29 r30 14 14 from twisted.words.protocols.jabber.jid import JID 15 15 16 from wokkel import data_form, iwokkel, pubsub 16 from wokkel import data_form, iwokkel, pubsub, shim 17 17 from wokkel.generic import parseXml 18 18 from wokkel.test.helpers import XmlStreamStub … … 85 85 self.assertEquals('test', event.nodeIdentifier) 86 86 self.assertEquals([item1, item2, item3], event.items) 87 88 d, self.protocol.itemsReceived = calledAsync(itemsReceived) 89 self.stub.send(message) 90 return d 91 92 93 def test_eventItemsCollection(self): 94 """ 95 Test receiving an items event resulting in a call to itemsReceived. 96 """ 97 message = domish.Element((None, 'message')) 98 message['from'] = 'pubsub.example.org' 99 message['to'] = 'user@example.org/home' 100 event = message.addElement((NS_PUBSUB_EVENT, 'event')) 101 items = event.addElement('items') 102 items['node'] = 'test' 103 104 headers = shim.Headers([('Collection', 'collection')]) 105 message.addChild(headers) 106 107 def itemsReceived(event): 108 self.assertEquals(JID('user@example.org/home'), event.recipient) 109 self.assertEquals(JID('pubsub.example.org'), event.sender) 110 self.assertEquals('test', event.nodeIdentifier) 111 self.assertEquals({'Collection': ['collection']}, event.headers) 87 112 88 113 d, self.protocol.itemsReceived = calledAsync(itemsReceived) … … 574 599 } 575 600 576 def getDefaultConfiguration(requestor, service ):601 def getDefaultConfiguration(requestor, service, nodeType): 577 602 self.assertEqual(JID('user@example.org'), requestor) 578 603 self.assertEqual(JID('pubsub.example.org'), service) 604 self.assertEqual('leaf', nodeType) 579 605 return defer.succeed({}) 580 606 … … 800 826 d.addCallback(cb) 801 827 return d 828 829 830 def test_onRetract(self): 831 """ 832 A retract request should result in L{PubSubService.retract} being 833 called. 834 """ 835 836 xml = """ 837 <iq type='set' to='pubsub.example.org' 838 from='user@example.org'> 839 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 840 <retract node='test'> 841 <item id='item1'/> 842 <item id='item2'/> 843 </retract> 844 </pubsub> 845 </iq> 846 """ 847 848 def retract(requestor, service, nodeIdentifier, itemIdentifiers): 849 self.assertEqual(JID('user@example.org'), requestor) 850 self.assertEqual(JID('pubsub.example.org'), service) 851 self.assertEqual('test', nodeIdentifier) 852 self.assertEqual(['item1', 'item2'], itemIdentifiers) 853 return defer.succeed(None) 854 855 self.service.retract = retract 856 return self.handleRequest(xml) 857 858 859 def test_onPurge(self): 860 """ 861 A purge request should result in L{PubSubService.purge} being 862 called. 863 """ 864 865 xml = """ 866 <iq type='set' to='pubsub.example.org' 867 from='user@example.org'> 868 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 869 <purge node='test'/> 870 </pubsub> 871 </iq> 872 """ 873 874 def purge(requestor, service, nodeIdentifier): 875 self.assertEqual(JID('user@example.org'), requestor) 876 self.assertEqual(JID('pubsub.example.org'), service) 877 self.assertEqual('test', nodeIdentifier) 878 return defer.succeed(None) 879 880 self.service.purge = purge 881 return self.handleRequest(xml) 882 883 884 def test_onDelete(self): 885 """ 886 A delete request should result in L{PubSubService.delete} being 887 called. 888 """ 889 890 xml = """ 891 <iq type='set' to='pubsub.example.org' 892 from='user@example.org'> 893 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 894 <delete node='test'/> 895 </pubsub> 896 </iq> 897 """ 898 899 def delete(requestor, service, nodeIdentifier): 900 self.assertEqual(JID('user@example.org'), requestor) 901 self.assertEqual(JID('pubsub.example.org'), service) 902 self.assertEqual('test', nodeIdentifier) 903 return defer.succeed(None) 904 905 self.service.delete = delete 906 return self.handleRequest(xml)
Note: See TracChangeset
for help on using the changeset viewer.