Changeset 57:bcc9bc7a0929
- Timestamp:
- Apr 22, 2009, 5:02:02 PM (12 years ago)
- Branch:
- default
- Convert:
- svn:b33ecbfc-034c-dc11-8662-000475d9059e/trunk@169
- Location:
- wokkel
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
wokkel/generic.py
r55 r57 11 11 12 12 from twisted.internet import defer, protocol 13 from twisted.words.protocols.jabber import error, xmlstream13 from twisted.words.protocols.jabber import error, jid, xmlstream 14 14 from twisted.words.protocols.jabber.xmlstream import toResponse 15 15 from twisted.words.xish import domish, utility … … 163 163 164 164 165 166 class Stanza(object): 167 """ 168 Abstract representation of a stanza. 169 170 @ivar sender: The sending entity. 171 @type sender: L{jid.JID} 172 @ivar recipient: The receiving entity. 173 @type recipient: L{jid.JID} 174 """ 175 176 sender = None 177 recipient = None 178 stanzaType = None 179 180 @classmethod 181 def fromElement(Class, element): 182 stanza = Class() 183 stanza.parseElement(element) 184 return stanza 185 186 187 def parseElement(self, element): 188 self.sender = jid.internJID(element['from']) 189 if element.hasAttribute('from'): 190 self.sender = jid.internJID(element['from']) 191 if element.hasAttribute('to'): 192 self.recipient = jid.internJID(element['to']) 193 self.stanzaType = element.getAttribute('type') 194 195 165 196 class DeferredXmlStreamFactory(BootstrapMixin, protocol.ClientFactory): 166 197 protocol = xmlstream.XmlStream -
wokkel/pubsub.py
r52 r57 17 17 from twisted.words.xish import domish 18 18 19 from wokkel import disco, data_form, shim19 from wokkel import disco, data_form, generic, shim 20 20 from wokkel.subprotocols import IQHandlerMixin, XMPPHandler 21 21 from wokkel.iwokkel import IPubSubClient, IPubSubService … … 32 32 NS_PUBSUB_NODE_CONFIG = NS_PUBSUB + "#node_config" 33 33 NS_PUBSUB_META_DATA = NS_PUBSUB + "#meta-data" 34 35 # In publish-subscribe namespace XPath query selector. 36 IN_NS_PUBSUB = '[@xmlns="' + NS_PUBSUB + '"]' 37 IN_NS_PUBSUB_OWNER = '[@xmlns="' + NS_PUBSUB_OWNER + '"]' 38 39 # Publish-subscribe XPath queries 40 PUBSUB_ELEMENT = '/pubsub' + IN_NS_PUBSUB 41 PUBSUB_OWNER_ELEMENT = '/pubsub' + IN_NS_PUBSUB_OWNER 42 PUBSUB_GET = IQ_GET + PUBSUB_ELEMENT 43 PUBSUB_SET = IQ_SET + PUBSUB_ELEMENT 44 PUBSUB_OWNER_GET = IQ_GET + PUBSUB_OWNER_ELEMENT 45 PUBSUB_OWNER_SET = IQ_SET + PUBSUB_OWNER_ELEMENT 46 47 # Publish-subscribe command XPath queries 48 PUBSUB_PUBLISH = PUBSUB_SET + '/publish' + IN_NS_PUBSUB 49 PUBSUB_CREATE = PUBSUB_SET + '/create' + IN_NS_PUBSUB 50 PUBSUB_SUBSCRIBE = PUBSUB_SET + '/subscribe' + IN_NS_PUBSUB 51 PUBSUB_UNSUBSCRIBE = PUBSUB_SET + '/unsubscribe' + IN_NS_PUBSUB 52 PUBSUB_OPTIONS_GET = PUBSUB_GET + '/options' + IN_NS_PUBSUB 53 PUBSUB_OPTIONS_SET = PUBSUB_SET + '/options' + IN_NS_PUBSUB 54 PUBSUB_DEFAULT = PUBSUB_OWNER_GET + '/default' + IN_NS_PUBSUB_OWNER 55 PUBSUB_CONFIGURE_GET = PUBSUB_OWNER_GET + '/configure' + IN_NS_PUBSUB_OWNER 56 PUBSUB_CONFIGURE_SET = PUBSUB_OWNER_SET + '/configure' + IN_NS_PUBSUB_OWNER 57 PUBSUB_SUBSCRIPTIONS = PUBSUB_GET + '/subscriptions' + IN_NS_PUBSUB 58 PUBSUB_AFFILIATIONS = PUBSUB_GET + '/affiliations' + IN_NS_PUBSUB 59 PUBSUB_AFFILIATIONS_GET = PUBSUB_OWNER_GET + '/affiliations' + \ 60 IN_NS_PUBSUB_OWNER 61 PUBSUB_AFFILIATIONS_SET = PUBSUB_OWNER_SET + '/affiliations' + \ 62 IN_NS_PUBSUB_OWNER 63 PUBSUB_SUBSCRIPTIONS_GET = PUBSUB_OWNER_GET + '/subscriptions' + \ 64 IN_NS_PUBSUB_OWNER 65 PUBSUB_SUBSCRIPTIONS_SET = PUBSUB_OWNER_SET + '/subscriptions' + \ 66 IN_NS_PUBSUB_OWNER 67 PUBSUB_ITEMS = PUBSUB_GET + '/items' + IN_NS_PUBSUB 68 PUBSUB_RETRACT = PUBSUB_SET + '/retract' + IN_NS_PUBSUB 69 PUBSUB_PURGE = PUBSUB_OWNER_SET + '/purge' + IN_NS_PUBSUB_OWNER 70 PUBSUB_DELETE = PUBSUB_OWNER_SET + '/delete' + IN_NS_PUBSUB_OWNER 34 NS_PUBSUB_SUBSCRIBE_OPTIONS = NS_PUBSUB + "#subscribe_options" 35 36 # XPath to match pubsub requests 37 PUBSUB_REQUEST = '/iq[@type="get" or @type="set"]/' + \ 38 'pubsub[@xmlns="' + NS_PUBSUB + '" or ' + \ 39 '@xmlns="' + NS_PUBSUB_OWNER + '"]' 71 40 72 41 class SubscriptionPending(Exception): … … 99 68 100 69 101 class BadRequest( PubSubError):70 class BadRequest(error.StanzaError): 102 71 """ 103 72 Bad request stanza error. 104 73 """ 105 74 def __init__(self, pubsubCondition=None, text=None): 106 PubSubError.__init__(self, 'bad-request', pubsubCondition, text) 75 if pubsubCondition: 76 appCondition = domish.Element((NS_PUBSUB_ERRORS, pubsubCondition)) 77 else: 78 appCondition = None 79 error.StanzaError.__init__(self, 'bad-request', 80 text=text, 81 appCondition=appCondition) 107 82 108 83 … … 168 143 169 144 170 class _PubSubRequest(xmlstream.IQ): 171 """ 172 Publish subscribe request. 173 174 @ivar verb: Request verb 175 @type verb: C{str} 176 @ivar namespace: Request namespace. 177 @type namespace: C{str} 178 @ivar method: Type attribute of the IQ request. Either C{'set'} or C{'get'} 179 @type method: C{str} 180 @ivar command: Command element of the request. This is the direct child of 181 the C{pubsub} element in the C{namespace} with the name 182 C{verb}. 183 """ 184 185 def __init__(self, xs, verb, namespace=NS_PUBSUB, method='set'): 186 xmlstream.IQ.__init__(self, xs, method) 187 self.addElement((namespace, 'pubsub')) 188 189 self.command = self.pubsub.addElement(verb) 190 191 192 def send(self, to): 193 """ 194 Send out request. 195 196 Extends L{xmlstream.IQ.send} by requiring the C{to} parameter to be 197 a L{JID} instance. 198 199 @param to: Entity to send the request to. 200 @type to: L{JID} 201 """ 202 destination = to.full() 203 return xmlstream.IQ.send(self, destination) 145 class PubSubRequest(generic.Stanza): 146 """ 147 A publish-subscribe request. 148 149 The set of instance variables used depends on the type of request. If 150 a variable is not applicable or not passed in the request, its value is 151 C{None}. 152 153 @ivar verb: The type of publish-subscribe request. See L{_requestVerbMap}. 154 @type verb: C{str}. 155 156 @ivar affiliations: Affiliations to be modified. 157 @type affiliations: C{set} 158 @ivar items: The items to be published, as L{domish.Element}s. 159 @type items: C{list} 160 @ivar itemIdentifiers: Identifiers of the items to be retrieved or 161 retracted. 162 @type itemIdentifiers: C{set} 163 @ivar maxItems: Maximum number of items to retrieve. 164 @type maxItems: C{int}. 165 @ivar nodeIdentifier: Identifier of the node the request is about. 166 @type nodeIdentifier: C{unicode} 167 @ivar nodeType: The type of node that should be created, or for which the 168 configuration is retrieved. C{'leaf'} or C{'collection'}. 169 @type nodeType: C{str} 170 @ivar options: Configurations options for nodes, subscriptions and publish 171 requests. 172 @type options: L{data_form.Form} 173 @ivar subscriber: The subscribing entity. 174 @type subscriber: L{JID} 175 @ivar subscriptionIdentifier: Identifier for a specific subscription. 176 @type subscriptionIdentifier: C{unicode} 177 @ivar subscriptions: Subscriptions to be modified, as a set of 178 L{Subscription}. 179 @type subscriptions: C{set} 180 """ 181 182 verb = None 183 184 affiliations = None 185 items = None 186 itemIdentifiers = None 187 maxItems = None 188 nodeIdentifier = None 189 nodeType = None 190 options = None 191 subscriber = None 192 subscriptionIdentifier = None 193 subscriptions = None 194 195 # Map request iq type and subelement name to request verb 196 _requestVerbMap = { 197 ('set', NS_PUBSUB, 'publish'): 'publish', 198 ('set', NS_PUBSUB, 'subscribe'): 'subscribe', 199 ('set', NS_PUBSUB, 'unsubscribe'): 'unsubscribe', 200 ('get', NS_PUBSUB, 'options'): 'optionsGet', 201 ('set', NS_PUBSUB, 'options'): 'optionsSet', 202 ('get', NS_PUBSUB, 'subscriptions'): 'subscriptions', 203 ('get', NS_PUBSUB, 'affiliations'): 'affiliations', 204 ('set', NS_PUBSUB, 'create'): 'create', 205 ('get', NS_PUBSUB_OWNER, 'default'): 'default', 206 ('get', NS_PUBSUB_OWNER, 'configure'): 'configureGet', 207 ('set', NS_PUBSUB_OWNER, 'configure'): 'configureSet', 208 ('get', NS_PUBSUB, 'items'): 'items', 209 ('set', NS_PUBSUB, 'retract'): 'retract', 210 ('set', NS_PUBSUB_OWNER, 'purge'): 'purge', 211 ('set', NS_PUBSUB_OWNER, 'delete'): 'delete', 212 ('get', NS_PUBSUB_OWNER, 'affiliations'): 'affiliationsGet', 213 ('set', NS_PUBSUB_OWNER, 'affiliations'): 'affiliationsSet', 214 ('get', NS_PUBSUB_OWNER, 'subscriptions'): 'subscriptionsGet', 215 ('set', NS_PUBSUB_OWNER, 'subscriptions'): 'subscriptionsSet', 216 } 217 218 # Map request verb to request iq type and subelement name 219 _verbRequestMap = dict(((v, k) for k, v in _requestVerbMap.iteritems())) 220 221 # Map request verb to parameter handler names 222 _parameters = { 223 'publish': ['node', 'items'], 224 'subscribe': ['nodeOrEmpty', 'jid'], 225 'unsubscribe': ['nodeOrEmpty', 'jid'], 226 'optionsGet': ['nodeOrEmpty', 'jid'], 227 'optionsSet': ['nodeOrEmpty', 'jid', 'options'], 228 'subscriptions': [], 229 'affiliations': [], 230 'create': ['nodeOrNone'], 231 'default': ['default'], 232 'configureGet': ['nodeOrEmpty'], 233 'configureSet': ['nodeOrEmpty', 'configure'], 234 'items': ['node', 'maxItems', 'itemIdentifiers'], 235 'retract': ['node', 'itemIdentifiers'], 236 'purge': ['node'], 237 'delete': ['node'], 238 'affiliationsGet': [], 239 'affiliationsSet': [], 240 'subscriptionsGet': [], 241 'subscriptionsSet': [], 242 } 243 244 def __init__(self, verb=None): 245 self.verb = verb 246 247 248 @staticmethod 249 def _findForm(element, formNamespace): 250 """ 251 Find a Data Form. 252 253 Look for an element that represents a Data Form with the specified 254 form namespace as a child element of the given element. 255 """ 256 if not element: 257 return None 258 259 form = None 260 for child in element.elements(): 261 try: 262 form = data_form.Form.fromElement(child) 263 except data_form.Error: 264 continue 265 266 if form.formNamespace != NS_PUBSUB_NODE_CONFIG: 267 continue 268 269 return form 270 271 272 def _parse_node(self, verbElement): 273 """ 274 Parse the required node identifier out of the verbElement. 275 """ 276 try: 277 self.nodeIdentifier = verbElement["node"] 278 except KeyError: 279 raise BadRequest('nodeid-required') 280 281 282 def _render_node(self, verbElement): 283 """ 284 Render the required node identifier on the verbElement. 285 """ 286 if not self.nodeIdentifier: 287 raise Exception("Node identifier is required") 288 289 verbElement['node'] = self.nodeIdentifier 290 291 292 def _parse_nodeOrEmpty(self, verbElement): 293 """ 294 Parse the node identifier out of the verbElement. May be empty. 295 """ 296 self.nodeIdentifier = verbElement.getAttribute("node", '') 297 298 299 def _render_nodeOrEmpty(self, verbElement): 300 """ 301 Render the node identifier on the verbElement. May be empty. 302 """ 303 if self.nodeIdentifier: 304 verbElement['node'] = self.nodeIdentifier 305 306 307 def _parse_nodeOrNone(self, verbElement): 308 """ 309 Parse the optional node identifier out of the verbElement. 310 """ 311 self.nodeIdentifier = verbElement.getAttribute("node") 312 313 314 def _render_nodeOrNone(self, verbElement): 315 """ 316 Render the optional node identifier on the verbElement. 317 """ 318 if self.nodeIdentifier: 319 verbElement['node'] = self.nodeIdentifier 320 321 322 def _parse_items(self, verbElement): 323 """ 324 Parse items out of the verbElement for publish requests. 325 """ 326 self.items = [] 327 for element in verbElement.elements(): 328 if element.uri == NS_PUBSUB and element.name == 'item': 329 self.items.append(element) 330 331 332 def _render_items(self, verbElement): 333 """ 334 Render items into the verbElement for publish requests. 335 """ 336 if self.items: 337 for item in self.items: 338 verbElement.addChild(item) 339 340 341 def _parse_jid(self, verbElement): 342 """ 343 Parse subscriber out of the verbElement for un-/subscribe requests. 344 """ 345 try: 346 self.subscriber = jid.internJID(verbElement["jid"]) 347 except KeyError: 348 raise BadRequest('jid-required') 349 350 351 def _render_jid(self, verbElement): 352 """ 353 Render subscriber into the verbElement for un-/subscribe requests. 354 """ 355 verbElement['jid'] = self.subscriber.full() 356 357 358 def _parse_default(self, verbElement): 359 """ 360 Parse node type out of a request for the default node configuration. 361 """ 362 form = PubSubRequest._findForm(verbElement, NS_PUBSUB_NODE_CONFIG) 363 if form and form.formType == 'submit': 364 values = form.getValues() 365 self.nodeType = values.get('pubsub#node_type', 'leaf') 366 else: 367 self.nodeType = 'leaf' 368 369 370 def _parse_configure(self, verbElement): 371 """ 372 Parse options out of a request for setting the node configuration. 373 """ 374 form = PubSubRequest._findForm(verbElement, NS_PUBSUB_NODE_CONFIG) 375 if form: 376 if form.formType == 'submit': 377 self.options = form.getValues() 378 elif form.formType == 'cancel': 379 self.options = {} 380 else: 381 raise BadRequest(text="Unexpected form type %r" % form.formType) 382 else: 383 raise BadRequest(text="Missing configuration form") 384 385 386 387 def _parse_itemIdentifiers(self, verbElement): 388 """ 389 Parse item identifiers out of items and retract requests. 390 """ 391 self.itemIdentifiers = [] 392 for element in verbElement.elements(): 393 if element.uri == NS_PUBSUB and element.name == 'item': 394 try: 395 self.itemIdentifiers.append(element["id"]) 396 except KeyError: 397 raise BadRequest() 398 399 400 def _render_itemIdentifiers(self, verbElement): 401 """ 402 Render item identifiers into items and retract requests. 403 """ 404 if self.itemIdentifiers: 405 for itemIdentifier in self.itemIdentifiers: 406 item = verbElement.addElement('item') 407 item['id'] = itemIdentifier 408 409 410 def _parse_maxItems(self, verbElement): 411 """ 412 Parse maximum items out of an items request. 413 """ 414 value = verbElement.getAttribute('max_items') 415 416 if value: 417 try: 418 self.maxItems = int(value) 419 except ValueError: 420 raise BadRequest(text="Field max_items requires a positive " + 421 "integer value") 422 423 424 def _render_maxItems(self, verbElement): 425 """ 426 Parse maximum items into an items request. 427 """ 428 if self.maxItems: 429 verbElement['max_items'] = unicode(self.maxItems) 430 431 432 def _parse_options(self, verbElement): 433 form = PubSubRequest._findForm(verbElement, NS_PUBSUB_SUBSCRIBE_OPTIONS) 434 if form: 435 if form.formType == 'submit': 436 self.options = form.getValues() 437 elif form.formType == 'cancel': 438 self.options = {} 439 else: 440 raise BadRequest(text="Unexpected form type %r" % form.formType) 441 else: 442 raise BadRequest(text="Missing options form") 443 444 def parseElement(self, element): 445 """ 446 Parse the publish-subscribe verb and parameters out of a request. 447 """ 448 generic.Stanza.parseElement(self, element) 449 450 for child in element.pubsub.elements(): 451 key = (self.stanzaType, child.uri, child.name) 452 try: 453 verb = self._requestVerbMap[key] 454 except KeyError: 455 continue 456 else: 457 self.verb = verb 458 break 459 460 if not self.verb: 461 raise NotImplementedError() 462 463 for parameter in self._parameters[verb]: 464 getattr(self, '_parse_%s' % parameter)(child) 465 466 467 def send(self, xs): 468 """ 469 Send this request to its recipient. 470 471 This renders all of the relevant parameters for this specific 472 requests into an L{xmlstream.IQ}, and invoke its C{send} method. 473 This returns a deferred that fires upon reception of a response. See 474 L{xmlstream.IQ} for details. 475 476 @param xs: The XML stream to send the request on. 477 @type xs: L{xmlstream.XmlStream} 478 @rtype: L{defer.Deferred}. 479 """ 480 481 try: 482 (self.stanzaType, 483 childURI, 484 childName) = self._verbRequestMap[self.verb] 485 except KeyError: 486 raise NotImplementedError() 487 488 iq = xmlstream.IQ(xs, self.stanzaType) 489 iq.addElement((childURI, 'pubsub')) 490 verbElement = iq.pubsub.addElement(childName) 491 492 if self.sender: 493 iq['from'] = self.sender.full() 494 if self.recipient: 495 iq['to'] = self.recipient.full() 496 497 for parameter in self._parameters[self.verb]: 498 getattr(self, '_render_%s' % parameter)(verbElement) 499 500 return iq.send() 204 501 205 502 … … 337 634 @type nodeIdentifier: C{unicode} 338 635 """ 339 340 341 request = _PubSubRequest(self.xmlstream, 'create') 342 if nodeIdentifier: 343 request.command['node'] = nodeIdentifier 636 request = PubSubRequest('create') 637 request.recipient = service 638 request.nodeIdentifier = nodeIdentifier 344 639 345 640 def cb(iq): … … 351 646 return new_node 352 647 353 return request.send(service).addCallback(cb) 648 d = request.send(self.xmlstream) 649 d.addCallback(cb) 650 return d 354 651 355 652 … … 363 660 @type nodeIdentifier: C{unicode} 364 661 """ 365 request = _PubSubRequest(self.xmlstream, 'delete', NS_PUBSUB_OWNER) 366 request.command['node'] = nodeIdentifier 367 return request.send(service) 662 request = PubSubRequest('delete') 663 request.recipient = service 664 request.nodeIdentifier = nodeIdentifier 665 return request.send(self.xmlstream) 368 666 369 667 … … 380 678 @type subscriber: L{JID} 381 679 """ 382 request = _PubSubRequest(self.xmlstream,'subscribe')383 if nodeIdentifier:384 request.command['node']= nodeIdentifier385 request. command['jid'] = subscriber.full()680 request = PubSubRequest('subscribe') 681 request.recipient = service 682 request.nodeIdentifier = nodeIdentifier 683 request.subscriber = subscriber 386 684 387 685 def cb(iq): … … 398 696 return None 399 697 400 return request.send(service).addCallback(cb) 698 d = request.send(self.xmlstream) 699 d.addCallback(cb) 700 return d 401 701 402 702 … … 412 712 @type subscriber: L{JID} 413 713 """ 414 request = _PubSubRequest(self.xmlstream,'unsubscribe')415 if nodeIdentifier:416 request.command['node']= nodeIdentifier417 request. command['jid'] = subscriber.full()418 return request.send(se rvice)714 request = PubSubRequest('unsubscribe') 715 request.recipient = service 716 request.nodeIdentifier = nodeIdentifier 717 request.subscriber = subscriber 718 return request.send(self.xmlstream) 419 719 420 720 … … 430 730 @type items: C{list} 431 731 """ 432 request = _PubSubRequest(self.xmlstream, 'publish') 433 request.command['node'] = nodeIdentifier 434 if items: 435 for item in items: 436 request.command.addChild(item) 437 438 return request.send(service) 732 request = PubSubRequest('publish') 733 request.recipient = service 734 request.nodeIdentifier = nodeIdentifier 735 request.items = items 736 return request.send(self.xmlstream) 439 737 440 738 … … 450 748 @type maxItems: C{int} 451 749 """ 452 request = _PubSubRequest(self.xmlstream, 'items', method='get')453 if nodeIdentifier:454 request.command['node']= nodeIdentifier750 request = PubSubRequest('items') 751 request.recipient = service 752 request.nodeIdentifier = nodeIdentifier 455 753 if maxItems: 456 request. command["max_items"]= str(int(maxItems))754 request.maxItems = str(int(maxItems)) 457 755 458 756 def cb(iq): … … 463 761 return items 464 762 465 return request.send(service).addCallback(cb) 763 d = request.send(self.xmlstream) 764 d.addCallback(cb) 765 return d 466 766 467 767 … … 498 798 499 799 iqHandlers = { 500 PUBSUB_PUBLISH: '_onPublish', 501 PUBSUB_CREATE: '_onCreate', 502 PUBSUB_SUBSCRIBE: '_onSubscribe', 503 PUBSUB_OPTIONS_GET: '_onOptionsGet', 504 PUBSUB_OPTIONS_SET: '_onOptionsSet', 505 PUBSUB_AFFILIATIONS: '_onAffiliations', 506 PUBSUB_ITEMS: '_onItems', 507 PUBSUB_RETRACT: '_onRetract', 508 PUBSUB_SUBSCRIPTIONS: '_onSubscriptions', 509 PUBSUB_UNSUBSCRIBE: '_onUnsubscribe', 510 511 PUBSUB_AFFILIATIONS_GET: '_onAffiliationsGet', 512 PUBSUB_AFFILIATIONS_SET: '_onAffiliationsSet', 513 PUBSUB_CONFIGURE_GET: '_onConfigureGet', 514 PUBSUB_CONFIGURE_SET: '_onConfigureSet', 515 PUBSUB_DEFAULT: '_onDefault', 516 PUBSUB_PURGE: '_onPurge', 517 PUBSUB_DELETE: '_onDelete', 518 PUBSUB_SUBSCRIPTIONS_GET: '_onSubscriptionsGet', 519 PUBSUB_SUBSCRIPTIONS_SET: '_onSubscriptionsSet', 520 800 '/*': '_onPubSubRequest', 521 801 } 522 802 … … 531 811 532 812 def connectionMade(self): 533 self.xmlstream.addObserver(PUBSUB_GET, self.handleRequest) 534 self.xmlstream.addObserver(PUBSUB_SET, self.handleRequest) 535 self.xmlstream.addObserver(PUBSUB_OWNER_GET, self.handleRequest) 536 self.xmlstream.addObserver(PUBSUB_OWNER_SET, self.handleRequest) 813 self.xmlstream.addObserver(PUBSUB_REQUEST, self.handleRequest) 537 814 538 815 … … 586 863 587 864 588 def _findForm(self, element, formNamespace): 589 if not element: 590 return None 591 592 form = None 593 for child in element.elements(): 594 try: 595 form = data_form.Form.fromElement(child) 596 except data_form.Error: 597 continue 598 599 if form.formNamespace != NS_PUBSUB_NODE_CONFIG: 600 continue 601 602 return form 603 604 605 def _getParameter_node(self, commandElement): 606 try: 607 return commandElement["node"] 608 except KeyError: 609 raise BadRequest('nodeid-required') 610 611 612 def _getParameter_nodeOrEmpty(self, commandElement): 613 return commandElement.getAttribute("node", '') 614 615 616 def _getParameter_jid(self, commandElement): 617 try: 618 return jid.internJID(commandElement["jid"]) 619 except KeyError: 620 raise BadRequest('jid-required') 621 622 623 def _getParameter_max_items(self, commandElement): 624 value = commandElement.getAttribute('max_items') 625 626 if value: 627 try: 628 return int(value) 629 except ValueError: 630 raise BadRequest(text="Field max_items requires a positive " + 631 "integer value") 632 else: 633 return None 634 635 636 def _getParameters(self, iq, *names): 637 requestor = jid.internJID(iq["from"]).userhostJID() 638 service = jid.internJID(iq["to"]) 639 640 params = [requestor, service] 641 642 if names: 643 command = names[0] 644 commandElement = getattr(iq.pubsub, command) 645 if not commandElement: 646 raise Exception("Could not find command element %r" % command) 647 648 for name in names[1:]: 649 try: 650 getter = getattr(self, '_getParameter_' + name) 651 except KeyError: 652 raise Exception("No parameter getter for this name") 653 654 params.append(getter(commandElement)) 655 656 return params 657 658 659 def _onPublish(self, iq): 660 requestor, service, nodeIdentifier = self._getParameters( 661 iq, 'publish', 'node') 662 663 items = [] 664 for element in iq.pubsub.publish.elements(): 665 if element.uri == NS_PUBSUB and element.name == 'item': 666 items.append(element) 667 668 return self.publish(requestor, service, nodeIdentifier, items) 669 670 671 def _onSubscribe(self, iq): 672 requestor, service, nodeIdentifier, subscriber = self._getParameters( 673 iq, 'subscribe', 'nodeOrEmpty', 'jid') 865 def _onPubSubRequest(self, iq): 866 request = PubSubRequest.fromElement(iq) 867 handler = getattr(self, '_on_%s' % request.verb) 868 return handler(request) 869 870 871 def _on_publish(self, request): 872 return self.publish(request.sender, request.recipient, 873 request.nodeIdentifier, request.items) 874 875 876 def _on_subscribe(self, request): 674 877 675 878 def toResponse(result): … … 682 885 return response 683 886 684 d = self.subscribe(requestor, service, nodeIdentifier, subscriber) 887 d = self.subscribe(request.sender, request.recipient, 888 request.nodeIdentifier, request.subscriber) 685 889 d.addCallback(toResponse) 686 890 return d 687 891 688 892 689 def _onUnsubscribe(self, iq): 690 requestor, service, nodeIdentifier, subscriber = self._getParameters( 691 iq, 'unsubscribe', 'nodeOrEmpty', 'jid') 692 693 return self.unsubscribe(requestor, service, nodeIdentifier, subscriber) 694 695 696 def _onOptionsGet(self, iq): 893 def _on_unsubscribe(self, request): 894 return self.unsubscribe(request.sender, request.recipient, 895 request.nodeIdentifier, request.subscriber) 896 897 898 def _on_optionsGet(self, request): 697 899 raise Unsupported('subscription-options') 698 900 699 901 700 def _on OptionsSet(self, iq):902 def _on_optionsSet(self, request): 701 903 raise Unsupported('subscription-options') 702 904 703 905 704 def _onSubscriptions(self, iq): 705 requestor, service = self._getParameters(iq) 906 def _on_subscriptions(self, request): 706 907 707 908 def toResponse(result): … … 715 916 return response 716 917 717 d = self.subscriptions(request or, service)918 d = self.subscriptions(request.sender, request.recipient) 718 919 d.addCallback(toResponse) 719 920 return d 720 921 721 922 722 def _onAffiliations(self, iq): 723 requestor, service = self._getParameters(iq) 923 def _on_affiliations(self, request): 724 924 725 925 def toResponse(result): … … 734 934 return response 735 935 736 d = self.affiliations(request or, service)936 d = self.affiliations(request.sender, request.recipient) 737 937 d.addCallback(toResponse) 738 938 return d 739 939 740 940 741 def _onCreate(self, iq): 742 requestor, service = self._getParameters(iq) 743 nodeIdentifier = iq.pubsub.create.getAttribute("node") 941 def _on_create(self, request): 744 942 745 943 def toResponse(result): 746 if not nodeIdentifier ornodeIdentifier != result:944 if not request.nodeIdentifier or request.nodeIdentifier != result: 747 945 response = domish.Element((NS_PUBSUB, 'pubsub')) 748 946 create = response.addElement('create') … … 752 950 return None 753 951 754 d = self.create(requestor, service, nodeIdentifier) 952 d = self.create(request.sender, request.recipient, 953 request.nodeIdentifier) 755 954 d.addCallback(toResponse) 756 955 return d … … 772 971 return fields 773 972 973 774 974 def _formFromConfiguration(self, values): 775 975 options = self.getConfigurationOptions() … … 780 980 781 981 return form 982 782 983 783 984 def _checkConfiguration(self, values): … … 806 1007 807 1008 808 def _onDefault(self, iq): 809 requestor, service = self._getParameters(iq) 1009 def _on_default(self, request): 810 1010 811 1011 def toResponse(options): … … 815 1015 return response 816 1016 817 form = self._findForm(iq.pubsub.config, NS_PUBSUB_NODE_CONFIG) 818 values = form and form.formType == 'result' and form.getValues() or {} 819 nodeType = values.get('pubsub#node_type', 'leaf') 820 821 if nodeType not in ('leaf', 'collections'): 1017 if request.nodeType not in ('leaf', 'collection'): 822 1018 return defer.fail(error.StanzaError('not-acceptable')) 823 1019 824 d = self.getDefaultConfiguration(requestor, service, nodeType) 1020 d = self.getDefaultConfiguration(request.sender, request.recipient, 1021 request.nodeType) 825 1022 d.addCallback(toResponse) 826 1023 return d 827 1024 828 1025 829 def _onConfigureGet(self, iq): 830 requestor, service, nodeIdentifier = self._getParameters( 831 iq, 'configure', 'nodeOrEmpty') 832 1026 def _on_configureGet(self, request): 833 1027 def toResponse(options): 834 1028 response = domish.Element((NS_PUBSUB_OWNER, "pubsub")) 835 1029 configure = response.addElement("configure") 836 configure.addChild(self._formFromConfiguration(options).toElement()) 837 838 if nodeIdentifier: 839 configure["node"] = nodeIdentifier 1030 form = self._formFromConfiguration(options) 1031 configure.addChild(form.toElement()) 1032 1033 if request.nodeIdentifier: 1034 configure["node"] = request.nodeIdentifier 840 1035 841 1036 return response 842 1037 843 d = self.getConfiguration(requestor, service, nodeIdentifier) 1038 d = self.getConfiguration(request.sender, request.recipient, 1039 request.nodeIdentifier) 844 1040 d.addCallback(toResponse) 845 1041 return d 846 1042 847 1043 848 def _onConfigureSet(self, iq): 849 requestor, service, nodeIdentifier = self._getParameters( 850 iq, 'configure', 'nodeOrEmpty') 851 852 # Search configuration form with correct FORM_TYPE and process it 853 854 form = self._findForm(iq.pubsub.configure, NS_PUBSUB_NODE_CONFIG) 855 856 if form: 857 if form.formType == 'submit': 858 options = self._checkConfiguration(form.getValues()) 859 860 return self.setConfiguration(requestor, service, 861 nodeIdentifier, options) 862 elif form.formType == 'cancel': 863 return None 864 865 raise BadRequest() 866 867 868 def _onItems(self, iq): 869 requestor, service, nodeIdentifier, maxItems = self._getParameters( 870 iq, 'items', 'nodeOrEmpty', 'max_items') 871 872 itemIdentifiers = [] 873 for child in iq.pubsub.items.elements(): 874 if child.name == 'item' and child.uri == NS_PUBSUB: 875 try: 876 itemIdentifiers.append(child["id"]) 877 except KeyError: 878 raise BadRequest() 1044 def _on_configureSet(self, request): 1045 if request.options: 1046 request.options = self._checkConfiguration(request.options) 1047 return self.setConfiguration(request.sender, request.recipient, 1048 request.nodeIdentifier, 1049 request.options) 1050 else: 1051 return None 1052 1053 1054 1055 def _on_items(self, request): 879 1056 880 1057 def toResponse(result): 881 1058 response = domish.Element((NS_PUBSUB, 'pubsub')) 882 1059 items = response.addElement('items') 883 if nodeIdentifier: 884 items["node"] = nodeIdentifier 1060 items["node"] = request.nodeIdentifier 885 1061 886 1062 for item in result: … … 889 1065 return response 890 1066 891 d = self.items(requestor, service, nodeIdentifier, maxItems, 892 itemIdentifiers) 1067 d = self.items(request.sender, request.recipient, 1068 request.nodeIdentifier, request.maxItems, 1069 request.itemIdentifiers) 893 1070 d.addCallback(toResponse) 894 1071 return d 895 1072 896 1073 897 def _onRetract(self, iq): 898 requestor, service, nodeIdentifier = self._getParameters( 899 iq, 'retract', 'node') 900 901 itemIdentifiers = [] 902 for child in iq.pubsub.retract.elements(): 903 if child.uri == NS_PUBSUB and child.name == 'item': 904 try: 905 itemIdentifiers.append(child["id"]) 906 except KeyError: 907 raise BadRequest() 908 909 return self.retract(requestor, service, nodeIdentifier, 910 itemIdentifiers) 911 912 913 def _onPurge(self, iq): 914 requestor, service, nodeIdentifier = self._getParameters( 915 iq, 'purge', 'node') 916 return self.purge(requestor, service, nodeIdentifier) 917 918 919 def _onDelete(self, iq): 920 requestor, service, nodeIdentifier = self._getParameters( 921 iq, 'delete', 'node') 922 return self.delete(requestor, service, nodeIdentifier) 923 924 925 def _onAffiliationsGet(self, iq): 1074 def _on_retract(self, request): 1075 return self.retract(request.sender, request.recipient, 1076 request.nodeIdentifier, request.itemIdentifiers) 1077 1078 1079 def _on_purge(self, request): 1080 return self.purge(request.sender, request.recipient, 1081 request.nodeIdentifier) 1082 1083 1084 def _on_delete(self, request): 1085 return self.delete(request.sender, request.recipient, 1086 request.nodeIdentifier) 1087 1088 1089 def _on_affiliationsGet(self, iq): 926 1090 raise Unsupported('modify-affiliations') 927 1091 928 1092 929 def _on AffiliationsSet(self, iq):1093 def _on_affiliationsSet(self, iq): 930 1094 raise Unsupported('modify-affiliations') 931 1095 932 1096 933 def _on SubscriptionsGet(self, iq):1097 def _on_subscriptionsGet(self, iq): 934 1098 raise Unsupported('manage-subscriptions') 935 1099 936 1100 937 def _on SubscriptionsSet(self, iq):1101 def _on_subscriptionsSet(self, iq): 938 1102 raise Unsupported('manage-subscriptions') 939 1103 -
wokkel/test/test_pubsub.py
r56 r57 16 16 17 17 from wokkel import data_form, disco, iwokkel, pubsub, shim 18 from wokkel.generic import parseXml 18 19 from wokkel.test.helpers import TestableRequestHandlerMixin, XmlStreamStub 19 20 … … 488 489 489 490 491 class PubSubRequestTest(unittest.TestCase): 492 493 def test_fromElementPublish(self): 494 """ 495 Test parsing a publish request. 496 """ 497 498 xml = """ 499 <iq type='set' to='pubsub.example.org' 500 from='user@example.org'> 501 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 502 <publish node='test'/> 503 </pubsub> 504 </iq> 505 """ 506 507 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 508 self.assertEqual('publish', request.verb) 509 self.assertEqual(JID('user@example.org'), request.sender) 510 self.assertEqual(JID('pubsub.example.org'), request.recipient) 511 self.assertEqual('test', request.nodeIdentifier) 512 self.assertEqual([], request.items) 513 514 515 def test_fromElementPublishItems(self): 516 """ 517 Test parsing a publish request with items. 518 """ 519 520 xml = """ 521 <iq type='set' to='pubsub.example.org' 522 from='user@example.org'> 523 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 524 <publish node='test'> 525 <item id="item1"/> 526 <item id="item2"/> 527 </publish> 528 </pubsub> 529 </iq> 530 """ 531 532 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 533 self.assertEqual(2, len(request.items)) 534 self.assertEqual(u'item1', request.items[0]["id"]) 535 self.assertEqual(u'item2', request.items[1]["id"]) 536 537 538 def test_fromElementPublishNoNode(self): 539 """ 540 A publish request to the root node should raise an exception. 541 """ 542 xml = """ 543 <iq type='set' to='pubsub.example.org' 544 from='user@example.org'> 545 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 546 <publish/> 547 </pubsub> 548 </iq> 549 """ 550 551 err = self.assertRaises(error.StanzaError, 552 pubsub.PubSubRequest.fromElement, 553 parseXml(xml)) 554 self.assertEqual('bad-request', err.condition) 555 self.assertEqual(NS_PUBSUB_ERRORS, err.appCondition.uri) 556 self.assertEqual('nodeid-required', err.appCondition.name) 557 558 559 def test_fromElementSubscribe(self): 560 """ 561 Test parsing a subscription request. 562 """ 563 564 xml = """ 565 <iq type='set' to='pubsub.example.org' 566 from='user@example.org'> 567 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 568 <subscribe node='test' jid='user@example.org/Home'/> 569 </pubsub> 570 </iq> 571 """ 572 573 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 574 self.assertEqual('subscribe', request.verb) 575 self.assertEqual(JID('user@example.org'), request.sender) 576 self.assertEqual(JID('pubsub.example.org'), request.recipient) 577 self.assertEqual('test', request.nodeIdentifier) 578 self.assertEqual(JID('user@example.org/Home'), request.subscriber) 579 580 581 def test_fromElementSubscribeEmptyNode(self): 582 """ 583 Test parsing a subscription request to the root node. 584 """ 585 586 xml = """ 587 <iq type='set' to='pubsub.example.org' 588 from='user@example.org'> 589 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 590 <subscribe jid='user@example.org/Home'/> 591 </pubsub> 592 </iq> 593 """ 594 595 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 596 self.assertEqual('', request.nodeIdentifier) 597 598 599 def test_fromElementSubscribeNoJID(self): 600 """ 601 Subscribe requests without a JID should raise a bad-request exception. 602 """ 603 xml = """ 604 <iq type='set' to='pubsub.example.org' 605 from='user@example.org'> 606 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 607 <subscribe node='test'/> 608 </pubsub> 609 </iq> 610 """ 611 err = self.assertRaises(error.StanzaError, 612 pubsub.PubSubRequest.fromElement, 613 parseXml(xml)) 614 self.assertEqual('bad-request', err.condition) 615 self.assertEqual(NS_PUBSUB_ERRORS, err.appCondition.uri) 616 self.assertEqual('jid-required', err.appCondition.name) 617 618 def test_fromElementUnsubscribe(self): 619 """ 620 Test parsing an unsubscription request. 621 """ 622 623 xml = """ 624 <iq type='set' to='pubsub.example.org' 625 from='user@example.org'> 626 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 627 <unsubscribe node='test' jid='user@example.org/Home'/> 628 </pubsub> 629 </iq> 630 """ 631 632 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 633 self.assertEqual('unsubscribe', request.verb) 634 self.assertEqual(JID('user@example.org'), request.sender) 635 self.assertEqual(JID('pubsub.example.org'), request.recipient) 636 self.assertEqual('test', request.nodeIdentifier) 637 self.assertEqual(JID('user@example.org/Home'), request.subscriber) 638 639 640 def test_fromElementUnsubscribeNoJID(self): 641 """ 642 Unsubscribe requests without a JID should raise a bad-request exception. 643 """ 644 xml = """ 645 <iq type='set' to='pubsub.example.org' 646 from='user@example.org'> 647 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 648 <unsubscribe node='test'/> 649 </pubsub> 650 </iq> 651 """ 652 err = self.assertRaises(error.StanzaError, 653 pubsub.PubSubRequest.fromElement, 654 parseXml(xml)) 655 self.assertEqual('bad-request', err.condition) 656 self.assertEqual(NS_PUBSUB_ERRORS, err.appCondition.uri) 657 self.assertEqual('jid-required', err.appCondition.name) 658 659 660 def test_fromElementOptionsGet(self): 661 """ 662 Test parsing a request for getting subscription options. 663 """ 664 665 xml = """ 666 <iq type='get' to='pubsub.example.org' 667 from='user@example.org'> 668 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 669 <options node='test' jid='user@example.org/Home'/> 670 </pubsub> 671 </iq> 672 """ 673 674 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 675 self.assertEqual('optionsGet', request.verb) 676 677 678 def test_fromElementOptionsSet(self): 679 """ 680 Test parsing a request for setting subscription options. 681 """ 682 683 xml = """ 684 <iq type='set' to='pubsub.example.org' 685 from='user@example.org'> 686 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 687 <options node='test' jid='user@example.org/Home'> 688 <x xmlns='jabber:x:data' type='submit'> 689 <field var='FORM_TYPE' type='hidden'> 690 <value>http://jabber.org/protocol/pubsub#subscribe_options</value> 691 </field> 692 <field var='pubsub#deliver'><value>1</value></field> 693 </x> 694 </options> 695 </pubsub> 696 </iq> 697 """ 698 699 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 700 self.assertEqual('optionsSet', request.verb) 701 self.assertEqual(JID('user@example.org'), request.sender) 702 self.assertEqual(JID('pubsub.example.org'), request.recipient) 703 self.assertEqual('test', request.nodeIdentifier) 704 self.assertEqual(JID('user@example.org/Home'), request.subscriber) 705 self.assertEqual({'pubsub#deliver': '1'}, request.options) 706 707 708 def test_fromElementOptionsSetCancel(self): 709 """ 710 Test parsing a request for cancelling setting subscription options. 711 """ 712 713 xml = """ 714 <iq type='set' to='pubsub.example.org' 715 from='user@example.org'> 716 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 717 <options node='test' jid='user@example.org/Home'> 718 <x xmlns='jabber:x:data' type='cancel'/> 719 </options> 720 </pubsub> 721 </iq> 722 """ 723 724 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 725 self.assertEqual({}, request.options) 726 727 728 def test_fromElementOptionsSetBadFormType(self): 729 """ 730 On a options set request unknown fields should be ignored. 731 """ 732 733 xml = """ 734 <iq type='set' to='pubsub.example.org' 735 from='user@example.org'> 736 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 737 <options node='test' jid='user@example.org/Home'> 738 <x xmlns='jabber:x:data' type='result'> 739 <field var='FORM_TYPE' type='hidden'> 740 <value>http://jabber.org/protocol/pubsub#node_config</value> 741 </field> 742 <field var='pubsub#deliver'><value>1</value></field> 743 </x> 744 </options> 745 </pubsub> 746 </iq> 747 """ 748 749 err = self.assertRaises(error.StanzaError, 750 pubsub.PubSubRequest.fromElement, 751 parseXml(xml)) 752 self.assertEqual('bad-request', err.condition) 753 self.assertEqual(None, err.appCondition) 754 755 756 def test_fromElementOptionsSetNoForm(self): 757 """ 758 On a options set request a form is required. 759 """ 760 761 xml = """ 762 <iq type='set' to='pubsub.example.org' 763 from='user@example.org'> 764 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 765 <options node='test' jid='user@example.org/Home'/> 766 </pubsub> 767 </iq> 768 """ 769 err = self.assertRaises(error.StanzaError, 770 pubsub.PubSubRequest.fromElement, 771 parseXml(xml)) 772 self.assertEqual('bad-request', err.condition) 773 self.assertEqual(None, err.appCondition) 774 775 776 def test_fromElementSubscriptions(self): 777 """ 778 Test parsing a request for all subscriptions. 779 """ 780 781 xml = """ 782 <iq type='get' to='pubsub.example.org' 783 from='user@example.org'> 784 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 785 <subscriptions/> 786 </pubsub> 787 </iq> 788 """ 789 790 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 791 self.assertEqual('subscriptions', request.verb) 792 self.assertEqual(JID('user@example.org'), request.sender) 793 self.assertEqual(JID('pubsub.example.org'), request.recipient) 794 795 796 def test_fromElementAffiliations(self): 797 """ 798 Test parsing a request for all affiliations. 799 """ 800 801 xml = """ 802 <iq type='get' to='pubsub.example.org' 803 from='user@example.org'> 804 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 805 <affiliations/> 806 </pubsub> 807 </iq> 808 """ 809 810 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 811 self.assertEqual('affiliations', request.verb) 812 self.assertEqual(JID('user@example.org'), request.sender) 813 self.assertEqual(JID('pubsub.example.org'), request.recipient) 814 815 816 def test_fromElementCreate(self): 817 """ 818 Test parsing a request to create a node. 819 """ 820 821 xml = """ 822 <iq type='set' to='pubsub.example.org' 823 from='user@example.org'> 824 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 825 <create node='mynode'/> 826 </pubsub> 827 </iq> 828 """ 829 830 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 831 self.assertEqual('create', request.verb) 832 self.assertEqual(JID('user@example.org'), request.sender) 833 self.assertEqual(JID('pubsub.example.org'), request.recipient) 834 self.assertEqual('mynode', request.nodeIdentifier) 835 836 837 def test_fromElementCreateInstant(self): 838 """ 839 Test parsing a request to create an instant node. 840 """ 841 842 xml = """ 843 <iq type='set' to='pubsub.example.org' 844 from='user@example.org'> 845 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 846 <create/> 847 </pubsub> 848 </iq> 849 """ 850 851 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 852 self.assertIdentical(None, request.nodeIdentifier) 853 854 855 def test_fromElementDefault(self): 856 """ 857 Test parsing a request for the default node configuration. 858 """ 859 860 xml = """ 861 <iq type='get' to='pubsub.example.org' 862 from='user@example.org'> 863 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 864 <default/> 865 </pubsub> 866 </iq> 867 """ 868 869 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 870 self.assertEqual('default', request.verb) 871 self.assertEqual(JID('user@example.org'), request.sender) 872 self.assertEqual(JID('pubsub.example.org'), request.recipient) 873 self.assertEqual('leaf', request.nodeType) 874 875 876 def test_fromElementDefaultCollection(self): 877 """ 878 Parsing a request for the default configuration extracts the node type. 879 """ 880 881 xml = """ 882 <iq type='get' to='pubsub.example.org' 883 from='user@example.org'> 884 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 885 <default> 886 <x xmlns='jabber:x:data' type='submit'> 887 <field var='FORM_TYPE' type='hidden'> 888 <value>http://jabber.org/protocol/pubsub#node_config</value> 889 </field> 890 <field var='pubsub#node_type'> 891 <value>collection</value> 892 </field> 893 </x> 894 </default> 895 896 </pubsub> 897 </iq> 898 """ 899 900 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 901 self.assertEqual('collection', request.nodeType) 902 903 904 def test_fromElementConfigureGet(self): 905 """ 906 Test parsing a node configuration get request. 907 """ 908 909 xml = """ 910 <iq type='get' to='pubsub.example.org' 911 from='user@example.org'> 912 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 913 <configure node='test'/> 914 </pubsub> 915 </iq> 916 """ 917 918 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 919 self.assertEqual('configureGet', request.verb) 920 self.assertEqual(JID('user@example.org'), request.sender) 921 self.assertEqual(JID('pubsub.example.org'), request.recipient) 922 self.assertEqual('test', request.nodeIdentifier) 923 924 925 def test_fromElementConfigureSet(self): 926 """ 927 On a node configuration set request the Data Form is parsed. 928 """ 929 930 xml = """ 931 <iq type='set' to='pubsub.example.org' 932 from='user@example.org'> 933 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 934 <configure node='test'> 935 <x xmlns='jabber:x:data' type='submit'> 936 <field var='FORM_TYPE' type='hidden'> 937 <value>http://jabber.org/protocol/pubsub#node_config</value> 938 </field> 939 <field var='pubsub#deliver_payloads'><value>0</value></field> 940 <field var='pubsub#persist_items'><value>1</value></field> 941 </x> 942 </configure> 943 </pubsub> 944 </iq> 945 """ 946 947 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 948 self.assertEqual('configureSet', request.verb) 949 self.assertEqual(JID('user@example.org'), request.sender) 950 self.assertEqual(JID('pubsub.example.org'), request.recipient) 951 self.assertEqual('test', request.nodeIdentifier) 952 self.assertEqual({'pubsub#deliver_payloads': '0', 953 'pubsub#persist_items': '1'}, request.options) 954 955 956 def test_fromElementConfigureSetCancel(self): 957 """ 958 The node configuration is cancelled, so no options. 959 """ 960 961 xml = """ 962 <iq type='set' to='pubsub.example.org' 963 from='user@example.org'> 964 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 965 <configure node='test'> 966 <x xmlns='jabber:x:data' type='cancel'/> 967 </configure> 968 </pubsub> 969 </iq> 970 """ 971 972 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 973 self.assertEqual({}, request.options) 974 975 976 def test_fromElementConfigureSetBadFormType(self): 977 """ 978 On a node configuration set request unknown fields should be ignored. 979 """ 980 981 xml = """ 982 <iq type='set' to='pubsub.example.org' 983 from='user@example.org'> 984 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 985 <configure node='test'> 986 <x xmlns='jabber:x:data' type='result'> 987 <field var='FORM_TYPE' type='hidden'> 988 <value>http://jabber.org/protocol/pubsub#node_config</value> 989 </field> 990 <field var='pubsub#deliver_payloads'><value>0</value></field> 991 <field var='x-myfield'><value>1</value></field> 992 </x> 993 </configure> 994 </pubsub> 995 </iq> 996 """ 997 998 err = self.assertRaises(error.StanzaError, 999 pubsub.PubSubRequest.fromElement, 1000 parseXml(xml)) 1001 self.assertEqual('bad-request', err.condition) 1002 self.assertEqual(None, err.appCondition) 1003 1004 1005 def test_fromElementConfigureSetNoForm(self): 1006 """ 1007 On a node configuration set request a form is required. 1008 """ 1009 1010 xml = """ 1011 <iq type='set' to='pubsub.example.org' 1012 from='user@example.org'> 1013 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 1014 <configure node='test'/> 1015 </pubsub> 1016 </iq> 1017 """ 1018 err = self.assertRaises(error.StanzaError, 1019 pubsub.PubSubRequest.fromElement, 1020 parseXml(xml)) 1021 self.assertEqual('bad-request', err.condition) 1022 self.assertEqual(None, err.appCondition) 1023 1024 1025 def test_fromElementItems(self): 1026 """ 1027 Test parsing an items request. 1028 """ 1029 xml = """ 1030 <iq type='get' to='pubsub.example.org' 1031 from='user@example.org'> 1032 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1033 <items node='test'/> 1034 </pubsub> 1035 </iq> 1036 """ 1037 1038 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 1039 self.assertEqual('items', request.verb) 1040 self.assertEqual(JID('user@example.org'), request.sender) 1041 self.assertEqual(JID('pubsub.example.org'), request.recipient) 1042 self.assertEqual('test', request.nodeIdentifier) 1043 self.assertIdentical(None, request.maxItems) 1044 self.assertEqual([], request.itemIdentifiers) 1045 1046 1047 def test_fromElementRetract(self): 1048 """ 1049 Test parsing a retract request. 1050 """ 1051 1052 xml = """ 1053 <iq type='set' to='pubsub.example.org' 1054 from='user@example.org'> 1055 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1056 <retract node='test'> 1057 <item id='item1'/> 1058 <item id='item2'/> 1059 </retract> 1060 </pubsub> 1061 </iq> 1062 """ 1063 1064 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 1065 self.assertEqual('retract', request.verb) 1066 self.assertEqual(JID('user@example.org'), request.sender) 1067 self.assertEqual(JID('pubsub.example.org'), request.recipient) 1068 self.assertEqual('test', request.nodeIdentifier) 1069 self.assertEqual(['item1', 'item2'], request.itemIdentifiers) 1070 1071 1072 def test_fromElementPurge(self): 1073 """ 1074 Test parsing a purge request. 1075 """ 1076 1077 xml = """ 1078 <iq type='set' to='pubsub.example.org' 1079 from='user@example.org'> 1080 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 1081 <purge node='test'/> 1082 </pubsub> 1083 </iq> 1084 """ 1085 1086 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 1087 self.assertEqual('purge', request.verb) 1088 self.assertEqual(JID('user@example.org'), request.sender) 1089 self.assertEqual(JID('pubsub.example.org'), request.recipient) 1090 self.assertEqual('test', request.nodeIdentifier) 1091 1092 1093 def test_fromElementDelete(self): 1094 """ 1095 Test parsing a delete request. 1096 """ 1097 1098 xml = """ 1099 <iq type='set' to='pubsub.example.org' 1100 from='user@example.org'> 1101 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 1102 <delete node='test'/> 1103 </pubsub> 1104 </iq> 1105 """ 1106 1107 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 1108 self.assertEqual('delete', request.verb) 1109 self.assertEqual(JID('user@example.org'), request.sender) 1110 self.assertEqual(JID('pubsub.example.org'), request.recipient) 1111 self.assertEqual('test', request.nodeIdentifier) 1112 1113 1114 490 1115 class PubSubServiceTest(unittest.TestCase, TestableRequestHandlerMixin): 491 1116 """ … … 503 1128 """ 504 1129 verify.verifyObject(iwokkel.IPubSubService, self.service) 1130 1131 1132 def test_connectionMade(self): 1133 """ 1134 Verify setup of observers in L{pubsub.connectionMade}. 1135 """ 1136 requests = [] 1137 1138 def handleRequest(iq): 1139 requests.append(iq) 1140 1141 self.service.xmlstream = self.stub.xmlstream 1142 self.service.handleRequest = handleRequest 1143 self.service.connectionMade() 1144 1145 for namespace in (NS_PUBSUB, NS_PUBSUB_OWNER): 1146 for stanzaType in ('get', 'set'): 1147 iq = domish.Element((None, 'iq')) 1148 iq['type'] = stanzaType 1149 iq.addElement((namespace, 'pubsub')) 1150 self.stub.xmlstream.dispatch(iq) 1151 1152 self.assertEqual(4, len(requests)) 505 1153 506 1154 … … 570 1218 571 1219 572 def test_onPublishNoNode(self):573 """574 The root node is always a collection, publishing is a bad request.575 """576 xml = """577 <iq type='set' to='pubsub.example.org'578 from='user@example.org'>579 <pubsub xmlns='http://jabber.org/protocol/pubsub'>580 <publish/>581 </pubsub>582 </iq>583 """584 585 def cb(result):586 self.assertEquals('bad-request', result.condition)587 588 d = self.handleRequest(xml)589 self.assertFailure(d, error.StanzaError)590 d.addCallback(cb)591 return d592 593 594 1220 def test_onPublish(self): 595 1221 """ … … 608 1234 609 1235 def publish(requestor, service, nodeIdentifier, items): 610 self.assertEqual(JID('user@example.org'), requestor)611 self.assertEqual(JID('pubsub.example.org'), service)612 self.assertEqual('test', nodeIdentifier)613 self.assertEqual([], items)614 1236 return defer.succeed(None) 615 1237 616 1238 self.service.publish = publish 1239 verify.verifyObject(iwokkel.IPubSubService, self.service) 617 1240 return self.handleRequest(xml) 618 1241 619 1242 1243 def test_onSubscribe(self): 1244 """ 1245 A successful subscription should return the current subscription. 1246 """ 1247 1248 xml = """ 1249 <iq type='set' to='pubsub.example.org' 1250 from='user@example.org'> 1251 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1252 <subscribe node='test' jid='user@example.org/Home'/> 1253 </pubsub> 1254 </iq> 1255 """ 1256 1257 def subscribe(requestor, service, nodeIdentifier, subscriber): 1258 return defer.succeed(pubsub.Subscription(nodeIdentifier, 1259 subscriber, 1260 'subscribed')) 1261 1262 def cb(element): 1263 self.assertEqual('pubsub', element.name) 1264 self.assertEqual(NS_PUBSUB, element.uri) 1265 subscription = element.subscription 1266 self.assertEqual(NS_PUBSUB, subscription.uri) 1267 self.assertEqual('test', subscription['node']) 1268 self.assertEqual('user@example.org/Home', subscription['jid']) 1269 self.assertEqual('subscribed', subscription['subscription']) 1270 1271 self.service.subscribe = subscribe 1272 verify.verifyObject(iwokkel.IPubSubService, self.service) 1273 d = self.handleRequest(xml) 1274 d.addCallback(cb) 1275 return d 1276 1277 1278 def test_onSubscribeEmptyNode(self): 1279 """ 1280 A successful subscription on root node should return no node attribute. 1281 """ 1282 1283 xml = """ 1284 <iq type='set' to='pubsub.example.org' 1285 from='user@example.org'> 1286 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1287 <subscribe jid='user@example.org/Home'/> 1288 </pubsub> 1289 </iq> 1290 """ 1291 1292 def subscribe(requestor, service, nodeIdentifier, subscriber): 1293 return defer.succeed(pubsub.Subscription(nodeIdentifier, 1294 subscriber, 1295 'subscribed')) 1296 1297 def cb(element): 1298 self.assertFalse(element.subscription.hasAttribute('node')) 1299 1300 self.service.subscribe = subscribe 1301 verify.verifyObject(iwokkel.IPubSubService, self.service) 1302 d = self.handleRequest(xml) 1303 d.addCallback(cb) 1304 return d 1305 1306 1307 def test_onUnsubscribe(self): 1308 """ 1309 A successful unsubscription should return an empty response. 1310 """ 1311 1312 xml = """ 1313 <iq type='set' to='pubsub.example.org' 1314 from='user@example.org'> 1315 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1316 <unsubscribe node='test' jid='user@example.org/Home'/> 1317 </pubsub> 1318 </iq> 1319 """ 1320 1321 def unsubscribe(requestor, service, nodeIdentifier, subscriber): 1322 return defer.succeed(None) 1323 1324 def cb(element): 1325 self.assertIdentical(None, element) 1326 1327 self.service.unsubscribe = unsubscribe 1328 verify.verifyObject(iwokkel.IPubSubService, self.service) 1329 d = self.handleRequest(xml) 1330 d.addCallback(cb) 1331 return d 1332 1333 620 1334 def test_onOptionsGet(self): 621 1335 """ 622 Subscription options arenot supported.1336 Getting subscription options is not supported. 623 1337 """ 624 1338 … … 627 1341 from='user@example.org'> 628 1342 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 629 <options/> 1343 <options node='test' jid='user@example.org/Home'/> 1344 </pubsub> 1345 </iq> 1346 """ 1347 1348 def cb(result): 1349 self.assertEquals('feature-not-implemented', result.condition) 1350 self.assertEquals('unsupported', result.appCondition.name) 1351 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 1352 1353 d = self.handleRequest(xml) 1354 self.assertFailure(d, error.StanzaError) 1355 d.addCallback(cb) 1356 return d 1357 1358 1359 def test_onOptionsSet(self): 1360 """ 1361 Setting subscription options is not supported. 1362 """ 1363 1364 xml = """ 1365 <iq type='set' to='pubsub.example.org' 1366 from='user@example.org'> 1367 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1368 <options node='test' jid='user@example.org/Home'> 1369 <x xmlns='jabber:x:data' type='submit'> 1370 <field var='FORM_TYPE' type='hidden'> 1371 <value>http://jabber.org/protocol/pubsub#subscribe_options</value> 1372 </field> 1373 <field var='pubsub#deliver'><value>1</value></field> 1374 </x> 1375 </options> 630 1376 </pubsub> 631 1377 </iq> … … 674 1420 675 1421 def subscriptions(requestor, service): 676 self.assertEqual(JID('user@example.org'), requestor)677 self.assertEqual(JID('pubsub.example.org'), service)678 1422 subscription = pubsub.Subscription('test', JID('user@example.org'), 679 1423 'subscribed') … … 681 1425 682 1426 self.service.subscriptions = subscriptions 1427 verify.verifyObject(iwokkel.IPubSubService, self.service) 1428 d = self.handleRequest(xml) 1429 d.addCallback(cb) 1430 return d 1431 1432 1433 def test_onAffiliations(self): 1434 """ 1435 A subscriptions request should result in 1436 L{PubSubService.affiliations} being called and the result prepared 1437 for the response. 1438 """ 1439 1440 xml = """ 1441 <iq type='get' to='pubsub.example.org' 1442 from='user@example.org'> 1443 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1444 <affiliations/> 1445 </pubsub> 1446 </iq> 1447 """ 1448 1449 def cb(element): 1450 self.assertEqual('pubsub', element.name) 1451 self.assertEqual(NS_PUBSUB, element.uri) 1452 self.assertEqual(NS_PUBSUB, element.affiliations.uri) 1453 children = list(element.affiliations.elements()) 1454 self.assertEqual(1, len(children)) 1455 affiliation = children[0] 1456 self.assertEqual('affiliation', affiliation.name) 1457 self.assertEqual(NS_PUBSUB, affiliation.uri) 1458 self.assertEqual('test', affiliation['node']) 1459 self.assertEqual('owner', affiliation['affiliation']) 1460 1461 1462 def affiliations(requestor, service): 1463 affiliation = ('test', 'owner') 1464 return defer.succeed([affiliation]) 1465 1466 self.service.affiliations = affiliations 1467 verify.verifyObject(iwokkel.IPubSubService, self.service) 1468 d = self.handleRequest(xml) 1469 d.addCallback(cb) 1470 return d 1471 1472 1473 def test_onCreate(self): 1474 """ 1475 Replies to create node requests don't return the created node. 1476 """ 1477 1478 xml = """ 1479 <iq type='set' to='pubsub.example.org' 1480 from='user@example.org'> 1481 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1482 <create node='mynode'/> 1483 </pubsub> 1484 </iq> 1485 """ 1486 1487 def create(requestor, service, nodeIdentifier): 1488 return defer.succeed(nodeIdentifier) 1489 1490 def cb(element): 1491 self.assertIdentical(None, element) 1492 1493 self.service.create = create 1494 verify.verifyObject(iwokkel.IPubSubService, self.service) 1495 d = self.handleRequest(xml) 1496 d.addCallback(cb) 1497 return d 1498 1499 1500 def test_onCreateChanged(self): 1501 """ 1502 Replies to create node requests return the created node if changed. 1503 """ 1504 1505 xml = """ 1506 <iq type='set' to='pubsub.example.org' 1507 from='user@example.org'> 1508 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1509 <create node='mynode'/> 1510 </pubsub> 1511 </iq> 1512 """ 1513 1514 def create(requestor, service, nodeIdentifier): 1515 return defer.succeed(u'myrenamednode') 1516 1517 def cb(element): 1518 self.assertEqual('pubsub', element.name) 1519 self.assertEqual(NS_PUBSUB, element.uri) 1520 self.assertEqual(NS_PUBSUB, element.create.uri) 1521 self.assertEqual(u'myrenamednode', 1522 element.create.getAttribute('node')) 1523 1524 self.service.create = create 1525 verify.verifyObject(iwokkel.IPubSubService, self.service) 1526 d = self.handleRequest(xml) 1527 d.addCallback(cb) 1528 return d 1529 1530 1531 def test_onCreateInstant(self): 1532 """ 1533 Replies to create instant node requests return the created node. 1534 """ 1535 1536 xml = """ 1537 <iq type='set' to='pubsub.example.org' 1538 from='user@example.org'> 1539 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1540 <create/> 1541 </pubsub> 1542 </iq> 1543 """ 1544 1545 def create(requestor, service, nodeIdentifier): 1546 return defer.succeed(u'random') 1547 1548 def cb(element): 1549 self.assertEqual('pubsub', element.name) 1550 self.assertEqual(NS_PUBSUB, element.uri) 1551 self.assertEqual(NS_PUBSUB, element.create.uri) 1552 self.assertEqual(u'random', element.create.getAttribute('node')) 1553 1554 self.service.create = create 1555 verify.verifyObject(iwokkel.IPubSubService, self.service) 683 1556 d = self.handleRequest(xml) 684 1557 d.addCallback(cb) … … 712 1585 713 1586 def getDefaultConfiguration(requestor, service, nodeType): 714 self.assertEqual(JID('user@example.org'), requestor)715 self.assertEqual(JID('pubsub.example.org'), service)716 self.assertEqual('leaf', nodeType)717 1587 return defer.succeed({}) 718 1588 … … 728 1598 verify.verifyObject(iwokkel.IPubSubService, self.service) 729 1599 d = self.handleRequest(xml) 1600 d.addCallback(cb) 1601 return d 1602 1603 1604 def test_onDefaultCollection(self): 1605 """ 1606 Responses to default requests should depend on passed node type. 1607 """ 1608 1609 xml = """ 1610 <iq type='get' to='pubsub.example.org' 1611 from='user@example.org'> 1612 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 1613 <default> 1614 <x xmlns='jabber:x:data' type='submit'> 1615 <field var='FORM_TYPE' type='hidden'> 1616 <value>http://jabber.org/protocol/pubsub#node_config</value> 1617 </field> 1618 <field var='pubsub#node_type'> 1619 <value>collection</value> 1620 </field> 1621 </x> 1622 </default> 1623 1624 </pubsub> 1625 </iq> 1626 """ 1627 1628 def getConfigurationOptions(): 1629 return { 1630 "pubsub#deliver_payloads": 1631 {"type": "boolean", 1632 "label": "Deliver payloads with event notifications"} 1633 } 1634 1635 def getDefaultConfiguration(requestor, service, nodeType): 1636 return defer.succeed({}) 1637 1638 self.service.getConfigurationOptions = getConfigurationOptions 1639 self.service.getDefaultConfiguration = getDefaultConfiguration 1640 verify.verifyObject(iwokkel.IPubSubService, self.service) 1641 return self.handleRequest(xml) 1642 1643 1644 def test_onDefaultUnknownNodeType(self): 1645 """ 1646 A default request should result in 1647 L{PubSubService.getDefaultConfiguration} being called. 1648 """ 1649 1650 xml = """ 1651 <iq type='get' to='pubsub.example.org' 1652 from='user@example.org'> 1653 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 1654 <default> 1655 <x xmlns='jabber:x:data' type='submit'> 1656 <field var='FORM_TYPE' type='hidden'> 1657 <value>http://jabber.org/protocol/pubsub#node_config</value> 1658 </field> 1659 <field var='pubsub#node_type'> 1660 <value>unknown</value> 1661 </field> 1662 </x> 1663 </default> 1664 1665 </pubsub> 1666 </iq> 1667 """ 1668 1669 def getDefaultConfiguration(requestor, service, nodeType): 1670 self.fail("Unexpected call to getConfiguration") 1671 1672 def cb(result): 1673 self.assertEquals('not-acceptable', result.condition) 1674 1675 self.service.getDefaultConfiguration = getDefaultConfiguration 1676 verify.verifyObject(iwokkel.IPubSubService, self.service) 1677 d = self.handleRequest(xml) 1678 self.assertFailure(d, error.StanzaError) 730 1679 d.addCallback(cb) 731 1680 return d … … 761 1710 762 1711 def getConfiguration(requestor, service, nodeIdentifier): 763 self.assertEqual(JID('user@example.org'), requestor)764 self.assertEqual(JID('pubsub.example.org'), service)765 self.assertEqual('test', nodeIdentifier)766 767 1712 return defer.succeed({'pubsub#deliver_payloads': '0', 768 1713 'pubsub#persist_items': '1', 769 'pubsub#owner': JID('user@example.org')}) 1714 'pubsub#owner': JID('user@example.org'), 1715 'x-myfield': ['a', 'b']}) 770 1716 771 1717 def cb(element): … … 795 1741 self.assertEqual(JID('user@example.org'), field.value) 796 1742 1743 self.assertNotIn('x-myfield', fields) 1744 1745 797 1746 self.service.getConfigurationOptions = getConfigurationOptions 798 1747 self.service.getConfiguration = getConfiguration 1748 verify.verifyObject(iwokkel.IPubSubService, self.service) 799 1749 d = self.handleRequest(xml) 800 1750 d.addCallback(cb) … … 836 1786 837 1787 def setConfiguration(requestor, service, nodeIdentifier, options): 838 self.assertEqual(JID('user@example.org'), requestor)839 self.assertEqual(JID('pubsub.example.org'), service)840 self.assertEqual('test', nodeIdentifier)841 1788 self.assertEqual({'pubsub#deliver_payloads': False, 842 1789 'pubsub#persist_items': True}, options) … … 845 1792 self.service.getConfigurationOptions = getConfigurationOptions 846 1793 self.service.setConfiguration = setConfiguration 1794 verify.verifyObject(iwokkel.IPubSubService, self.service) 847 1795 return self.handleRequest(xml) 848 1796 … … 873 1821 874 1822 self.service.setConfiguration = setConfiguration 1823 verify.verifyObject(iwokkel.IPubSubService, self.service) 875 1824 return self.handleRequest(xml) 876 1825 … … 913 1862 self.service.getConfigurationOptions = getConfigurationOptions 914 1863 self.service.setConfiguration = setConfiguration 1864 verify.verifyObject(iwokkel.IPubSubService, self.service) 915 1865 return self.handleRequest(xml) 916 1866 917 1867 1868 def test_onConfigureSetBadFormType(self): 1869 """ 1870 On a node configuration set request unknown fields should be ignored. 1871 """ 1872 1873 xml = """ 1874 <iq type='set' to='pubsub.example.org' 1875 from='user@example.org'> 1876 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 1877 <configure node='test'> 1878 <x xmlns='jabber:x:data' type='result'> 1879 <field var='FORM_TYPE' type='hidden'> 1880 <value>http://jabber.org/protocol/pubsub#node_config</value> 1881 </field> 1882 <field var='pubsub#deliver_payloads'><value>0</value></field> 1883 <field var='x-myfield'><value>1</value></field> 1884 </x> 1885 </configure> 1886 </pubsub> 1887 </iq> 1888 """ 1889 1890 def cb(result): 1891 self.assertEquals('bad-request', result.condition) 1892 1893 d = self.handleRequest(xml) 1894 self.assertFailure(d, error.StanzaError) 1895 d.addCallback(cb) 1896 return d 1897 1898 918 1899 def test_onItems(self): 919 1900 """ … … 929 1910 """ 930 1911 931 def items(requestor, service, nodeIdentifier, maxItems, items): 932 self.assertEqual(JID('user@example.org'), requestor) 933 self.assertEqual(JID('pubsub.example.org'), service) 934 self.assertEqual('test', nodeIdentifier) 935 self.assertIdentical(None, maxItems) 936 self.assertEqual([], items) 1912 def items(requestor, service, nodeIdentifier, maxItems, 1913 itemIdentifiers): 937 1914 return defer.succeed([pubsub.Item('current')]) 938 1915 … … 972 1949 973 1950 def retract(requestor, service, nodeIdentifier, itemIdentifiers): 974 self.assertEqual(JID('user@example.org'), requestor)975 self.assertEqual(JID('pubsub.example.org'), service)976 self.assertEqual('test', nodeIdentifier)977 self.assertEqual(['item1', 'item2'], itemIdentifiers)978 1951 return defer.succeed(None) 979 1952 … … 998 1971 999 1972 def purge(requestor, service, nodeIdentifier): 1000 self.assertEqual(JID('user@example.org'), requestor)1001 self.assertEqual(JID('pubsub.example.org'), service)1002 self.assertEqual('test', nodeIdentifier)1003 1973 return defer.succeed(None) 1004 1974 … … 1023 1993 1024 1994 def delete(requestor, service, nodeIdentifier): 1025 self.assertEqual(JID('user@example.org'), requestor)1026 self.assertEqual(JID('pubsub.example.org'), service)1027 self.assertEqual('test', nodeIdentifier)1028 1995 return defer.succeed(None) 1029 1996 … … 1077 2044 self.assertTrue(message.event.delete.redirect.hasAttribute('uri')) 1078 2045 self.assertEqual(redirectURI, message.event.delete.redirect['uri']) 2046 2047 2048 def test_onSubscriptionsGet(self): 2049 """ 2050 Getting subscription options is not supported. 2051 """ 2052 2053 xml = """ 2054 <iq type='get' to='pubsub.example.org' 2055 from='user@example.org'> 2056 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 2057 <subscriptions/> 2058 </pubsub> 2059 </iq> 2060 """ 2061 2062 def cb(result): 2063 self.assertEquals('feature-not-implemented', result.condition) 2064 self.assertEquals('unsupported', result.appCondition.name) 2065 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2066 self.assertEquals('manage-subscriptions', 2067 result.appCondition['feature']) 2068 2069 d = self.handleRequest(xml) 2070 self.assertFailure(d, error.StanzaError) 2071 d.addCallback(cb) 2072 return d 2073 2074 2075 def test_onSubscriptionsSet(self): 2076 """ 2077 Setting subscription options is not supported. 2078 """ 2079 2080 xml = """ 2081 <iq type='set' to='pubsub.example.org' 2082 from='user@example.org'> 2083 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 2084 <subscriptions/> 2085 </pubsub> 2086 </iq> 2087 """ 2088 2089 def cb(result): 2090 self.assertEquals('feature-not-implemented', result.condition) 2091 self.assertEquals('unsupported', result.appCondition.name) 2092 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2093 self.assertEquals('manage-subscriptions', 2094 result.appCondition['feature']) 2095 2096 d = self.handleRequest(xml) 2097 self.assertFailure(d, error.StanzaError) 2098 d.addCallback(cb) 2099 return d 2100 2101 2102 def test_onAffiliationsGet(self): 2103 """ 2104 Getting subscription options is not supported. 2105 """ 2106 2107 xml = """ 2108 <iq type='get' to='pubsub.example.org' 2109 from='user@example.org'> 2110 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 2111 <affiliations/> 2112 </pubsub> 2113 </iq> 2114 """ 2115 2116 def cb(result): 2117 self.assertEquals('feature-not-implemented', result.condition) 2118 self.assertEquals('unsupported', result.appCondition.name) 2119 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2120 self.assertEquals('modify-affiliations', 2121 result.appCondition['feature']) 2122 2123 d = self.handleRequest(xml) 2124 self.assertFailure(d, error.StanzaError) 2125 d.addCallback(cb) 2126 return d 2127 2128 2129 def test_onAffiliationsSet(self): 2130 """ 2131 Setting subscription options is not supported. 2132 """ 2133 2134 xml = """ 2135 <iq type='set' to='pubsub.example.org' 2136 from='user@example.org'> 2137 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 2138 <affiliations/> 2139 </pubsub> 2140 </iq> 2141 """ 2142 2143 def cb(result): 2144 self.assertEquals('feature-not-implemented', result.condition) 2145 self.assertEquals('unsupported', result.appCondition.name) 2146 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2147 self.assertEquals('modify-affiliations', 2148 result.appCondition['feature']) 2149 2150 d = self.handleRequest(xml) 2151 self.assertFailure(d, error.StanzaError) 2152 d.addCallback(cb) 2153 return d 2154 2155 2156 def test_publish(self): 2157 """ 2158 Non-overridden L{PubSubService.publish} yields unsupported error. 2159 """ 2160 2161 xml = """ 2162 <iq type='set' to='pubsub.example.org' 2163 from='user@example.org'> 2164 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 2165 <publish node='mynode'/> 2166 </pubsub> 2167 </iq> 2168 """ 2169 2170 def cb(result): 2171 self.assertEquals('feature-not-implemented', result.condition) 2172 self.assertEquals('unsupported', result.appCondition.name) 2173 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2174 self.assertEquals('publish', result.appCondition['feature']) 2175 2176 d = self.handleRequest(xml) 2177 self.assertFailure(d, error.StanzaError) 2178 d.addCallback(cb) 2179 return d 2180 2181 2182 def test_subscribe(self): 2183 """ 2184 Non-overridden L{PubSubService.subscribe} yields unsupported error. 2185 """ 2186 2187 xml = """ 2188 <iq type='set' to='pubsub.example.org' 2189 from='user@example.org'> 2190 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 2191 <subscribe node='test' jid='user@example.org/Home'/> 2192 </pubsub> 2193 </iq> 2194 """ 2195 2196 def cb(result): 2197 self.assertEquals('feature-not-implemented', result.condition) 2198 self.assertEquals('unsupported', result.appCondition.name) 2199 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2200 self.assertEquals('subscribe', result.appCondition['feature']) 2201 2202 d = self.handleRequest(xml) 2203 self.assertFailure(d, error.StanzaError) 2204 d.addCallback(cb) 2205 return d 2206 2207 2208 def test_unsubscribe(self): 2209 """ 2210 Non-overridden L{PubSubService.unsubscribe} yields unsupported error. 2211 """ 2212 2213 xml = """ 2214 <iq type='set' to='pubsub.example.org' 2215 from='user@example.org'> 2216 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 2217 <unsubscribe node='test' jid='user@example.org/Home'/> 2218 </pubsub> 2219 </iq> 2220 """ 2221 2222 def cb(result): 2223 self.assertEquals('feature-not-implemented', result.condition) 2224 self.assertEquals('unsupported', result.appCondition.name) 2225 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2226 self.assertEquals('subscribe', result.appCondition['feature']) 2227 2228 d = self.handleRequest(xml) 2229 self.assertFailure(d, error.StanzaError) 2230 d.addCallback(cb) 2231 return d 2232 2233 2234 def test_subscriptions(self): 2235 """ 2236 Non-overridden L{PubSubService.subscriptions} yields unsupported error. 2237 """ 2238 2239 xml = """ 2240 <iq type='get' to='pubsub.example.org' 2241 from='user@example.org'> 2242 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 2243 <subscriptions/> 2244 </pubsub> 2245 </iq> 2246 """ 2247 2248 def cb(result): 2249 self.assertEquals('feature-not-implemented', result.condition) 2250 self.assertEquals('unsupported', result.appCondition.name) 2251 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2252 self.assertEquals('retrieve-subscriptions', 2253 result.appCondition['feature']) 2254 2255 d = self.handleRequest(xml) 2256 self.assertFailure(d, error.StanzaError) 2257 d.addCallback(cb) 2258 return d 2259 2260 2261 def test_affiliations(self): 2262 """ 2263 Non-overridden L{PubSubService.affiliations} yields unsupported error. 2264 """ 2265 2266 xml = """ 2267 <iq type='get' to='pubsub.example.org' 2268 from='user@example.org'> 2269 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 2270 <affiliations/> 2271 </pubsub> 2272 </iq> 2273 """ 2274 2275 def cb(result): 2276 self.assertEquals('feature-not-implemented', result.condition) 2277 self.assertEquals('unsupported', result.appCondition.name) 2278 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2279 self.assertEquals('retrieve-affiliations', 2280 result.appCondition['feature']) 2281 2282 d = self.handleRequest(xml) 2283 self.assertFailure(d, error.StanzaError) 2284 d.addCallback(cb) 2285 return d 2286 2287 2288 def test_create(self): 2289 """ 2290 Non-overridden L{PubSubService.create} yields unsupported error. 2291 """ 2292 2293 xml = """ 2294 <iq type='set' to='pubsub.example.org' 2295 from='user@example.org'> 2296 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 2297 <create node='mynode'/> 2298 </pubsub> 2299 </iq> 2300 """ 2301 2302 def cb(result): 2303 self.assertEquals('feature-not-implemented', result.condition) 2304 self.assertEquals('unsupported', result.appCondition.name) 2305 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2306 self.assertEquals('create-nodes', result.appCondition['feature']) 2307 2308 d = self.handleRequest(xml) 2309 self.assertFailure(d, error.StanzaError) 2310 d.addCallback(cb) 2311 return d 2312 2313 2314 def test_getDefaultConfiguration(self): 2315 """ 2316 Non-overridden L{PubSubService.getDefaultConfiguration} yields 2317 unsupported error. 2318 """ 2319 2320 xml = """ 2321 <iq type='get' to='pubsub.example.org' 2322 from='user@example.org'> 2323 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 2324 <default/> 2325 </pubsub> 2326 </iq> 2327 """ 2328 2329 def cb(result): 2330 self.assertEquals('feature-not-implemented', result.condition) 2331 self.assertEquals('unsupported', result.appCondition.name) 2332 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2333 self.assertEquals('retrieve-default', result.appCondition['feature']) 2334 2335 d = self.handleRequest(xml) 2336 self.assertFailure(d, error.StanzaError) 2337 d.addCallback(cb) 2338 return d 2339 2340 2341 def test_getConfiguration(self): 2342 """ 2343 Non-overridden L{PubSubService.getConfiguration} yields unsupported 2344 error. 2345 """ 2346 2347 xml = """ 2348 <iq type='get' to='pubsub.example.org' 2349 from='user@example.org'> 2350 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 2351 <configure/> 2352 </pubsub> 2353 </iq> 2354 """ 2355 2356 def cb(result): 2357 self.assertEquals('feature-not-implemented', result.condition) 2358 self.assertEquals('unsupported', result.appCondition.name) 2359 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2360 self.assertEquals('config-node', result.appCondition['feature']) 2361 2362 d = self.handleRequest(xml) 2363 self.assertFailure(d, error.StanzaError) 2364 d.addCallback(cb) 2365 return d 2366 2367 2368 def test_setConfiguration(self): 2369 """ 2370 Non-overridden L{PubSubService.setConfiguration} yields unsupported 2371 error. 2372 """ 2373 2374 xml = """ 2375 <iq type='set' to='pubsub.example.org' 2376 from='user@example.org'> 2377 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 2378 <configure node='test'> 2379 <x xmlns='jabber:x:data' type='submit'> 2380 <field var='FORM_TYPE' type='hidden'> 2381 <value>http://jabber.org/protocol/pubsub#node_config</value> 2382 </field> 2383 <field var='pubsub#deliver_payloads'><value>0</value></field> 2384 <field var='pubsub#persist_items'><value>1</value></field> 2385 </x> 2386 </configure> 2387 </pubsub> 2388 </iq> 2389 """ 2390 2391 def cb(result): 2392 self.assertEquals('feature-not-implemented', result.condition) 2393 self.assertEquals('unsupported', result.appCondition.name) 2394 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2395 self.assertEquals('config-node', result.appCondition['feature']) 2396 2397 d = self.handleRequest(xml) 2398 self.assertFailure(d, error.StanzaError) 2399 d.addCallback(cb) 2400 return d 2401 2402 2403 def test_items(self): 2404 """ 2405 Non-overridden L{PubSubService.items} yields unsupported error. 2406 """ 2407 xml = """ 2408 <iq type='get' to='pubsub.example.org' 2409 from='user@example.org'> 2410 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 2411 <items node='test'/> 2412 </pubsub> 2413 </iq> 2414 """ 2415 2416 def cb(result): 2417 self.assertEquals('feature-not-implemented', result.condition) 2418 self.assertEquals('unsupported', result.appCondition.name) 2419 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2420 self.assertEquals('retrieve-items', result.appCondition['feature']) 2421 2422 d = self.handleRequest(xml) 2423 self.assertFailure(d, error.StanzaError) 2424 d.addCallback(cb) 2425 return d 2426 2427 2428 def test_retract(self): 2429 """ 2430 Non-overridden L{PubSubService.retract} yields unsupported error. 2431 """ 2432 xml = """ 2433 <iq type='set' to='pubsub.example.org' 2434 from='user@example.org'> 2435 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 2436 <retract node='test'> 2437 <item id='item1'/> 2438 <item id='item2'/> 2439 </retract> 2440 </pubsub> 2441 </iq> 2442 """ 2443 2444 def cb(result): 2445 self.assertEquals('feature-not-implemented', result.condition) 2446 self.assertEquals('unsupported', result.appCondition.name) 2447 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2448 self.assertEquals('retract-items', result.appCondition['feature']) 2449 2450 d = self.handleRequest(xml) 2451 self.assertFailure(d, error.StanzaError) 2452 d.addCallback(cb) 2453 return d 2454 2455 2456 def test_purge(self): 2457 """ 2458 Non-overridden L{PubSubService.purge} yields unsupported error. 2459 """ 2460 xml = """ 2461 <iq type='set' to='pubsub.example.org' 2462 from='user@example.org'> 2463 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 2464 <purge node='test'/> 2465 </pubsub> 2466 </iq> 2467 """ 2468 2469 def cb(result): 2470 self.assertEquals('feature-not-implemented', result.condition) 2471 self.assertEquals('unsupported', result.appCondition.name) 2472 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2473 self.assertEquals('purge-nodes', result.appCondition['feature']) 2474 2475 d = self.handleRequest(xml) 2476 self.assertFailure(d, error.StanzaError) 2477 d.addCallback(cb) 2478 return d 2479 2480 2481 def test_delete(self): 2482 """ 2483 Non-overridden L{PubSubService.delete} yields unsupported error. 2484 """ 2485 xml = """ 2486 <iq type='set' to='pubsub.example.org' 2487 from='user@example.org'> 2488 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 2489 <delete node='test'/> 2490 </pubsub> 2491 </iq> 2492 """ 2493 2494 def cb(result): 2495 self.assertEquals('feature-not-implemented', result.condition) 2496 self.assertEquals('unsupported', result.appCondition.name) 2497 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2498 self.assertEquals('delete-nodes', result.appCondition['feature']) 2499 2500 d = self.handleRequest(xml) 2501 self.assertFailure(d, error.StanzaError) 2502 d.addCallback(cb) 2503 return d
Note: See TracChangeset
for help on using the changeset viewer.