Changeset 4:c8c73d9e5496 in ralphm-patches
- Timestamp:
- Mar 23, 2009, 9:42:55 PM (13 years ago)
- Branch:
- default
- Files:
-
- 1 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
pubsub_client_sender.patch
r3 r4 1 diff -r 52898d5828ee wokkel/pubsub.py 2 --- a/wokkel/pubsub.py Thu Mar 05 19:41:28 2009 +0100 3 +++ b/wokkel/pubsub.py Fri Mar 06 21:15:35 2009 +0100 4 @@ -150,8 +150,11 @@ 5 C{verb}. 6 """ 7 8 - def __init__(self, xs, verb, namespace=NS_PUBSUB, method='set'): 9 + def __init__(self, xs, verb, namespace=NS_PUBSUB, method='set', 10 + sender=None): 11 xmlstream.IQ.__init__(self, xs, method) 12 + if sender: 13 + self['from'] = sender.full() 14 self.addElement((namespace, 'pubsub')) 15 16 self.command = self.pubsub.addElement(verb) 17 @@ -295,7 +298,7 @@ 1 diff -r 8be0600d2c32 wokkel/pubsub.py 2 --- a/wokkel/pubsub.py Mon Mar 23 09:00:16 2009 +0100 3 +++ b/wokkel/pubsub.py Mon Mar 23 09:00:24 2009 +0100 4 @@ -605,7 +605,7 @@ 18 5 pass 19 6 … … 24 11 Create a publish subscribe node. 25 12 26 @@ -306,7 +309,7 @@ 27 """ 28 29 30 - request = _PubSubRequest(self.xmlstream, 'create') 31 + request = _PubSubRequest(self.xmlstream, 'create', sender=sender) 32 if nodeIdentifier: 33 request.command['node'] = nodeIdentifier 34 35 @@ -321,7 +324,7 @@ 36 return request.send(service).addCallback(cb) 13 @@ -617,6 +617,7 @@ 14 request = PubSubRequest('create') 15 request.recipient = service 16 request.nodeIdentifier = nodeIdentifier 17 + request.sender = sender 18 19 def cb(iq): 20 try: 21 @@ -631,7 +632,7 @@ 22 return d 37 23 38 24 … … 42 28 Delete a publish subscribe node. 43 29 44 @@ -330,12 +333,13 @@ 45 @param nodeIdentifier: The identifier of the node. 46 @type nodeIdentifier: C{unicode} 47 """ 48 - request = _PubSubRequest(self.xmlstream, 'delete', NS_PUBSUB_OWNER) 49 + request = _PubSubRequest(self.xmlstream, 'delete', NS_PUBSUB_OWNER, 50 + sender=None) 51 request.command['node'] = nodeIdentifier 52 return request.send(service) 30 @@ -643,10 +644,11 @@ 31 request = PubSubRequest('delete') 32 request.recipient = service 33 request.nodeIdentifier = nodeIdentifier 34 + request.sender = sender 35 return request.send(self.xmlstream) 53 36 54 37 … … 58 41 Subscribe to a publish subscribe node. 59 42 60 @@ -347,7 +351,7 @@ 61 will get notifications of new published items. 62 @type subscriber: L{JID} 63 """ 64 - request = _PubSubRequest(self.xmlstream, 'subscribe') 65 + request = _PubSubRequest(self.xmlstream, 'subscribe', sender=sender) 66 if nodeIdentifier: 67 request.command['node'] = nodeIdentifier 68 request.command['jid'] = subscriber.full() 69 @@ -368,7 +372,7 @@ 70 return request.send(service).addCallback(cb) 43 @@ -662,6 +664,7 @@ 44 request.recipient = service 45 request.nodeIdentifier = nodeIdentifier 46 request.subscriber = subscriber 47 + request.sender = sender 48 49 def cb(iq): 50 subscription = iq.pubsub.subscription["subscription"] 51 @@ -681,7 +684,7 @@ 52 return d 71 53 72 54 … … 76 58 Unsubscribe from a publish subscribe node. 77 59 78 @@ -379,14 +383,14 @@ 79 @param subscriber: The entity to unsubscribe from the node. 80 @type subscriber: L{JID} 81 """ 82 - request = _PubSubRequest(self.xmlstream, 'unsubscribe') 83 + request = _PubSubRequest(self.xmlstream, 'unsubscribe', sender=sender) 84 if nodeIdentifier: 85 request.command['node'] = nodeIdentifier 86 request.command['jid'] = subscriber.full() 87 return request.send(service) 60 @@ -696,10 +699,11 @@ 61 request.recipient = service 62 request.nodeIdentifier = nodeIdentifier 63 request.subscriber = subscriber 64 + request.sender = sender 65 return request.send(self.xmlstream) 88 66 89 67 … … 93 71 Publish to a publish subscribe node. 94 72 95 @@ -397,7 +401,7 @@ 96 @param items: Optional list of L{Item}s to publish. 97 @type items: C{list} 98 """ 99 - request = _PubSubRequest(self.xmlstream, 'publish') 100 + request = _PubSubRequest(self.xmlstream, 'publish', sender=sender) 101 request.command['node'] = nodeIdentifier 102 if items: 103 for item in items: 104 @@ -406,7 +410,7 @@ 105 return request.send(service) 73 @@ -714,10 +718,11 @@ 74 request.recipient = service 75 request.nodeIdentifier = nodeIdentifier 76 request.items = items 77 + request.sender = sender 78 return request.send(self.xmlstream) 106 79 107 80 … … 111 84 Retrieve previously published items from a publish subscribe node. 112 85 113 @@ -417,7 +421,8 @@ 114 @param maxItems: Optional limit on the number of retrieved items. 115 @type maxItems: C{int} 116 """ 117 - request = _PubSubRequest(self.xmlstream, 'items', method='get') 118 + request = _PubSubRequest(self.xmlstream, 'items', method='get', 119 + sender=sender) 120 if nodeIdentifier: 121 request.command['node'] = nodeIdentifier 86 @@ -733,6 +738,7 @@ 87 request.nodeIdentifier = nodeIdentifier 122 88 if maxItems: 89 request.maxItems = str(int(maxItems)) 90 + request.sender = sender 91 92 def cb(iq): 93 items = [] 94 diff -r 8be0600d2c32 wokkel/test/test_pubsub.py 95 --- a/wokkel/test/test_pubsub.py Mon Mar 23 09:00:16 2009 +0100 96 +++ b/wokkel/test/test_pubsub.py Mon Mar 23 09:00:24 2009 +0100 97 @@ -257,6 +257,22 @@ 98 return d 99 100 101 + def test_createNodeWithSender(self): 102 + """ 103 + Test sending create request from a specific JID. 104 + """ 105 + 106 + d = self.protocol.createNode(JID('pubsub.example.org'), 'test', 107 + sender=JID('user@example.org')) 108 + 109 + iq = self.stub.output[-1] 110 + self.assertEquals('user@example.org', iq['from']) 111 + 112 + response = toResponse(iq, 'result') 113 + self.stub.send(response) 114 + return d 115 + 116 + 117 def test_deleteNode(self): 118 """ 119 Test sending delete request. 120 @@ -280,6 +296,22 @@ 121 return d 122 123 124 + def test_deleteNodeWithSender(self): 125 + """ 126 + Test sending delete request. 127 + """ 128 + 129 + d = self.protocol.deleteNode(JID('pubsub.example.org'), 'test', 130 + sender=JID('user@example.org')) 131 + 132 + iq = self.stub.output[-1] 133 + self.assertEquals('user@example.org', iq['from']) 134 + 135 + response = toResponse(iq, 'result') 136 + self.stub.send(response) 137 + return d 138 + 139 + 140 def test_publish(self): 141 """ 142 Test sending publish request. 143 @@ -331,6 +363,23 @@ 144 return d 145 146 147 + def test_publishWithSender(self): 148 + """ 149 + Test sending publish request from a specific JID. 150 + """ 151 + 152 + item = pubsub.Item() 153 + d = self.protocol.publish(JID('pubsub.example.org'), 'test', [item], 154 + JID('user@example.org')) 155 + 156 + iq = self.stub.output[-1] 157 + self.assertEquals('user@example.org', iq['from']) 158 + 159 + response = toResponse(iq, 'result') 160 + self.stub.send(response) 161 + return d 162 + 163 + 164 def test_subscribe(self): 165 """ 166 Test sending subscription request. 167 @@ -400,6 +449,27 @@ 168 return d 169 170 171 + def test_subscribeWithSender(self): 172 + """ 173 + Test sending subscription request from a specific JID. 174 + """ 175 + d = self.protocol.subscribe(JID('pubsub.example.org'), 'test', 176 + JID('user@example.org'), 177 + sender=JID('user@example.org')) 178 + 179 + iq = self.stub.output[-1] 180 + self.assertEquals('user@example.org', iq['from']) 181 + 182 + response = toResponse(iq, 'result') 183 + pubsub = response.addElement((NS_PUBSUB, 'pubsub')) 184 + subscription = pubsub.addElement('subscription') 185 + subscription['node'] = 'test' 186 + subscription['jid'] = 'user@example.org' 187 + subscription['subscription'] = 'subscribed' 188 + self.stub.send(response) 189 + return d 190 + 191 + 192 def test_unsubscribe(self): 193 """ 194 Test sending unsubscription request. 195 @@ -423,6 +493,20 @@ 196 return d 197 198 199 + def test_unsubscribeWithSender(self): 200 + """ 201 + Test sending unsubscription request from a specific JID. 202 + """ 203 + d = self.protocol.unsubscribe(JID('pubsub.example.org'), 'test', 204 + JID('user@example.org'), 205 + sender=JID('user@example.org')) 206 + 207 + iq = self.stub.output[-1] 208 + self.assertEquals('user@example.org', iq['from']) 209 + self.stub.send(toResponse(iq, 'result')) 210 + return d 211 + 212 + 213 def test_items(self): 214 """ 215 Test sending items request. 216 @@ -489,6 +573,25 @@ 217 return d 218 219 220 + def test_itemsWithSender(self): 221 + """ 222 + Test sending items request from a specific JID. 223 + """ 224 + 225 + d = self.protocol.items(JID('pubsub.example.org'), 'test', 226 + sender=JID('user@example.org')) 227 + 228 + iq = self.stub.output[-1] 229 + self.assertEquals('user@example.org', iq['from']) 230 + 231 + response = toResponse(iq, 'result') 232 + items = response.addElement((NS_PUBSUB, 'pubsub')).addElement('items') 233 + items['node'] = 'test' 234 + 235 + self.stub.send(response) 236 + return d 237 + 238 + 239 240 class PubSubServiceTest(unittest.TestCase, TestableRequestHandlerMixin): 241 """ -
pubsub_request.patch
r1 r4 11 11 that is passed to the corresponding handler methods. 12 12 13 diff -r fafe0148a94c wokkel/iwokkel.py 14 --- a/wokkel/iwokkel.py Wed Feb 25 09:21:33 2009 +0100 15 +++ b/wokkel/iwokkel.py Thu Feb 26 09:29:59 2009 +0100 13 diff -r 884ac8d88411 wokkel/generic.py 14 --- a/wokkel/generic.py Thu Mar 05 16:29:12 2009 +0100 15 +++ b/wokkel/generic.py Wed Mar 18 09:26:20 2009 +0100 16 @@ -10,7 +10,7 @@ 17 from zope.interface import implements 18 19 from twisted.internet import defer 20 -from twisted.words.protocols.jabber import error 21 +from twisted.words.protocols.jabber import error, jid 22 from twisted.words.protocols.jabber.xmlstream import toResponse 23 from twisted.words.xish import domish, utility 24 25 @@ -155,3 +155,34 @@ 26 self.sink = utility.EventDispatcher() 27 self.source.send = lambda obj: self.sink.dispatch(obj) 28 self.sink.send = lambda obj: self.source.dispatch(obj) 29 + 30 + 31 + 32 +class Stanza(object): 33 + """ 34 + Abstract representation of a stanza. 35 + 36 + @ivar sender: The sending entity. 37 + @type sender: L{jid.JID} 38 + @ivar recipient: The receiving entity. 39 + @type recipient: L{jid.JID} 40 + """ 41 + 42 + sender = None 43 + recipient = None 44 + stanzaType = None 45 + 46 + @classmethod 47 + def fromElement(Class, element): 48 + stanza = Class() 49 + stanza.parseElement(element) 50 + return stanza 51 + 52 + 53 + def parseElement(self, element): 54 + self.sender = jid.internJID(element['from']) 55 + if element.hasAttribute('from'): 56 + self.sender = jid.internJID(element['from']) 57 + if element.hasAttribute('to'): 58 + self.recipient = jid.internJID(element['to']) 59 + self.stanzaType = element.getAttribute('type') 60 diff -r 884ac8d88411 wokkel/iwokkel.py 61 --- a/wokkel/iwokkel.py Thu Mar 05 16:29:12 2009 +0100 62 +++ b/wokkel/iwokkel.py Wed Mar 18 09:26:20 2009 +0100 16 63 @@ -278,6 +278,7 @@ 17 64 C{list} of L{domish.Element}) … … 120 167 C{tuple}s of (node identifier as C{unicode}, affiliation state 121 168 as C{str}). The affiliation can be C{'owner'}, C{'publisher'}, 122 @@ -373,2 3 +357,18@@169 @@ -373,24 +357,19 @@ 123 170 @rtype: L{defer.Deferred} 124 171 """ … … 145 192 @rtype: L{defer.Deferred} 146 193 """ 147 + 148 194 195 + 149 196 def getConfigurationOptions(): 150 197 """ 198 Retrieve all known node configuration options. 151 199 @@ -426,17 +405,13 @@ 152 200 @rtype: C{dict}. … … 292 340 + @rtype: L{defer.Deferred} 293 341 """ 294 diff -r fafe0148a94c wokkel/pubsub.py 295 --- a/wokkel/pubsub.py Wed Feb 25 09:21:33 2009 +0100 296 +++ b/wokkel/pubsub.py Thu Feb 26 09:29:59 2009 +0100 342 diff -r 884ac8d88411 wokkel/pubsub.py 343 --- a/wokkel/pubsub.py Thu Mar 05 16:29:12 2009 +0100 344 +++ b/wokkel/pubsub.py Wed Mar 18 09:26:20 2009 +0100 345 @@ -16,7 +16,7 @@ 346 from twisted.words.protocols.jabber import jid, error, xmlstream 347 from twisted.words.xish import domish 348 349 -from wokkel import disco, data_form, shim 350 +from wokkel import disco, data_form, generic, shim 351 from wokkel.subprotocols import IQHandlerMixin, XMPPHandler 352 from wokkel.iwokkel import IPubSubClient, IPubSubService 353 297 354 @@ -32,42 +32,10 @@ 298 355 NS_PUBSUB_NODE_CONFIG = NS_PUBSUB + "#node_config" … … 342 399 class SubscriptionPending(Exception): 343 400 """ 344 @@ -466,6 +434,219 @@ 345 346 347 348 +class Request(object): 349 + """ 350 + An IQ request. 351 + 352 + @ivar sender: The entity from which the request was received. 353 + @type sender: L{jid.JID} 354 + @ivar recipient: The entity to which the request was sent. 355 + @type recipient: L{jid.JID} 356 + """ 357 + 358 + sender = None 359 + recipient = None 360 + stanzaType = None 361 + 362 + @classmethod 363 + def fromElement(Class, element): 364 + request = Class() 365 + request.parseElement(element) 366 + return request 367 + 368 + 369 + def parseElement(self, element): 370 + self.sender = jid.internJID(element['from']) 371 + if element.hasAttribute('from'): 372 + self.sender = jid.internJID(element['from']) 373 + if element.hasAttribute('to'): 374 + self.recipient = jid.internJID(element['to']) 375 + self.stanzaType = element.getAttribute('type') 376 + 377 + 378 + 379 +class PubSubRequest(Request): 380 + """ 401 @@ -167,40 +135,350 @@ 402 403 404 405 -class _PubSubRequest(xmlstream.IQ): 406 +class PubSubRequest(generic.Stanza): 407 """ 408 - Publish subscribe request. 381 409 + A publish-subscribe request. 382 + 410 411 - @ivar verb: Request verb 412 - @type verb: C{str} 413 - @ivar namespace: Request namespace. 414 - @type namespace: C{str} 415 - @ivar method: Type attribute of the IQ request. Either C{'set'} or C{'get'} 416 - @type method: C{str} 417 - @ivar command: Command element of the request. This is the direct child of 418 - the C{pubsub} element in the C{namespace} with the name 419 - C{verb}. 383 420 + The set of instance variables used depends on the type of request. If 384 421 + a variable is not applicable or not passed in the request, its value is 385 422 + C{None}. 423 + 424 + @ivar verb: The type of publish-subscribe request. See L{_requestVerbMap}. 425 + @type verb: C{str}. 386 426 + 387 427 + @ivar affiliations: Affiliations to be modified. … … 409 449 + L{Subscription}. 410 450 + @type subscriptions: C{set} 411 + """ 412 + 451 """ 452 453 - def __init__(self, xs, verb, namespace=NS_PUBSUB, method='set'): 454 - xmlstream.IQ.__init__(self, xs, method) 455 - self.addElement((namespace, 'pubsub')) 413 456 + verb = None 414 + 457 458 - self.command = self.pubsub.addElement(verb) 415 459 + affiliations = None 416 460 + items = None … … 423 467 + subscriptionIdentifier = None 424 468 + subscriptions = None 425 + 426 + 427 + _verbs = { 428 + ('set', NS_PUBSUB, 'publish'): ('publish', ['node', 'items']), 429 + ('set', NS_PUBSUB, 'subscribe'): ('subscribe', ['nodeOrEmpty', 'jid']), 430 + ('set', NS_PUBSUB, 'unsubscribe'): ('unsubscribe', ['node', 'jid']), 431 + ('get', NS_PUBSUB, 'options'): ('optionsGet', []), 432 + ('set', NS_PUBSUB, 'options'): ('optionsSet', []), 433 + ('get', NS_PUBSUB, 'subscriptions'): ('subscriptions', []), 434 + ('get', NS_PUBSUB, 'affiliations'): ('affiliations', []), 435 + ('set', NS_PUBSUB, 'create'): ('create', ['nodeOrNone']), 436 + ('get', NS_PUBSUB_OWNER, 'default'): ('default', ['default']), 437 + ('get', NS_PUBSUB_OWNER, 'configure'): ('configureGet', 438 + ['nodeOrEmpty']), 439 + ('set', NS_PUBSUB_OWNER, 'configure'): ('configureSet', 440 + ['nodeOrEmpty', 'configure']), 441 + ('get', NS_PUBSUB, 'items'): ('items', ['node', 'maxItems', 442 + 'itemIdentifiers']), 443 + ('set', NS_PUBSUB, 'retract'): ('retract', ['node', 444 + 'itemIdentifiers']), 445 + ('set', NS_PUBSUB_OWNER, 'purge'): ('purge', ['node']), 446 + ('set', NS_PUBSUB_OWNER, 'delete'): ('delete', ['node']), 447 + ('get', NS_PUBSUB_OWNER, 'affiliations'): ('affiliationsGet', []), 448 + ('set', NS_PUBSUB_OWNER, 'affiliations'): ('affiliationsSet', []), 449 + ('get', NS_PUBSUB_OWNER, 'subscriptions'): ('subscriptionsGet', []), 450 + ('set', NS_PUBSUB_OWNER, 'subscriptions'): ('subscriptionsSet', []), 469 470 + # Map request iq type and subelement name to request verb 471 + _requestVerbMap = { 472 + ('set', NS_PUBSUB, 'publish'): 'publish', 473 + ('set', NS_PUBSUB, 'subscribe'): 'subscribe', 474 + ('set', NS_PUBSUB, 'unsubscribe'): 'unsubscribe', 475 + ('get', NS_PUBSUB, 'options'): 'optionsGet', 476 + ('set', NS_PUBSUB, 'options'): 'optionsSet', 477 + ('get', NS_PUBSUB, 'subscriptions'): 'subscriptions', 478 + ('get', NS_PUBSUB, 'affiliations'): 'affiliations', 479 + ('set', NS_PUBSUB, 'create'): 'create', 480 + ('get', NS_PUBSUB_OWNER, 'default'): 'default', 481 + ('get', NS_PUBSUB_OWNER, 'configure'): 'configureGet', 482 + ('set', NS_PUBSUB_OWNER, 'configure'): 'configureSet', 483 + ('get', NS_PUBSUB, 'items'): 'items', 484 + ('set', NS_PUBSUB, 'retract'): 'retract', 485 + ('set', NS_PUBSUB_OWNER, 'purge'): 'purge', 486 + ('set', NS_PUBSUB_OWNER, 'delete'): 'delete', 487 + ('get', NS_PUBSUB_OWNER, 'affiliations'): 'affiliationsGet', 488 + ('set', NS_PUBSUB_OWNER, 'affiliations'): 'affiliationsSet', 489 + ('get', NS_PUBSUB_OWNER, 'subscriptions'): 'subscriptionsGet', 490 + ('set', NS_PUBSUB_OWNER, 'subscriptions'): 'subscriptionsSet', 451 491 + } 492 493 - def send(self, to): 494 + # Map request verb to request iq type and subelement name 495 + _verbRequestMap = dict(((v, k) for k, v in _requestVerbMap.iteritems())) 496 + 497 + # Map request verb to parameter handler names 498 + _parameters = { 499 + 'publish': ['node', 'items'], 500 + 'subscribe': ['nodeOrEmpty', 'jid'], 501 + 'unsubscribe': ['nodeOrEmpty', 'jid'], 502 + 'optionsGet': [], 503 + 'optionsSet': [], 504 + 'subscriptions': [], 505 + 'affiliations': [], 506 + 'create': ['nodeOrNone'], 507 + 'default': ['default'], 508 + 'configureGet': ['nodeOrEmpty'], 509 + 'configureSet': ['nodeOrEmpty', 'configure'], 510 + 'items': ['node', 'maxItems', 'itemIdentifiers'], 511 + 'retract': ['node', 'itemIdentifiers'], 512 + 'purge': ['node'], 513 + 'delete': ['node'], 514 + 'affiliationsGet': [], 515 + 'affiliationsSet': [], 516 + 'subscriptionsGet': [], 517 + 'subscriptionsSet': [], 518 + } 519 + 520 + def __init__(self, verb=None): 521 + self.verb = verb 522 + 452 523 + 453 524 + @staticmethod 454 525 + def _findForm(element, formNamespace): 526 """ 527 - Send out request. 528 + Find a Data Form. 529 530 - Extends L{xmlstream.IQ.send} by requiring the C{to} parameter to be 531 - a L{JID} instance. 532 + Look for an element that represents a Data Form with the specified 533 + form namespace as a child element of the given element. 534 + """ 455 535 + if not element: 456 536 + return None 457 + 537 538 - @param to: Entity to send the request to. 539 - @type to: L{JID} 458 540 + form = None 459 541 + for child in element.elements(): … … 470 552 + 471 553 + def _parse_node(self, verbElement): 554 """ 555 - destination = to.full() 556 - return xmlstream.IQ.send(self, destination) 557 + Parse the required node identifier out of the verbElement. 558 + """ 472 559 + try: 473 560 + self.nodeIdentifier = verbElement["node"] … … 476 563 + 477 564 + 565 + def _render_node(self, verbElement): 566 + """ 567 + Render the required node identifier on the verbElement. 568 + """ 569 + if not self.nodeIdentifier: 570 + raise Exception("Node identifier is required") 571 + 572 + verbElement['node'] = self.nodeIdentifier 573 + 574 + 478 575 + def _parse_nodeOrEmpty(self, verbElement): 576 + """ 577 + Parse the node identifier out of the verbElement. May be empty. 578 + """ 479 579 + self.nodeIdentifier = verbElement.getAttribute("node", '') 480 580 + 481 581 + 582 + def _render_nodeOrEmpty(self, verbElement): 583 + """ 584 + Render the node identifier on the verbElement. May be empty. 585 + """ 586 + if self.nodeIdentifier: 587 + verbElement['node'] = self.nodeIdentifier 588 + 589 + 482 590 + def _parse_nodeOrNone(self, verbElement): 591 + """ 592 + Parse the optional node identifier out of the verbElement. 593 + """ 483 594 + self.nodeIdentifier = verbElement.getAttribute("node") 484 595 + 485 596 + 597 + def _render_nodeOrNone(self, verbElement): 598 + """ 599 + Render the optional node identifier on the verbElement. 600 + """ 601 + if self.nodeIdentifier: 602 + verbElement['node'] = self.nodeIdentifier 603 + 604 + 486 605 + def _parse_items(self, verbElement): 606 + """ 607 + Parse items out of the verbElement for publish requests. 608 + """ 487 609 + self.items = [] 488 610 + for element in verbElement.elements(): … … 491 613 + 492 614 + 615 + def _render_items(self, verbElement): 616 + """ 617 + Render items into the verbElement for publish requests. 618 + """ 619 + if self.items: 620 + for item in self.items: 621 + verbElement.addChild(item) 622 + 623 + 493 624 + def _parse_jid(self, verbElement): 625 + """ 626 + Parse subscriber out of the verbElement for un-/subscribe requests. 627 + """ 494 628 + try: 495 629 + self.subscriber = jid.internJID(verbElement["jid"]) … … 498 632 + 499 633 + 634 + def _render_jid(self, verbElement): 635 + """ 636 + Render subscriber into the verbElement for un-/subscribe requests. 637 + """ 638 + verbElement['jid'] = self.subscriber.full() 639 + 640 + 500 641 + def _parse_default(self, verbElement): 642 + """ 643 + Parse node type out of a request for the default node configuration. 644 + """ 501 645 + form = PubSubRequest._findForm(verbElement, NS_PUBSUB_NODE_CONFIG) 502 646 + if form and form.formType == 'submit': … … 508 652 + 509 653 + def _parse_configure(self, verbElement): 654 + """ 655 + Parse options out of a request for setting the node configuration. 656 + """ 510 657 + form = PubSubRequest._findForm(verbElement, NS_PUBSUB_NODE_CONFIG) 511 658 + if form: … … 522 669 + 523 670 + def _parse_itemIdentifiers(self, verbElement): 671 + """ 672 + Parse item identifiers out of items and retract requests. 673 + """ 524 674 + self.itemIdentifiers = [] 525 675 + for element in verbElement.elements(): … … 531 681 + 532 682 + 683 + def _render_itemIdentifiers(self, verbElement): 684 + """ 685 + Render item identifiers into items and retract requests. 686 + """ 687 + if self.itemIdentifiers: 688 + for itemIdentifier in self.itemIdentifiers: 689 + item = verbElement.addElement('item') 690 + item['id'] = itemIdentifier 691 + 692 + 533 693 + def _parse_maxItems(self, verbElement): 694 + """ 695 + Parse maximum items out of an items request. 696 + """ 534 697 + value = verbElement.getAttribute('max_items') 535 698 + … … 542 705 + 543 706 + 707 + def _render_maxItems(self, verbElement): 708 + """ 709 + Parse maximum items into an items request. 710 + """ 711 + if self.maxItems: 712 + verbElement['max_items'] = unicode(self.maxItems) 713 + 714 + 544 715 + def parseElement(self, element): 545 + Request.parseElement(self, element) 716 + """ 717 + Parse the publish-subscribe verb and parameters out of a request. 718 + """ 719 + generic.Stanza.parseElement(self, element) 546 720 + 547 721 + for child in element.pubsub.elements(): 548 722 + key = (self.stanzaType, child.uri, child.name) 549 + self.verb, parsers = PubSubRequest._verbs.get(key) 550 + if self.verb: 723 + try: 724 + verb = self._requestVerbMap[key] 725 + except KeyError: 726 + continue 727 + else: 728 + self.verb = verb 551 729 + break 552 730 + … … 554 732 + raise NotImplementedError() 555 733 + 556 + for parser in parsers: 557 + getattr(self, '_parse_%s' % parser)(child) 558 + 559 + 560 + 561 class PubSubService(XMPPHandler, IQHandlerMixin): 562 """ 563 Protocol implementation for a XMPP Publish Subscribe Service. 564 @@ -497,27 +678,7 @@ 734 + for parameter in self._parameters[verb]: 735 + getattr(self, '_parse_%s' % parameter)(child) 736 + 737 + 738 + def send(self, xs): 739 + """ 740 + Send this request to its recipient. 741 + 742 + This renders all of the relevant parameters for this specific 743 + requests into an L{xmlstream.IQ}, and invoke its C{send} method. 744 + This returns a deferred that fires upon reception of a response. See 745 + L{xmlstream.IQ} for details. 746 + 747 + @param xs: The XML stream to send the request on. 748 + @type xs: L{xmlstream.XmlStream} 749 + @rtype: L{defer.Deferred}. 750 + """ 751 + 752 + try: 753 + (self.stanzaType, 754 + childURI, 755 + childName) = self._verbRequestMap[self.verb] 756 + except KeyError: 757 + raise NotImplementedError() 758 + 759 + iq = xmlstream.IQ(xs, self.stanzaType) 760 + iq.addElement((childURI, 'pubsub')) 761 + verbElement = iq.pubsub.addElement(childName) 762 + 763 + if self.sender: 764 + iq['from'] = self.sender.full() 765 + if self.recipient: 766 + iq['to'] = self.recipient.full() 767 + 768 + for parameter in self._parameters[self.verb]: 769 + getattr(self, '_render_%s' % parameter)(verbElement) 770 + 771 + return iq.send() 772 773 774 775 @@ -336,11 +614,9 @@ 776 @param nodeIdentifier: Optional suggestion for the id of the node. 777 @type nodeIdentifier: C{unicode} 778 """ 779 - 780 - 781 - request = _PubSubRequest(self.xmlstream, 'create') 782 - if nodeIdentifier: 783 - request.command['node'] = nodeIdentifier 784 + request = PubSubRequest('create') 785 + request.recipient = service 786 + request.nodeIdentifier = nodeIdentifier 787 788 def cb(iq): 789 try: 790 @@ -350,7 +626,9 @@ 791 new_node = nodeIdentifier 792 return new_node 793 794 - return request.send(service).addCallback(cb) 795 + d = request.send(self.xmlstream) 796 + d.addCallback(cb) 797 + return d 798 799 800 def deleteNode(self, service, nodeIdentifier): 801 @@ -362,9 +640,10 @@ 802 @param nodeIdentifier: The identifier of the node. 803 @type nodeIdentifier: C{unicode} 804 """ 805 - request = _PubSubRequest(self.xmlstream, 'delete', NS_PUBSUB_OWNER) 806 - request.command['node'] = nodeIdentifier 807 - return request.send(service) 808 + request = PubSubRequest('delete') 809 + request.recipient = service 810 + request.nodeIdentifier = nodeIdentifier 811 + return request.send(self.xmlstream) 812 813 814 def subscribe(self, service, nodeIdentifier, subscriber): 815 @@ -379,10 +658,10 @@ 816 will get notifications of new published items. 817 @type subscriber: L{JID} 818 """ 819 - request = _PubSubRequest(self.xmlstream, 'subscribe') 820 - if nodeIdentifier: 821 - request.command['node'] = nodeIdentifier 822 - request.command['jid'] = subscriber.full() 823 + request = PubSubRequest('subscribe') 824 + request.recipient = service 825 + request.nodeIdentifier = nodeIdentifier 826 + request.subscriber = subscriber 827 828 def cb(iq): 829 subscription = iq.pubsub.subscription["subscription"] 830 @@ -397,7 +676,9 @@ 831 # yielded a stanza error. 832 return None 833 834 - return request.send(service).addCallback(cb) 835 + d = request.send(self.xmlstream) 836 + d.addCallback(cb) 837 + return d 838 839 840 def unsubscribe(self, service, nodeIdentifier, subscriber): 841 @@ -411,11 +692,11 @@ 842 @param subscriber: The entity to unsubscribe from the node. 843 @type subscriber: L{JID} 844 """ 845 - request = _PubSubRequest(self.xmlstream, 'unsubscribe') 846 - if nodeIdentifier: 847 - request.command['node'] = nodeIdentifier 848 - request.command['jid'] = subscriber.full() 849 - return request.send(service) 850 + request = PubSubRequest('unsubscribe') 851 + request.recipient = service 852 + request.nodeIdentifier = nodeIdentifier 853 + request.subscriber = subscriber 854 + return request.send(self.xmlstream) 855 856 857 def publish(self, service, nodeIdentifier, items=None): 858 @@ -429,13 +710,11 @@ 859 @param items: Optional list of L{Item}s to publish. 860 @type items: C{list} 861 """ 862 - request = _PubSubRequest(self.xmlstream, 'publish') 863 - request.command['node'] = nodeIdentifier 864 - if items: 865 - for item in items: 866 - request.command.addChild(item) 867 - 868 - return request.send(service) 869 + request = PubSubRequest('publish') 870 + request.recipient = service 871 + request.nodeIdentifier = nodeIdentifier 872 + request.items = items 873 + return request.send(self.xmlstream) 874 875 876 def items(self, service, nodeIdentifier, maxItems=None): 877 @@ -449,11 +728,11 @@ 878 @param maxItems: Optional limit on the number of retrieved items. 879 @type maxItems: C{int} 880 """ 881 - request = _PubSubRequest(self.xmlstream, 'items', method='get') 882 - if nodeIdentifier: 883 - request.command['node'] = nodeIdentifier 884 + request = PubSubRequest('items') 885 + request.recipient = service 886 + request.nodeIdentifier = nodeIdentifier 887 if maxItems: 888 - request.command["max_items"] = str(int(maxItems)) 889 + request.maxItems = str(int(maxItems)) 890 891 def cb(iq): 892 items = [] 893 @@ -462,7 +741,9 @@ 894 items.append(element) 895 return items 896 897 - return request.send(service).addCallback(cb) 898 + d = request.send(self.xmlstream) 899 + d.addCallback(cb) 900 + return d 901 902 903 904 @@ -497,27 +778,7 @@ 565 905 implements(IPubSubService) 566 906 … … 591 931 592 932 593 @@ -530,10 + 691,7 @@933 @@ -530,10 +791,7 @@ 594 934 595 935 … … 603 943 604 944 def getDiscoInfo(self, requestor, target, nodeIdentifier): 605 @@ -585,92 + 743,17 @@945 @@ -585,92 +843,17 @@ 606 946 return d 607 947 … … 612 952 + def _onPubSubRequest(self, iq): 613 953 + request = PubSubRequest.fromElement(iq) 614 + handler = getattr(self, '_on_%s' % (request.verb))954 + handler = getattr(self, '_on_%s' % request.verb) 615 955 + return handler(request) 616 956 … … 703 1043 def toResponse(result): 704 1044 response = domish.Element((NS_PUBSUB, "pubsub")) 705 @@ -681,28 + 764,24 @@1045 @@ -681,28 +864,24 @@ 706 1046 subscription["subscription"] = result.state 707 1047 return response … … 738 1078 def toResponse(result): 739 1079 response = domish.Element((NS_PUBSUB, 'pubsub')) 740 @@ -714,13 + 793,12 @@1080 @@ -714,13 +893,12 @@ 741 1081 item['subscription'] = subscription.state 742 1082 return response … … 754 1094 def toResponse(result): 755 1095 response = domish.Element((NS_PUBSUB, 'pubsub')) 756 @@ -733,17 + 811,15 @@1096 @@ -733,17 +911,15 @@ 757 1097 758 1098 return response … … 775 1115 create = response.addElement('create') 776 1116 create['node'] = result 777 @@ -751,7 + 827,7 @@1117 @@ -751,7 +927,7 @@ 778 1118 else: 779 1119 return None … … 784 1124 return d 785 1125 786 @@ -771,6 + 847,7 @@1126 @@ -771,6 +947,7 @@ 787 1127 fields.append(data_form.Field.fromDict(option)) 788 1128 return fields … … 792 1132 options = self.getConfigurationOptions() 793 1133 fields = self._makeFields(options, values) 794 @@ -779,6 +856,7 @@ 795 fields=fields) 1134 @@ -780,6 +957,7 @@ 796 1135 797 1136 return form 798 + 799 1137 1138 + 800 1139 def _checkConfiguration(self, values): 801 1140 options = self.getConfigurationOptions() 802 @@ -805,8 +883,7 @@ 1141 processedValues = {} 1142 @@ -805,8 +983,7 @@ 803 1143 return processedValues 804 1144 … … 810 1150 def toResponse(options): 811 1151 response = domish.Element((NS_PUBSUB_OWNER, "pubsub")) 812 @@ -814,127 + 891,82 @@1152 @@ -814,127 +991,82 @@ 813 1153 default.addChild(self._formFromConfiguration(options).toElement()) 814 1154 return response … … 965 1305 966 1306 # public methods 967 @@ -990,27 +1 022,27 @@1307 @@ -990,27 +1122,27 @@ 968 1308 return [] 969 1309 … … 999 1339 1000 1340 1001 @@ -1018,30 +1 050,29 @@1341 @@ -1018,30 +1150,29 @@ 1002 1342 return {} 1003 1343 … … 1037 1377 + def delete(self, request): 1038 1378 raise Unsupported('delete-nodes') 1039 diff -r fafe0148a94cwokkel/test/test_pubsub.py1040 --- a/wokkel/test/test_pubsub.py Wed Feb 25 09:21:332009 +01001041 +++ b/wokkel/test/test_pubsub.py Thu Feb 26 09:29:592009 +01001379 diff -r 884ac8d88411 wokkel/test/test_pubsub.py 1380 --- a/wokkel/test/test_pubsub.py Thu Mar 05 16:29:12 2009 +0100 1381 +++ b/wokkel/test/test_pubsub.py Wed Mar 18 09:26:20 2009 +0100 1042 1382 @@ -507,6 +507,29 @@ 1043 1383 verify.verifyObject(iwokkel.IPubSubService, self.service) … … 1070 1410 """ 1071 1411 Test getDiscoInfo calls getNodeInfo and returns some minimal info. 1072 @@ -561,2 4 +584,178@@1412 @@ -561,20 +584,149 @@ 1073 1413 </iq> 1074 1414 """ … … 1089 1429 + verify.verifyObject(iwokkel.IPubSubService, self.service) 1090 1430 return self.handleRequest(xml) 1091 + 1092 + 1431 1432 1093 1433 + def test_onPublishItems(self): 1094 1434 + """ … … 1217 1557 + d.addCallback(cb) 1218 1558 + return d 1219 1220 1559 + 1560 + 1221 1561 def test_onOptionsGet(self): 1222 1562 """ … … 1226 1566 1227 1567 xml = """ 1228 <iq type='get' to='pubsub.example.org' 1568 @@ -597,6 +749,31 @@ 1569 return d 1570 1571 1572 + def test_onOptionsSet(self): 1573 + """ 1574 + Setting subscription options is not supported. 1575 + """ 1576 + 1577 + xml = """ 1578 + <iq type='set' to='pubsub.example.org' 1229 1579 + from='user@example.org'> 1230 1580 + <pubsub xmlns='http://jabber.org/protocol/pubsub'> … … 1245 1595 + 1246 1596 + 1247 + def test_onOptionsSet(self): 1248 + """ 1249 + Setting subscription options is not supported. 1250 + """ 1251 + 1252 + xml = """ 1253 + <iq type='set' to='pubsub.example.org' 1254 from='user@example.org'> 1255 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1256 <options/> 1597 def test_onSubscriptions(self): 1598 """ 1599 A subscriptions request should result in 1257 1600 @@ -627,14 +804,149 @@ 1258 1601 self.assertEqual('subscribed', subscription['subscription']) … … 1423 1766 1424 1767 def cb(element): 1425 @@ -682,6 +994,95 @@ 1426 self.service.getDefaultConfiguration = getDefaultConfiguration 1427 verify.verifyObject(iwokkel.IPubSubService, self.service) 1428 d = self.handleRequest(xml) 1429 + d.addCallback(cb) 1430 + return d 1431 + 1432 + 1768 @@ -686,6 +998,95 @@ 1769 return d 1770 1771 1433 1772 + def test_onDefaultCollection(self): 1434 1773 + """ … … 1516 1855 + d = self.handleRequest(xml) 1517 1856 + self.assertFailure(d, error.StanzaError) 1518 d.addCallback(cb) 1519 return d 1520 1857 + d.addCallback(cb) 1858 + return d 1859 + 1860 + 1861 def test_onConfigureGet(self): 1862 """ 1863 On a node configuration get request L{PubSubService.getConfiguration} 1521 1864 @@ -714,14 +1115,15 @@ 1522 1865 "label": "Owner of the node"} … … 1589 1932 1590 1933 1591 @@ -862,1 2 +1270,45@@1934 @@ -862,14 +1270,47 @@ 1592 1935 "label": "Deliver payloads with event notifications"} 1593 1936 } … … 1603 1946 + verify.verifyObject(iwokkel.IPubSubService, self.service) 1604 1947 return self.handleRequest(xml) 1605 + 1606 + 1948 1949 1607 1950 + def test_onConfigureSetBadFormType(self): 1608 1951 + """ … … 1634 1977 + d.addCallback(cb) 1635 1978 + return d 1636 1637 1979 + 1980 + 1638 1981 def test_onItems(self): 1982 """ 1983 On a items request, return all items for the given node. 1639 1984 @@ -883,12 +1324,12 @@ 1640 1985 </iq> -
series
r3 r4 3 3 component_multiple.patch 4 4 pubsub_client_sender.patch 5 pubsub_resource.patch 5 6 compat-pre-twisted-8.0.0.patch 6 7 release-0.5.patch
Note: See TracChangeset
for help on using the changeset viewer.