source:
ralphm-patches/pubsub_request.patch
@
1:7fc86463b39f
Last change on this file since 1:7fc86463b39f was 1:7fc86463b39f, checked in by Ralph Meijer <ralphm@…>, 13 years ago | |
---|---|
File size: 76.2 KB |
-
wokkel/iwokkel.py
Add PubSubRequest that parses requests and replaces separate parameters. The publish-subscribe protocol has a large number of optional features. Adding support for a feature often means more information needs to be passed, and required changing the signature of the methods that need to be overridden by adaptors. This change adds the new PubSubRequest class that features a fromElement method that creates a new instance, parses a request and then fills the instance attributes where appropriate. This instance is then the only argument that is passed to the corresponding handler methods. diff -r fafe0148a94c wokkel/iwokkel.py
a b 278 278 C{list} of L{domish.Element}) 279 279 """ 280 280 281 281 282 def notifyDelete(service, nodeIdentifier, subscribers, 282 283 redirectURI=None): 283 284 """ … … 295 296 @type redirectURI: C{str} 296 297 """ 297 298 298 def publish(requestor, service, nodeIdentifier, items): 299 300 def publish(request): 299 301 """ 300 302 Called when a publish request has been received. 301 303 302 @param requestor: The entity the request originated from. 303 @type requestor: L{jid.JID} 304 @param service: The entity the request was addressed to. 305 @type service: L{jid.JID} 306 @param nodeIdentifier: The identifier of the node to publish to. 307 @type nodeIdentifier: C{unicode} 308 @param items: The items to be published as L{domish} elements. 309 @type items: C{list} of C{domish.Element} 304 @param request: The publish-subscribe request. 305 @type request: L{wokkel.pubsub.PubSubRequest} 310 306 @return: deferred that fires on success. 311 307 @rtype: L{defer.Deferred} 312 308 """ 313 309 314 def subscribe(requestor, service, nodeIdentifier, subscriber): 310 311 def subscribe(request): 315 312 """ 316 313 Called when a subscribe request has been received. 317 314 318 @param requestor: The entity the request originated from. 319 @type requestor: L{jid.JID} 320 @param service: The entity the request was addressed to. 321 @type service: L{jid.JID} 322 @param nodeIdentifier: The identifier of the node to subscribe to. 323 @type nodeIdentifier: C{unicode} 324 @param subscriber: The entity to be subscribed. 325 @type subscriber: L{jid.JID} 315 @param request: The publish-subscribe request. 316 @type request: L{wokkel.pubsub.PubSubRequest} 326 317 @return: A deferred that fires with a 327 318 L{Subscription<wokkel.pubsub.Subscription>}. 328 319 @rtype: L{defer.Deferred} 329 320 """ 330 321 331 def unsubscribe(requestor, service, nodeIdentifier, subscriber): 322 323 def unsubscribe(request): 332 324 """ 333 325 Called when a subscribe request has been received. 334 326 335 @param requestor: The entity the request originated from. 336 @type requestor: L{jid.JID} 337 @param service: The entity the request was addressed to. 338 @type service: L{jid.JID} 339 @param nodeIdentifier: The identifier of the node to unsubscribe from. 340 @type nodeIdentifier: C{unicode} 341 @param subscriber: The entity to be unsubscribed. 342 @type subscriber: L{jid.JID} 327 @param request: The publish-subscribe request. 328 @type request: L{wokkel.pubsub.PubSubRequest} 343 329 @return: A deferred that fires with C{None} when unsubscription has 344 330 succeeded. 345 331 @rtype: L{defer.Deferred} 346 332 """ 347 333 348 def subscriptions(requestor, service): 334 335 def subscriptions(request): 349 336 """ 350 337 Called when a subscriptions retrieval request has been received. 351 338 352 @param requestor: The entity the request originated from. 353 @type requestor: L{jid.JID} 354 @param service: The entity the request was addressed to. 355 @type service: L{jid.JID} 339 @param request: The publish-subscribe request. 340 @type request: L{wokkel.pubsub.PubSubRequest} 356 341 @return: A deferred that fires with a C{list} of subscriptions as 357 342 L{Subscription<wokkel.pubsub.Subscription>}. 358 343 @rtype: L{defer.Deferred} 359 344 """ 360 345 361 def affiliations(requestor, service): 346 347 def affiliations(request): 362 348 """ 363 349 Called when a affiliations retrieval request has been received. 364 350 365 @param requestor: The entity the request originated from. 366 @type requestor: L{jid.JID} 367 @param service: The entity the request was addressed to. 368 @type service: L{jid.JID} 351 @param request: The publish-subscribe request. 352 @type request: L{wokkel.pubsub.PubSubRequest} 369 353 @return: A deferred that fires with a C{list} of affiliations as 370 354 C{tuple}s of (node identifier as C{unicode}, affiliation state 371 355 as C{str}). The affiliation can be C{'owner'}, C{'publisher'}, … … 373 357 @rtype: L{defer.Deferred} 374 358 """ 375 359 376 def create(requestor, service, nodeIdentifier): 360 361 def create(request): 377 362 """ 378 363 Called when a node creation request has been received. 379 364 380 @param requestor: The entity the request originated from. 381 @type requestor: L{jid.JID} 382 @param service: The entity the request was addressed to. 383 @type service: L{jid.JID} 384 @param nodeIdentifier: The suggestion for the identifier of the node to 385 be created. If the request did not include a 386 suggestion for the node identifier, the value 387 is C{None}. 388 @type nodeIdentifier: C{unicode} or C{NoneType} 365 @param request: The publish-subscribe request. 366 @type request: L{wokkel.pubsub.PubSubRequest} 389 367 @return: A deferred that fires with a C{unicode} that represents 390 368 the identifier of the new node. 391 369 @rtype: L{defer.Deferred} 392 370 """ 371 393 372 394 373 def getConfigurationOptions(): 395 374 """ … … 426 405 @rtype: C{dict}. 427 406 """ 428 407 429 def getDefaultConfiguration(requestor, service, nodeType): 408 409 def getDefaultConfiguration(request): 430 410 """ 431 411 Called when a default node configuration request has been received. 432 412 433 @param requestor: The entity the request originated from. 434 @type requestor: L{jid.JID} 435 @param service: The entity the request was addressed to. 436 @type service: L{jid.JID} 437 @param nodeType: The type of node for which the configuration is 438 retrieved, C{'leaf'} or C{'collection'}. 439 @type nodeType: C{str} 413 @param request: The publish-subscribe request. 414 @type request: L{wokkel.pubsub.PubSubRequest} 440 415 @return: A deferred that fires with a C{dict} representing the default 441 416 node configuration. Keys are C{str}s that represent the 442 417 field name. Values can be of types C{unicode}, C{int} or … … 444 419 @rtype: L{defer.Deferred} 445 420 """ 446 421 447 def getConfiguration(requestor, service, nodeIdentifier): 422 423 def getConfiguration(request): 448 424 """ 449 425 Called when a node configuration retrieval request has been received. 450 426 451 @param requestor: The entity the request originated from. 452 @type requestor: L{jid.JID} 453 @param service: The entity the request was addressed to. 454 @type service: L{jid.JID} 455 @param nodeIdentifier: The identifier of the node to retrieve the 456 configuration from. 457 @type nodeIdentifier: C{unicode} 427 @param request: The publish-subscribe request. 428 @type request: L{wokkel.pubsub.PubSubRequest} 458 429 @return: A deferred that fires with a C{dict} representing the node 459 430 configuration. Keys are C{str}s that represent the field name. 460 431 Values can be of types C{unicode}, C{int} or C{bool}. 461 432 @rtype: L{defer.Deferred} 462 433 """ 463 434 464 def setConfiguration(requestor, service, nodeIdentifier, options): 435 436 def setConfiguration(request): 465 437 """ 466 438 Called when a node configuration change request has been received. 467 439 468 @param requestor: The entity the request originated from. 469 @type requestor: L{jid.JID} 470 @param service: The entity the request was addressed to. 471 @type service: L{jid.JID} 472 @param nodeIdentifier: The identifier of the node to change the 473 configuration of. 474 @type nodeIdentifier: C{unicode} 440 @param request: The publish-subscribe request. 441 @type request: L{wokkel.pubsub.PubSubRequest} 475 442 @return: A deferred that fires with C{None} when the node's 476 443 configuration has been changed. 477 444 @rtype: L{defer.Deferred} 478 445 """ 479 446 480 def items(requestor, service, nodeIdentifier, maxItems, itemIdentifiers): 447 448 def items(request): 481 449 """ 482 450 Called when a items retrieval request has been received. 483 451 484 @param requestor: The entity the request originated from. 485 @type requestor: L{jid.JID} 486 @param service: The entity the request was addressed to. 487 @type service: L{jid.JID} 488 @param nodeIdentifier: The identifier of the node to retrieve items 489 from. 490 @type nodeIdentifier: C{unicode} 452 @param request: The publish-subscribe request. 453 @type request: L{wokkel.pubsub.PubSubRequest} 454 @return: A deferred that fires with a C{list} of L{pubsub.Item}. 455 @rtype: L{defer.Deferred} 491 456 """ 492 457 493 def retract(requestor, service, nodeIdentifier, itemIdentifiers): 458 459 def retract(request): 494 460 """ 495 461 Called when a item retraction request has been received. 496 462 497 @param requestor: The entity the request originated from. 498 @type requestor: L{jid.JID} 499 @param service: The entity the request was addressed to. 500 @type service: L{jid.JID} 501 @param nodeIdentifier: The identifier of the node to retract items 502 from. 503 @type nodeIdentifier: C{unicode} 463 @param request: The publish-subscribe request. 464 @type request: L{wokkel.pubsub.PubSubRequest} 465 @return: A deferred that fires with C{None} when the given items have 466 been retracted. 467 @rtype: L{defer.Deferred} 504 468 """ 505 469 506 def purge(requestor, service, nodeIdentifier): 470 471 def purge(request): 507 472 """ 508 473 Called when a node purge request has been received. 509 474 510 @param requestor: The entity the request originated from. 511 @type requestor: L{jid.JID} 512 @param service: The entity the request was addressed to. 513 @type service: L{jid.JID} 514 @param nodeIdentifier: The identifier of the node to be purged. 515 @type nodeIdentifier: C{unicode} 475 @param request: The publish-subscribe request. 476 @type request: L{wokkel.pubsub.PubSubRequest} 477 @return: A deferred that fires with C{None} when the node has been 478 purged. 479 @rtype: L{defer.Deferred} 516 480 """ 517 481 518 def delete(requestor, service, nodeIdentifier): 482 483 def delete(request): 519 484 """ 520 485 Called when a node deletion request has been received. 521 486 522 @param requestor: The entity the request originated from. 523 @type requestor: L{jid.JID} 524 @param service: The entity the request was addressed to. 525 @type service: L{jid.JID} 526 @param nodeIdentifier: The identifier of the node to be delete. 527 @type nodeIdentifier: C{unicode} 487 @param request: The publish-subscribe request. 488 @type request: L{wokkel.pubsub.PubSubRequest} 489 @return: A deferred that fires with C{None} when the node has been 490 deleted. 491 @rtype: L{defer.Deferred} 528 492 """ -
wokkel/pubsub.py
diff -r fafe0148a94c wokkel/pubsub.py
a b 32 32 NS_PUBSUB_NODE_CONFIG = NS_PUBSUB + "#node_config" 33 33 NS_PUBSUB_META_DATA = NS_PUBSUB + "#meta-data" 34 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 35 # XPath to match pubsub requests 36 PUBSUB_REQUEST = '/iq[@type="get" or @type="set"]/' + \ 37 'pubsub[@xmlns="' + NS_PUBSUB + '" or ' + \ 38 '@xmlns="' + NS_PUBSUB_OWNER + '"]' 71 39 72 40 class SubscriptionPending(Exception): 73 41 """ … … 466 434 467 435 468 436 437 class Request(object): 438 """ 439 An IQ request. 440 441 @ivar sender: The entity from which the request was received. 442 @type sender: L{jid.JID} 443 @ivar recipient: The entity to which the request was sent. 444 @type recipient: L{jid.JID} 445 """ 446 447 sender = None 448 recipient = None 449 stanzaType = None 450 451 @classmethod 452 def fromElement(Class, element): 453 request = Class() 454 request.parseElement(element) 455 return request 456 457 458 def parseElement(self, element): 459 self.sender = jid.internJID(element['from']) 460 if element.hasAttribute('from'): 461 self.sender = jid.internJID(element['from']) 462 if element.hasAttribute('to'): 463 self.recipient = jid.internJID(element['to']) 464 self.stanzaType = element.getAttribute('type') 465 466 467 468 class PubSubRequest(Request): 469 """ 470 A publish-subscribe request. 471 472 The set of instance variables used depends on the type of request. If 473 a variable is not applicable or not passed in the request, its value is 474 C{None}. 475 476 @ivar affiliations: Affiliations to be modified. 477 @type affiliations: C{set} 478 @ivar items: The items to be published, as L{domish.Element}s. 479 @type items: C{list} 480 @ivar itemIdentifiers: Identifiers of the items to be retrieved or 481 retracted. 482 @type itemIdentifiers: C{set} 483 @ivar maxItems: Maximum number of items to retrieve. 484 @type maxItems: C{int}. 485 @ivar nodeIdentifier: Identifier of the node the request is about. 486 @type nodeIdentifier: C{unicode} 487 @ivar nodeType: The type of node that should be created, or for which the 488 configuration is retrieved. C{'leaf'} or C{'collection'}. 489 @type nodeType: C{str} 490 @ivar options: Configurations options for nodes, subscriptions and publish 491 requests. 492 @type options: L{data_form.Form} 493 @ivar subscriber: The subscribing entity. 494 @type subscriber: L{JID} 495 @ivar subscriptionIdentifier: Identifier for a specific subscription. 496 @type subscriptionIdentifier: C{unicode} 497 @ivar subscriptions: Subscriptions to be modified, as a set of 498 L{Subscription}. 499 @type subscriptions: C{set} 500 """ 501 502 verb = None 503 504 affiliations = None 505 items = None 506 itemIdentifiers = None 507 maxItems = None 508 nodeIdentifier = None 509 nodeType = None 510 options = None 511 subscriber = None 512 subscriptionIdentifier = None 513 subscriptions = None 514 515 516 _verbs = { 517 ('set', NS_PUBSUB, 'publish'): ('publish', ['node', 'items']), 518 ('set', NS_PUBSUB, 'subscribe'): ('subscribe', ['nodeOrEmpty', 'jid']), 519 ('set', NS_PUBSUB, 'unsubscribe'): ('unsubscribe', ['node', 'jid']), 520 ('get', NS_PUBSUB, 'options'): ('optionsGet', []), 521 ('set', NS_PUBSUB, 'options'): ('optionsSet', []), 522 ('get', NS_PUBSUB, 'subscriptions'): ('subscriptions', []), 523 ('get', NS_PUBSUB, 'affiliations'): ('affiliations', []), 524 ('set', NS_PUBSUB, 'create'): ('create', ['nodeOrNone']), 525 ('get', NS_PUBSUB_OWNER, 'default'): ('default', ['default']), 526 ('get', NS_PUBSUB_OWNER, 'configure'): ('configureGet', 527 ['nodeOrEmpty']), 528 ('set', NS_PUBSUB_OWNER, 'configure'): ('configureSet', 529 ['nodeOrEmpty', 'configure']), 530 ('get', NS_PUBSUB, 'items'): ('items', ['node', 'maxItems', 531 'itemIdentifiers']), 532 ('set', NS_PUBSUB, 'retract'): ('retract', ['node', 533 'itemIdentifiers']), 534 ('set', NS_PUBSUB_OWNER, 'purge'): ('purge', ['node']), 535 ('set', NS_PUBSUB_OWNER, 'delete'): ('delete', ['node']), 536 ('get', NS_PUBSUB_OWNER, 'affiliations'): ('affiliationsGet', []), 537 ('set', NS_PUBSUB_OWNER, 'affiliations'): ('affiliationsSet', []), 538 ('get', NS_PUBSUB_OWNER, 'subscriptions'): ('subscriptionsGet', []), 539 ('set', NS_PUBSUB_OWNER, 'subscriptions'): ('subscriptionsSet', []), 540 } 541 542 @staticmethod 543 def _findForm(element, formNamespace): 544 if not element: 545 return None 546 547 form = None 548 for child in element.elements(): 549 try: 550 form = data_form.Form.fromElement(child) 551 except data_form.Error: 552 continue 553 554 if form.formNamespace != NS_PUBSUB_NODE_CONFIG: 555 continue 556 557 return form 558 559 560 def _parse_node(self, verbElement): 561 try: 562 self.nodeIdentifier = verbElement["node"] 563 except KeyError: 564 raise BadRequest('nodeid-required') 565 566 567 def _parse_nodeOrEmpty(self, verbElement): 568 self.nodeIdentifier = verbElement.getAttribute("node", '') 569 570 571 def _parse_nodeOrNone(self, verbElement): 572 self.nodeIdentifier = verbElement.getAttribute("node") 573 574 575 def _parse_items(self, verbElement): 576 self.items = [] 577 for element in verbElement.elements(): 578 if element.uri == NS_PUBSUB and element.name == 'item': 579 self.items.append(element) 580 581 582 def _parse_jid(self, verbElement): 583 try: 584 self.subscriber = jid.internJID(verbElement["jid"]) 585 except KeyError: 586 raise BadRequest('jid-required') 587 588 589 def _parse_default(self, verbElement): 590 form = PubSubRequest._findForm(verbElement, NS_PUBSUB_NODE_CONFIG) 591 if form and form.formType == 'submit': 592 values = form.getValues() 593 self.nodeType = values.get('pubsub#node_type', 'leaf') 594 else: 595 self.nodeType = 'leaf' 596 597 598 def _parse_configure(self, verbElement): 599 form = PubSubRequest._findForm(verbElement, NS_PUBSUB_NODE_CONFIG) 600 if form: 601 if form.formType == 'submit': 602 self.options = form.getValues() 603 elif form.formType == 'cancel': 604 self.options = {} 605 else: 606 raise BadRequest("Unexpected form type %r" % form.formType) 607 else: 608 raise BadRequest("Missing configuration form") 609 610 611 612 def _parse_itemIdentifiers(self, verbElement): 613 self.itemIdentifiers = [] 614 for element in verbElement.elements(): 615 if element.uri == NS_PUBSUB and element.name == 'item': 616 try: 617 self.itemIdentifiers.append(element["id"]) 618 except KeyError: 619 raise BadRequest() 620 621 622 def _parse_maxItems(self, verbElement): 623 value = verbElement.getAttribute('max_items') 624 625 if value: 626 try: 627 self.maxItems = int(value) 628 except ValueError: 629 raise BadRequest(text="Field max_items requires a positive " + 630 "integer value") 631 632 633 def parseElement(self, element): 634 Request.parseElement(self, element) 635 636 for child in element.pubsub.elements(): 637 key = (self.stanzaType, child.uri, child.name) 638 self.verb, parsers = PubSubRequest._verbs.get(key) 639 if self.verb: 640 break 641 642 if not self.verb: 643 raise NotImplementedError() 644 645 for parser in parsers: 646 getattr(self, '_parse_%s' % parser)(child) 647 648 649 469 650 class PubSubService(XMPPHandler, IQHandlerMixin): 470 651 """ 471 652 Protocol implementation for a XMPP Publish Subscribe Service. … … 497 678 implements(IPubSubService) 498 679 499 680 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 681 '/*': '_onPubSubRequest', 521 682 } 522 683 523 684 … … 530 691 531 692 532 693 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) 694 self.xmlstream.addObserver(PUBSUB_REQUEST, self.handleRequest) 537 695 538 696 539 697 def getDiscoInfo(self, requestor, target, nodeIdentifier): … … 585 743 return d 586 744 587 745 588 def _findForm(self, element, formNamespace): 589 if not element: 590 return None 746 def _onPubSubRequest(self, iq): 747 request = PubSubRequest.fromElement(iq) 748 handler = getattr(self, '_on_%s' % (request.verb)) 749 return handler(request) 591 750 592 form = None593 for child in element.elements():594 try:595 form = data_form.Form.fromElement(child)596 except data_form.Error:597 continue598 751 599 if form.formNamespace != NS_PUBSUB_NODE_CONFIG:600 continue752 def _on_publish(self, request): 753 return self.publish(request) 601 754 602 return form603 755 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') 756 def _on_subscribe(self, request): 674 757 675 758 def toResponse(result): 676 759 response = domish.Element((NS_PUBSUB, "pubsub")) … … 681 764 subscription["subscription"] = result.state 682 765 return response 683 766 684 d = self.subscribe(request or, service, nodeIdentifier, subscriber)767 d = self.subscribe(request) 685 768 d.addCallback(toResponse) 686 769 return d 687 770 688 771 689 def _onUnsubscribe(self, iq): 690 requestor, service, nodeIdentifier, subscriber = self._getParameters( 691 iq, 'unsubscribe', 'nodeOrEmpty', 'jid') 772 def _on_unsubscribe(self, request): 773 return self.unsubscribe(request) 692 774 693 return self.unsubscribe(requestor, service, nodeIdentifier, subscriber)694 775 695 696 def _onOptionsGet(self, iq): 776 def _on_optionsGet(self, request): 697 777 raise Unsupported('subscription-options') 698 778 699 779 700 def _on OptionsSet(self, iq):780 def _on_optionsSet(self, request): 701 781 raise Unsupported('subscription-options') 702 782 703 783 704 def _onSubscriptions(self, iq): 705 requestor, service = self._getParameters(iq) 784 def _on_subscriptions(self, request): 706 785 707 786 def toResponse(result): 708 787 response = domish.Element((NS_PUBSUB, 'pubsub')) … … 714 793 item['subscription'] = subscription.state 715 794 return response 716 795 717 d = self.subscriptions(request or, service)796 d = self.subscriptions(request) 718 797 d.addCallback(toResponse) 719 798 return d 720 799 721 800 722 def _onAffiliations(self, iq): 723 requestor, service = self._getParameters(iq) 801 def _on_affiliations(self, request): 724 802 725 803 def toResponse(result): 726 804 response = domish.Element((NS_PUBSUB, 'pubsub')) … … 733 811 734 812 return response 735 813 736 d = self.affiliations(request or, service)814 d = self.affiliations(request) 737 815 d.addCallback(toResponse) 738 816 return d 739 817 740 818 741 def _onCreate(self, iq): 742 requestor, service = self._getParameters(iq) 743 nodeIdentifier = iq.pubsub.create.getAttribute("node") 819 def _on_create(self, request): 744 820 745 821 def toResponse(result): 746 if not nodeIdentifier ornodeIdentifier != result:822 if not request.nodeIdentifier or request.nodeIdentifier != result: 747 823 response = domish.Element((NS_PUBSUB, 'pubsub')) 748 824 create = response.addElement('create') 749 825 create['node'] = result … … 751 827 else: 752 828 return None 753 829 754 d = self.create(request or, service, nodeIdentifier)830 d = self.create(request) 755 831 d.addCallback(toResponse) 756 832 return d 757 833 … … 771 847 fields.append(data_form.Field.fromDict(option)) 772 848 return fields 773 849 850 774 851 def _formFromConfiguration(self, values): 775 852 options = self.getConfigurationOptions() 776 853 fields = self._makeFields(options, values) … … 779 856 fields=fields) 780 857 781 858 return form 859 782 860 783 861 def _checkConfiguration(self, values): 784 862 options = self.getConfigurationOptions() … … 805 883 return processedValues 806 884 807 885 808 def _onDefault(self, iq): 809 requestor, service = self._getParameters(iq) 886 def _on_default(self, request): 810 887 811 888 def toResponse(options): 812 889 response = domish.Element((NS_PUBSUB_OWNER, "pubsub")) … … 814 891 default.addChild(self._formFromConfiguration(options).toElement()) 815 892 return response 816 893 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'): 894 if request.nodeType not in ('leaf', 'collection'): 822 895 return defer.fail(error.StanzaError('not-acceptable')) 823 896 824 d = self.getDefaultConfiguration(request or, service, nodeType)897 d = self.getDefaultConfiguration(request) 825 898 d.addCallback(toResponse) 826 899 return d 827 900 828 901 829 def _onConfigureGet(self, iq): 830 requestor, service, nodeIdentifier = self._getParameters( 831 iq, 'configure', 'nodeOrEmpty') 832 902 def _on_configureGet(self, request): 833 903 def toResponse(options): 834 904 response = domish.Element((NS_PUBSUB_OWNER, "pubsub")) 835 905 configure = response.addElement("configure") 836 configure.addChild(self._formFromConfiguration(options).toElement()) 906 form = self._formFromConfiguration(options) 907 configure.addChild(form.toElement()) 837 908 838 if nodeIdentifier:839 configure["node"] = nodeIdentifier909 if request.nodeIdentifier: 910 configure["node"] = request.nodeIdentifier 840 911 841 912 return response 842 913 843 d = self.getConfiguration(request or, service, nodeIdentifier)914 d = self.getConfiguration(request) 844 915 d.addCallback(toResponse) 845 916 return d 846 917 847 918 848 def _onConfigureSet(self, iq): 849 requestor, service, nodeIdentifier = self._getParameters( 850 iq, 'configure', 'nodeOrEmpty') 919 def _on_configureSet(self, request): 920 if request.options: 921 request.options = self._checkConfiguration(request.options) 922 return self.setConfiguration(request) 923 else: 924 return None 851 925 852 # Search configuration form with correct FORM_TYPE and process it853 926 854 form = self._findForm(iq.pubsub.configure, NS_PUBSUB_NODE_CONFIG)855 927 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() 928 def _on_items(self, request): 879 929 880 930 def toResponse(result): 881 931 response = domish.Element((NS_PUBSUB, 'pubsub')) 882 932 items = response.addElement('items') 883 if nodeIdentifier: 884 items["node"] = nodeIdentifier 933 items["node"] = request.nodeIdentifier 885 934 886 935 for item in result: 887 936 items.addChild(item) 888 937 889 938 return response 890 939 891 d = self.items(requestor, service, nodeIdentifier, maxItems, 892 itemIdentifiers) 940 d = self.items(request) 893 941 d.addCallback(toResponse) 894 942 return d 895 943 896 944 897 def _onRetract(self, iq): 898 requestor, service, nodeIdentifier = self._getParameters( 899 iq, 'retract', 'node') 945 def _on_retract(self, request): 946 return self.retract(request) 900 947 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 948 909 return self.retract(requestor, service, nodeIdentifier,910 itemIdentifiers)949 def _on_purge(self, request): 950 return self.purge(request) 911 951 912 952 913 def _onPurge(self, iq): 914 requestor, service, nodeIdentifier = self._getParameters( 915 iq, 'purge', 'node') 916 return self.purge(requestor, service, nodeIdentifier) 953 def _on_delete(self, request): 954 return self.delete(request) 917 955 918 956 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): 957 def _on_affiliationsGet(self, iq): 926 958 raise Unsupported('modify-affiliations') 927 959 928 960 929 def _on AffiliationsSet(self, iq):961 def _on_affiliationsSet(self, iq): 930 962 raise Unsupported('modify-affiliations') 931 963 932 964 933 def _on SubscriptionsGet(self, iq):965 def _on_subscriptionsGet(self, iq): 934 966 raise Unsupported('manage-subscriptions') 935 967 936 968 937 def _on SubscriptionsSet(self, iq):969 def _on_subscriptionsSet(self, iq): 938 970 raise Unsupported('manage-subscriptions') 939 971 940 972 # public methods … … 990 1022 return [] 991 1023 992 1024 993 def publish(self, request or, service, nodeIdentifier, items):1025 def publish(self, request): 994 1026 raise Unsupported('publish') 995 1027 996 1028 997 def subscribe(self, request or, service, nodeIdentifier, subscriber):1029 def subscribe(self, request): 998 1030 raise Unsupported('subscribe') 999 1031 1000 1032 1001 def unsubscribe(self, request or, service, nodeIdentifier, subscriber):1033 def unsubscribe(self, request): 1002 1034 raise Unsupported('subscribe') 1003 1035 1004 1036 1005 def subscriptions(self, request or, service):1037 def subscriptions(self, request): 1006 1038 raise Unsupported('retrieve-subscriptions') 1007 1039 1008 1040 1009 def affiliations(self, request or, service):1041 def affiliations(self, request): 1010 1042 raise Unsupported('retrieve-affiliations') 1011 1043 1012 1044 1013 def create(self, request or, service, nodeIdentifier):1045 def create(self, request): 1014 1046 raise Unsupported('create-nodes') 1015 1047 1016 1048 … … 1018 1050 return {} 1019 1051 1020 1052 1021 def getDefaultConfiguration(self, request or, service, nodeType):1053 def getDefaultConfiguration(self, request): 1022 1054 raise Unsupported('retrieve-default') 1023 1055 1024 1056 1025 def getConfiguration(self, request or, service, nodeIdentifier):1057 def getConfiguration(self, request): 1026 1058 raise Unsupported('config-node') 1027 1059 1028 1060 1029 def setConfiguration(self, request or, service, nodeIdentifier, options):1061 def setConfiguration(self, request): 1030 1062 raise Unsupported('config-node') 1031 1063 1032 1064 1033 def items(self, requestor, service, nodeIdentifier, maxItems, 1034 itemIdentifiers): 1065 def items(self, request): 1035 1066 raise Unsupported('retrieve-items') 1036 1067 1037 1068 1038 def retract(self, request or, service, nodeIdentifier, itemIdentifiers):1069 def retract(self, request): 1039 1070 raise Unsupported('retract-items') 1040 1071 1041 1072 1042 def purge(self, request or, service, nodeIdentifier):1073 def purge(self, request): 1043 1074 raise Unsupported('purge-nodes') 1044 1075 1045 1076 1046 def delete(self, request or, service, nodeIdentifier):1077 def delete(self, request): 1047 1078 raise Unsupported('delete-nodes') -
wokkel/test/test_pubsub.py
diff -r fafe0148a94c wokkel/test/test_pubsub.py
a b 507 507 verify.verifyObject(iwokkel.IPubSubService, self.service) 508 508 509 509 510 def test_connectionMade(self): 511 """ 512 Verify setup of observers in L{pubsub.connectionMade}. 513 """ 514 requests = [] 515 516 def handleRequest(iq): 517 requests.append(iq) 518 519 self.service.xmlstream = self.stub.xmlstream 520 self.service.handleRequest = handleRequest 521 self.service.connectionMade() 522 523 for namespace in (NS_PUBSUB, NS_PUBSUB_OWNER): 524 for stanzaType in ('get', 'set'): 525 iq = domish.Element((None, 'iq')) 526 iq['type'] = stanzaType 527 iq.addElement((namespace, 'pubsub')) 528 self.stub.xmlstream.dispatch(iq) 529 530 self.assertEqual(4, len(requests)) 531 532 510 533 def test_getDiscoInfo(self): 511 534 """ 512 535 Test getDiscoInfo calls getNodeInfo and returns some minimal info. … … 561 584 </iq> 562 585 """ 563 586 564 def publish(request or, service, nodeIdentifier, items):565 self.assertEqual(JID('user@example.org'), request or)566 self.assertEqual(JID('pubsub.example.org'), service)567 self.assertEqual('test', nodeIdentifier)568 self.assertEqual([], items)587 def publish(request): 588 self.assertEqual(JID('user@example.org'), request.sender) 589 self.assertEqual(JID('pubsub.example.org'), request.recipient) 590 self.assertEqual('test', request.nodeIdentifier) 591 self.assertEqual([], request.items) 569 592 return defer.succeed(None) 570 593 571 594 self.service.publish = publish 595 verify.verifyObject(iwokkel.IPubSubService, self.service) 572 596 return self.handleRequest(xml) 597 598 599 def test_onPublishItems(self): 600 """ 601 A publish request with items should pass the items onto C{publish}. 602 """ 603 604 xml = """ 605 <iq type='set' to='pubsub.example.org' 606 from='user@example.org'> 607 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 608 <publish node='test'> 609 <item id="item1"/> 610 <item id="item2"/> 611 </publish> 612 </pubsub> 613 </iq> 614 """ 615 616 def publish(request): 617 self.assertEqual(2, len(request.items)) 618 self.assertEqual(u'item1', request.items[0]["id"]) 619 self.assertEqual(u'item2', request.items[1]["id"]) 620 return defer.succeed(None) 621 622 self.service.publish = publish 623 verify.verifyObject(iwokkel.IPubSubService, self.service) 624 return self.handleRequest(xml) 625 626 627 def test_onSubscribe(self): 628 """ 629 A successful subscription should return the current subscription. 630 """ 631 632 xml = """ 633 <iq type='set' to='pubsub.example.org' 634 from='user@example.org'> 635 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 636 <subscribe node='test' jid='user@example.org/Home'/> 637 </pubsub> 638 </iq> 639 """ 640 641 def subscribe(request): 642 self.assertEqual(JID('user@example.org'), request.sender) 643 self.assertEqual(JID('pubsub.example.org'), request.recipient) 644 self.assertEqual('test', request.nodeIdentifier) 645 self.assertEqual(JID('user@example.org/Home'), request.subscriber) 646 return defer.succeed(pubsub.Subscription(request.nodeIdentifier, 647 request.subscriber, 648 'subscribed')) 649 650 def cb(element): 651 self.assertEqual('pubsub', element.name) 652 self.assertEqual(NS_PUBSUB, element.uri) 653 subscription = element.subscription 654 self.assertEqual(NS_PUBSUB, subscription.uri) 655 self.assertEqual('test', subscription['node']) 656 self.assertEqual('user@example.org/Home', subscription['jid']) 657 self.assertEqual('subscribed', subscription['subscription']) 658 659 self.service.subscribe = subscribe 660 verify.verifyObject(iwokkel.IPubSubService, self.service) 661 d = self.handleRequest(xml) 662 d.addCallback(cb) 663 return d 664 665 666 def test_onSubscribeEmptyNode(self): 667 """ 668 A successful subscription on root node should return no node attribute. 669 """ 670 671 xml = """ 672 <iq type='set' to='pubsub.example.org' 673 from='user@example.org'> 674 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 675 <subscribe jid='user@example.org/Home'/> 676 </pubsub> 677 </iq> 678 """ 679 680 def subscribe(request): 681 self.assertEqual('', request.nodeIdentifier) 682 return defer.succeed(pubsub.Subscription(request.nodeIdentifier, 683 request.subscriber, 684 'subscribed')) 685 686 def cb(element): 687 self.assertFalse(element.subscription.hasAttribute('node')) 688 689 self.service.subscribe = subscribe 690 verify.verifyObject(iwokkel.IPubSubService, self.service) 691 d = self.handleRequest(xml) 692 d.addCallback(cb) 693 return d 694 695 696 def test_onUnsubscribe(self): 697 """ 698 A successful unsubscription should return an empty response. 699 """ 700 701 xml = """ 702 <iq type='set' to='pubsub.example.org' 703 from='user@example.org'> 704 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 705 <unsubscribe node='test' jid='user@example.org/Home'/> 706 </pubsub> 707 </iq> 708 """ 709 710 def unsubscribe(request): 711 self.assertEqual(JID('user@example.org'), request.sender) 712 self.assertEqual(JID('pubsub.example.org'), request.recipient) 713 self.assertEqual('test', request.nodeIdentifier) 714 self.assertEqual(JID('user@example.org/Home'), request.subscriber) 715 return defer.succeed(None) 716 717 def cb(element): 718 self.assertIdentical(None, element) 719 720 self.service.unsubscribe = unsubscribe 721 verify.verifyObject(iwokkel.IPubSubService, self.service) 722 d = self.handleRequest(xml) 723 d.addCallback(cb) 724 return d 573 725 574 726 575 727 def test_onOptionsGet(self): 576 728 """ 577 Subscription options arenot supported.729 Getting subscription options is not supported. 578 730 """ 579 731 580 732 xml = """ 581 733 <iq type='get' to='pubsub.example.org' 734 from='user@example.org'> 735 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 736 <options/> 737 </pubsub> 738 </iq> 739 """ 740 741 def cb(result): 742 self.assertEquals('feature-not-implemented', result.condition) 743 self.assertEquals('unsupported', result.appCondition.name) 744 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 745 746 d = self.handleRequest(xml) 747 self.assertFailure(d, error.StanzaError) 748 d.addCallback(cb) 749 return d 750 751 752 def test_onOptionsSet(self): 753 """ 754 Setting subscription options is not supported. 755 """ 756 757 xml = """ 758 <iq type='set' to='pubsub.example.org' 582 759 from='user@example.org'> 583 760 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 584 761 <options/> … … 627 804 self.assertEqual('subscribed', subscription['subscription']) 628 805 629 806 630 def subscriptions(request or, service):631 self.assertEqual(JID('user@example.org'), request or)632 self.assertEqual(JID('pubsub.example.org'), service)807 def subscriptions(request): 808 self.assertEqual(JID('user@example.org'), request.sender) 809 self.assertEqual(JID('pubsub.example.org'), request.recipient) 633 810 subscription = pubsub.Subscription('test', JID('user@example.org'), 634 811 'subscribed') 635 812 return defer.succeed([subscription]) 636 813 637 814 self.service.subscriptions = subscriptions 815 verify.verifyObject(iwokkel.IPubSubService, self.service) 816 d = self.handleRequest(xml) 817 d.addCallback(cb) 818 return d 819 820 821 def test_onAffiliations(self): 822 """ 823 A subscriptions request should result in 824 L{PubSubService.affiliations} being called and the result prepared 825 for the response. 826 """ 827 828 xml = """ 829 <iq type='get' to='pubsub.example.org' 830 from='user@example.org'> 831 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 832 <affiliations/> 833 </pubsub> 834 </iq> 835 """ 836 837 def cb(element): 838 self.assertEqual('pubsub', element.name) 839 self.assertEqual(NS_PUBSUB, element.uri) 840 self.assertEqual(NS_PUBSUB, element.affiliations.uri) 841 children = list(element.affiliations.elements()) 842 self.assertEqual(1, len(children)) 843 affiliation = children[0] 844 self.assertEqual('affiliation', affiliation.name) 845 self.assertEqual(NS_PUBSUB, affiliation.uri) 846 self.assertEqual('test', affiliation['node']) 847 self.assertEqual('owner', affiliation['affiliation']) 848 849 850 def affiliations(request): 851 self.assertEqual(JID('user@example.org'), request.sender) 852 self.assertEqual(JID('pubsub.example.org'), request.recipient) 853 affiliation = ('test', 'owner') 854 return defer.succeed([affiliation]) 855 856 self.service.affiliations = affiliations 857 verify.verifyObject(iwokkel.IPubSubService, self.service) 858 d = self.handleRequest(xml) 859 d.addCallback(cb) 860 return d 861 862 863 def test_onCreate(self): 864 """ 865 Replies to create node requests don't return the created node. 866 """ 867 868 xml = """ 869 <iq type='set' to='pubsub.example.org' 870 from='user@example.org'> 871 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 872 <create node='mynode'/> 873 </pubsub> 874 </iq> 875 """ 876 877 def create(request): 878 self.assertEqual(JID('user@example.org'), request.sender) 879 self.assertEqual(JID('pubsub.example.org'), request.recipient) 880 self.assertEqual('mynode', request.nodeIdentifier) 881 return defer.succeed(request.nodeIdentifier) 882 883 def cb(element): 884 self.assertIdentical(None, element) 885 886 self.service.create = create 887 verify.verifyObject(iwokkel.IPubSubService, self.service) 888 d = self.handleRequest(xml) 889 d.addCallback(cb) 890 return d 891 892 893 def test_onCreateChanged(self): 894 """ 895 Replies to create node requests return the created node if changed. 896 """ 897 898 xml = """ 899 <iq type='set' to='pubsub.example.org' 900 from='user@example.org'> 901 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 902 <create node='mynode'/> 903 </pubsub> 904 </iq> 905 """ 906 907 def create(request): 908 return defer.succeed(u'myrenamednode') 909 910 def cb(element): 911 self.assertEqual('pubsub', element.name) 912 self.assertEqual(NS_PUBSUB, element.uri) 913 self.assertEqual(NS_PUBSUB, element.create.uri) 914 self.assertEqual(u'myrenamednode', 915 element.create.getAttribute('node')) 916 917 self.service.create = create 918 verify.verifyObject(iwokkel.IPubSubService, self.service) 919 d = self.handleRequest(xml) 920 d.addCallback(cb) 921 return d 922 923 924 def test_onCreateInstant(self): 925 """ 926 Replies to create instant node requests return the created node. 927 """ 928 929 xml = """ 930 <iq type='set' to='pubsub.example.org' 931 from='user@example.org'> 932 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 933 <create/> 934 </pubsub> 935 </iq> 936 """ 937 938 def create(request): 939 self.assertIdentical(None, request.nodeIdentifier) 940 return defer.succeed(u'random') 941 942 def cb(element): 943 self.assertEqual('pubsub', element.name) 944 self.assertEqual(NS_PUBSUB, element.uri) 945 self.assertEqual(NS_PUBSUB, element.create.uri) 946 self.assertEqual(u'random', element.create.getAttribute('node')) 947 948 self.service.create = create 949 verify.verifyObject(iwokkel.IPubSubService, self.service) 638 950 d = self.handleRequest(xml) 639 951 d.addCallback(cb) 640 952 return d … … 665 977 "label": "Deliver payloads with event notifications"} 666 978 } 667 979 668 def getDefaultConfiguration(request or, service, nodeType):669 self.assertEqual(JID('user@example.org'), request or)670 self.assertEqual(JID('pubsub.example.org'), service)671 self.assertEqual('leaf', nodeType)980 def getDefaultConfiguration(request): 981 self.assertEqual(JID('user@example.org'), request.sender) 982 self.assertEqual(JID('pubsub.example.org'), request.recipient) 983 self.assertEqual('leaf', request.nodeType) 672 984 return defer.succeed({}) 673 985 674 986 def cb(element): … … 682 994 self.service.getDefaultConfiguration = getDefaultConfiguration 683 995 verify.verifyObject(iwokkel.IPubSubService, self.service) 684 996 d = self.handleRequest(xml) 997 d.addCallback(cb) 998 return d 999 1000 1001 def test_onDefaultCollection(self): 1002 """ 1003 Responses to default requests should depend on passed node type. 1004 """ 1005 1006 xml = """ 1007 <iq type='get' to='pubsub.example.org' 1008 from='user@example.org'> 1009 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 1010 <default> 1011 <x xmlns='jabber:x:data' type='submit'> 1012 <field var='FORM_TYPE' type='hidden'> 1013 <value>http://jabber.org/protocol/pubsub#node_config</value> 1014 </field> 1015 <field var='pubsub#node_type'> 1016 <value>collection</value> 1017 </field> 1018 </x> 1019 </default> 1020 1021 </pubsub> 1022 </iq> 1023 """ 1024 1025 def getConfigurationOptions(): 1026 return { 1027 "pubsub#deliver_payloads": 1028 {"type": "boolean", 1029 "label": "Deliver payloads with event notifications"} 1030 } 1031 1032 def getDefaultConfiguration(request): 1033 self.assertEqual('collection', request.nodeType) 1034 return defer.succeed({}) 1035 1036 def cb(element): 1037 self.assertEqual('pubsub', element.name) 1038 self.assertEqual(NS_PUBSUB_OWNER, element.uri) 1039 self.assertEqual(NS_PUBSUB_OWNER, element.default.uri) 1040 form = data_form.Form.fromElement(element.default.x) 1041 self.assertEqual(NS_PUBSUB_CONFIG, form.formNamespace) 1042 1043 self.service.getConfigurationOptions = getConfigurationOptions 1044 self.service.getDefaultConfiguration = getDefaultConfiguration 1045 verify.verifyObject(iwokkel.IPubSubService, self.service) 1046 d = self.handleRequest(xml) 1047 d.addCallback(cb) 1048 return d 1049 1050 1051 def test_onDefaultUnknownNodeType(self): 1052 """ 1053 A default request should result in 1054 L{PubSubService.getDefaultConfiguration} being called. 1055 """ 1056 1057 xml = """ 1058 <iq type='get' to='pubsub.example.org' 1059 from='user@example.org'> 1060 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 1061 <default> 1062 <x xmlns='jabber:x:data' type='submit'> 1063 <field var='FORM_TYPE' type='hidden'> 1064 <value>http://jabber.org/protocol/pubsub#node_config</value> 1065 </field> 1066 <field var='pubsub#node_type'> 1067 <value>unknown</value> 1068 </field> 1069 </x> 1070 </default> 1071 1072 </pubsub> 1073 </iq> 1074 """ 1075 1076 def getDefaultConfiguration(request): 1077 self.fail("Unexpected call to getConfiguration") 1078 1079 def cb(result): 1080 self.assertEquals('not-acceptable', result.condition) 1081 1082 self.service.getDefaultConfiguration = getDefaultConfiguration 1083 verify.verifyObject(iwokkel.IPubSubService, self.service) 1084 d = self.handleRequest(xml) 1085 self.assertFailure(d, error.StanzaError) 685 1086 d.addCallback(cb) 686 1087 return d 687 1088 … … 714 1115 "label": "Owner of the node"} 715 1116 } 716 1117 717 def getConfiguration(request or, service, nodeIdentifier):718 self.assertEqual(JID('user@example.org'), request or)719 self.assertEqual(JID('pubsub.example.org'), service)720 self.assertEqual('test', nodeIdentifier)1118 def getConfiguration(request): 1119 self.assertEqual(JID('user@example.org'), request.sender) 1120 self.assertEqual(JID('pubsub.example.org'), request.recipient) 1121 self.assertEqual('test', request.nodeIdentifier) 721 1122 722 1123 return defer.succeed({'pubsub#deliver_payloads': '0', 723 1124 'pubsub#persist_items': '1', 724 'pubsub#owner': JID('user@example.org')}) 1125 'pubsub#owner': JID('user@example.org'), 1126 'x-myfield': ['a', 'b']}) 725 1127 726 1128 def cb(element): 727 1129 self.assertEqual('pubsub', element.name) … … 749 1151 field.typeCheck() 750 1152 self.assertEqual(JID('user@example.org'), field.value) 751 1153 1154 self.assertNotIn('x-myfield', fields) 1155 1156 752 1157 self.service.getConfigurationOptions = getConfigurationOptions 753 1158 self.service.getConfiguration = getConfiguration 1159 verify.verifyObject(iwokkel.IPubSubService, self.service) 754 1160 d = self.handleRequest(xml) 755 1161 d.addCallback(cb) 756 1162 return d … … 789 1195 "label": "Deliver payloads with event notifications"} 790 1196 } 791 1197 792 def setConfiguration(request or, service, nodeIdentifier, options):793 self.assertEqual(JID('user@example.org'), request or)794 self.assertEqual(JID('pubsub.example.org'), service)795 self.assertEqual('test', nodeIdentifier)1198 def setConfiguration(request): 1199 self.assertEqual(JID('user@example.org'), request.sender) 1200 self.assertEqual(JID('pubsub.example.org'), request.recipient) 1201 self.assertEqual('test', request.nodeIdentifier) 796 1202 self.assertEqual({'pubsub#deliver_payloads': False, 797 'pubsub#persist_items': True}, options)1203 'pubsub#persist_items': True}, request.options) 798 1204 return defer.succeed(None) 799 1205 800 1206 self.service.getConfigurationOptions = getConfigurationOptions 801 1207 self.service.setConfiguration = setConfiguration 1208 verify.verifyObject(iwokkel.IPubSubService, self.service) 802 1209 return self.handleRequest(xml) 803 1210 804 1211 … … 823 1230 </iq> 824 1231 """ 825 1232 826 def setConfiguration(request or, service, nodeIdentifier, options):1233 def setConfiguration(request): 827 1234 self.fail("Unexpected call to setConfiguration") 828 1235 829 1236 self.service.setConfiguration = setConfiguration 1237 verify.verifyObject(iwokkel.IPubSubService, self.service) 830 1238 return self.handleRequest(xml) 831 1239 832 1240 … … 862 1270 "label": "Deliver payloads with event notifications"} 863 1271 } 864 1272 865 def setConfiguration(requestor, service, nodeIdentifier, options): 866 self.assertEquals(['pubsub#deliver_payloads'], options.keys()) 1273 def setConfiguration(request): 1274 self.assertEquals(['pubsub#deliver_payloads'], 1275 request.options.keys()) 867 1276 868 1277 self.service.getConfigurationOptions = getConfigurationOptions 869 1278 self.service.setConfiguration = setConfiguration 1279 verify.verifyObject(iwokkel.IPubSubService, self.service) 870 1280 return self.handleRequest(xml) 1281 1282 1283 def test_onConfigureSetBadFormType(self): 1284 """ 1285 On a node configuration set request unknown fields should be ignored. 1286 """ 1287 1288 xml = """ 1289 <iq type='set' to='pubsub.example.org' 1290 from='user@example.org'> 1291 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 1292 <configure node='test'> 1293 <x xmlns='jabber:x:data' type='result'> 1294 <field var='FORM_TYPE' type='hidden'> 1295 <value>http://jabber.org/protocol/pubsub#node_config</value> 1296 </field> 1297 <field var='pubsub#deliver_payloads'><value>0</value></field> 1298 <field var='x-myfield'><value>1</value></field> 1299 </x> 1300 </configure> 1301 </pubsub> 1302 </iq> 1303 """ 1304 1305 def cb(result): 1306 self.assertEquals('bad-request', result.condition) 1307 1308 d = self.handleRequest(xml) 1309 self.assertFailure(d, error.StanzaError) 1310 d.addCallback(cb) 1311 return d 871 1312 872 1313 873 1314 def test_onItems(self): … … 883 1324 </iq> 884 1325 """ 885 1326 886 def items(request or, service, nodeIdentifier, maxItems, items):887 self.assertEqual(JID('user@example.org'), request or)888 self.assertEqual(JID('pubsub.example.org'), service)889 self.assertEqual('test', nodeIdentifier)890 self.assertIdentical(None, maxItems)891 self.assertEqual([], items)1327 def items(request): 1328 self.assertEqual(JID('user@example.org'), request.sender) 1329 self.assertEqual(JID('pubsub.example.org'), request.recipient) 1330 self.assertEqual('test', request.nodeIdentifier) 1331 self.assertIdentical(None, request.maxItems) 1332 self.assertEqual([], request.itemIdentifiers) 892 1333 return defer.succeed([pubsub.Item('current')]) 893 1334 894 1335 def cb(element): … … 925 1366 </iq> 926 1367 """ 927 1368 928 def retract(request or, service, nodeIdentifier, itemIdentifiers):929 self.assertEqual(JID('user@example.org'), request or)930 self.assertEqual(JID('pubsub.example.org'), service)931 self.assertEqual('test', nodeIdentifier)932 self.assertEqual(['item1', 'item2'], itemIdentifiers)1369 def retract(request): 1370 self.assertEqual(JID('user@example.org'), request.sender) 1371 self.assertEqual(JID('pubsub.example.org'), request.recipient) 1372 self.assertEqual('test', request.nodeIdentifier) 1373 self.assertEqual(['item1', 'item2'], request.itemIdentifiers) 933 1374 return defer.succeed(None) 934 1375 935 1376 self.service.retract = retract … … 951 1392 </iq> 952 1393 """ 953 1394 954 def purge(request or, service, nodeIdentifier):955 self.assertEqual(JID('user@example.org'), request or)956 self.assertEqual(JID('pubsub.example.org'), service)957 self.assertEqual('test', nodeIdentifier)1395 def purge(request): 1396 self.assertEqual(JID('user@example.org'), request.sender) 1397 self.assertEqual(JID('pubsub.example.org'), request.recipient) 1398 self.assertEqual('test', request.nodeIdentifier) 958 1399 return defer.succeed(None) 959 1400 960 1401 self.service.purge = purge … … 976 1417 </iq> 977 1418 """ 978 1419 979 def delete(request or, service, nodeIdentifier):980 self.assertEqual(JID('user@example.org'), request or)981 self.assertEqual(JID('pubsub.example.org'), service)982 self.assertEqual('test', nodeIdentifier)1420 def delete(request): 1421 self.assertEqual(JID('user@example.org'), request.sender) 1422 self.assertEqual(JID('pubsub.example.org'), request.recipient) 1423 self.assertEqual('test', request.nodeIdentifier) 983 1424 return defer.succeed(None) 984 1425 985 1426 self.service.delete = delete … … 1031 1472 self.assertEqual(NS_PUBSUB_EVENT, message.event.delete.redirect.uri) 1032 1473 self.assertTrue(message.event.delete.redirect.hasAttribute('uri')) 1033 1474 self.assertEqual(redirectURI, message.event.delete.redirect['uri']) 1475 1476 1477 def test_onSubscriptionsGet(self): 1478 """ 1479 Getting subscription options is not supported. 1480 """ 1481 1482 xml = """ 1483 <iq type='get' to='pubsub.example.org' 1484 from='user@example.org'> 1485 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 1486 <subscriptions/> 1487 </pubsub> 1488 </iq> 1489 """ 1490 1491 def cb(result): 1492 self.assertEquals('feature-not-implemented', result.condition) 1493 self.assertEquals('unsupported', result.appCondition.name) 1494 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 1495 self.assertEquals('manage-subscriptions', 1496 result.appCondition['feature']) 1497 1498 d = self.handleRequest(xml) 1499 self.assertFailure(d, error.StanzaError) 1500 d.addCallback(cb) 1501 return d 1502 1503 1504 def test_onSubscriptionsSet(self): 1505 """ 1506 Setting subscription options is not supported. 1507 """ 1508 1509 xml = """ 1510 <iq type='set' to='pubsub.example.org' 1511 from='user@example.org'> 1512 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 1513 <subscriptions/> 1514 </pubsub> 1515 </iq> 1516 """ 1517 1518 def cb(result): 1519 self.assertEquals('feature-not-implemented', result.condition) 1520 self.assertEquals('unsupported', result.appCondition.name) 1521 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 1522 self.assertEquals('manage-subscriptions', 1523 result.appCondition['feature']) 1524 1525 d = self.handleRequest(xml) 1526 self.assertFailure(d, error.StanzaError) 1527 d.addCallback(cb) 1528 return d 1529 1530 1531 def test_onAffiliationsGet(self): 1532 """ 1533 Getting subscription options is not supported. 1534 """ 1535 1536 xml = """ 1537 <iq type='get' to='pubsub.example.org' 1538 from='user@example.org'> 1539 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 1540 <affiliations/> 1541 </pubsub> 1542 </iq> 1543 """ 1544 1545 def cb(result): 1546 self.assertEquals('feature-not-implemented', result.condition) 1547 self.assertEquals('unsupported', result.appCondition.name) 1548 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 1549 self.assertEquals('modify-affiliations', 1550 result.appCondition['feature']) 1551 1552 d = self.handleRequest(xml) 1553 self.assertFailure(d, error.StanzaError) 1554 d.addCallback(cb) 1555 return d 1556 1557 1558 def test_onAffiliationsSet(self): 1559 """ 1560 Setting subscription options is not supported. 1561 """ 1562 1563 xml = """ 1564 <iq type='set' to='pubsub.example.org' 1565 from='user@example.org'> 1566 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 1567 <affiliations/> 1568 </pubsub> 1569 </iq> 1570 """ 1571 1572 def cb(result): 1573 self.assertEquals('feature-not-implemented', result.condition) 1574 self.assertEquals('unsupported', result.appCondition.name) 1575 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 1576 self.assertEquals('modify-affiliations', 1577 result.appCondition['feature']) 1578 1579 d = self.handleRequest(xml) 1580 self.assertFailure(d, error.StanzaError) 1581 d.addCallback(cb) 1582 return d 1583 1584 1585 def test_publish(self): 1586 """ 1587 Non-overridden L{PubSubService.publish} yields unsupported error. 1588 """ 1589 1590 xml = """ 1591 <iq type='set' to='pubsub.example.org' 1592 from='user@example.org'> 1593 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1594 <publish node='mynode'/> 1595 </pubsub> 1596 </iq> 1597 """ 1598 1599 def cb(result): 1600 self.assertEquals('feature-not-implemented', result.condition) 1601 self.assertEquals('unsupported', result.appCondition.name) 1602 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 1603 self.assertEquals('publish', result.appCondition['feature']) 1604 1605 d = self.handleRequest(xml) 1606 self.assertFailure(d, error.StanzaError) 1607 d.addCallback(cb) 1608 return d 1609 1610 1611 def test_subscribe(self): 1612 """ 1613 Non-overridden L{PubSubService.subscribe} yields unsupported error. 1614 """ 1615 1616 xml = """ 1617 <iq type='set' to='pubsub.example.org' 1618 from='user@example.org'> 1619 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1620 <subscribe node='test' jid='user@example.org/Home'/> 1621 </pubsub> 1622 </iq> 1623 """ 1624 1625 def cb(result): 1626 self.assertEquals('feature-not-implemented', result.condition) 1627 self.assertEquals('unsupported', result.appCondition.name) 1628 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 1629 self.assertEquals('subscribe', result.appCondition['feature']) 1630 1631 d = self.handleRequest(xml) 1632 self.assertFailure(d, error.StanzaError) 1633 d.addCallback(cb) 1634 return d 1635 1636 1637 def test_unsubscribe(self): 1638 """ 1639 Non-overridden L{PubSubService.unsubscribe} yields unsupported error. 1640 """ 1641 1642 xml = """ 1643 <iq type='set' to='pubsub.example.org' 1644 from='user@example.org'> 1645 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1646 <unsubscribe node='test' jid='user@example.org/Home'/> 1647 </pubsub> 1648 </iq> 1649 """ 1650 1651 def cb(result): 1652 self.assertEquals('feature-not-implemented', result.condition) 1653 self.assertEquals('unsupported', result.appCondition.name) 1654 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 1655 self.assertEquals('subscribe', result.appCondition['feature']) 1656 1657 d = self.handleRequest(xml) 1658 self.assertFailure(d, error.StanzaError) 1659 d.addCallback(cb) 1660 return d 1661 1662 1663 def test_subscriptions(self): 1664 """ 1665 Non-overridden L{PubSubService.subscriptions} yields unsupported error. 1666 """ 1667 1668 xml = """ 1669 <iq type='get' to='pubsub.example.org' 1670 from='user@example.org'> 1671 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1672 <subscriptions/> 1673 </pubsub> 1674 </iq> 1675 """ 1676 1677 def cb(result): 1678 self.assertEquals('feature-not-implemented', result.condition) 1679 self.assertEquals('unsupported', result.appCondition.name) 1680 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 1681 self.assertEquals('retrieve-subscriptions', 1682 result.appCondition['feature']) 1683 1684 d = self.handleRequest(xml) 1685 self.assertFailure(d, error.StanzaError) 1686 d.addCallback(cb) 1687 return d 1688 1689 1690 def test_affiliations(self): 1691 """ 1692 Non-overridden L{PubSubService.affiliations} yields unsupported error. 1693 """ 1694 1695 xml = """ 1696 <iq type='get' to='pubsub.example.org' 1697 from='user@example.org'> 1698 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1699 <affiliations/> 1700 </pubsub> 1701 </iq> 1702 """ 1703 1704 def cb(result): 1705 self.assertEquals('feature-not-implemented', result.condition) 1706 self.assertEquals('unsupported', result.appCondition.name) 1707 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 1708 self.assertEquals('retrieve-affiliations', 1709 result.appCondition['feature']) 1710 1711 d = self.handleRequest(xml) 1712 self.assertFailure(d, error.StanzaError) 1713 d.addCallback(cb) 1714 return d 1715 1716 1717 def test_create(self): 1718 """ 1719 Non-overridden L{PubSubService.create} yields unsupported error. 1720 """ 1721 1722 xml = """ 1723 <iq type='set' to='pubsub.example.org' 1724 from='user@example.org'> 1725 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1726 <create node='mynode'/> 1727 </pubsub> 1728 </iq> 1729 """ 1730 1731 def cb(result): 1732 self.assertEquals('feature-not-implemented', result.condition) 1733 self.assertEquals('unsupported', result.appCondition.name) 1734 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 1735 self.assertEquals('create-nodes', result.appCondition['feature']) 1736 1737 d = self.handleRequest(xml) 1738 self.assertFailure(d, error.StanzaError) 1739 d.addCallback(cb) 1740 return d 1741 1742 1743 def test_getDefaultConfiguration(self): 1744 """ 1745 Non-overridden L{PubSubService.getDefaultConfiguration} yields 1746 unsupported error. 1747 """ 1748 1749 xml = """ 1750 <iq type='get' to='pubsub.example.org' 1751 from='user@example.org'> 1752 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 1753 <default/> 1754 </pubsub> 1755 </iq> 1756 """ 1757 1758 def cb(result): 1759 self.assertEquals('feature-not-implemented', result.condition) 1760 self.assertEquals('unsupported', result.appCondition.name) 1761 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 1762 self.assertEquals('retrieve-default', result.appCondition['feature']) 1763 1764 d = self.handleRequest(xml) 1765 self.assertFailure(d, error.StanzaError) 1766 d.addCallback(cb) 1767 return d 1768 1769 1770 def test_getConfiguration(self): 1771 """ 1772 Non-overridden L{PubSubService.getConfiguration} yields unsupported 1773 error. 1774 """ 1775 1776 xml = """ 1777 <iq type='get' to='pubsub.example.org' 1778 from='user@example.org'> 1779 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 1780 <configure/> 1781 </pubsub> 1782 </iq> 1783 """ 1784 1785 def cb(result): 1786 self.assertEquals('feature-not-implemented', result.condition) 1787 self.assertEquals('unsupported', result.appCondition.name) 1788 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 1789 self.assertEquals('config-node', result.appCondition['feature']) 1790 1791 d = self.handleRequest(xml) 1792 self.assertFailure(d, error.StanzaError) 1793 d.addCallback(cb) 1794 return d 1795 1796 1797 def test_setConfiguration(self): 1798 """ 1799 Non-overridden L{PubSubService.setConfiguration} yields unsupported 1800 error. 1801 """ 1802 1803 xml = """ 1804 <iq type='set' to='pubsub.example.org' 1805 from='user@example.org'> 1806 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 1807 <configure node='test'> 1808 <x xmlns='jabber:x:data' type='submit'> 1809 <field var='FORM_TYPE' type='hidden'> 1810 <value>http://jabber.org/protocol/pubsub#node_config</value> 1811 </field> 1812 <field var='pubsub#deliver_payloads'><value>0</value></field> 1813 <field var='pubsub#persist_items'><value>1</value></field> 1814 </x> 1815 </configure> 1816 </pubsub> 1817 </iq> 1818 """ 1819 1820 def cb(result): 1821 self.assertEquals('feature-not-implemented', result.condition) 1822 self.assertEquals('unsupported', result.appCondition.name) 1823 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 1824 self.assertEquals('config-node', result.appCondition['feature']) 1825 1826 d = self.handleRequest(xml) 1827 self.assertFailure(d, error.StanzaError) 1828 d.addCallback(cb) 1829 return d 1830 1831 1832 def test_items(self): 1833 """ 1834 Non-overridden L{PubSubService.items} yields unsupported error. 1835 """ 1836 xml = """ 1837 <iq type='get' to='pubsub.example.org' 1838 from='user@example.org'> 1839 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1840 <items node='test'/> 1841 </pubsub> 1842 </iq> 1843 """ 1844 1845 def cb(result): 1846 self.assertEquals('feature-not-implemented', result.condition) 1847 self.assertEquals('unsupported', result.appCondition.name) 1848 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 1849 self.assertEquals('retrieve-items', result.appCondition['feature']) 1850 1851 d = self.handleRequest(xml) 1852 self.assertFailure(d, error.StanzaError) 1853 d.addCallback(cb) 1854 return d 1855 1856 1857 def test_retract(self): 1858 """ 1859 Non-overridden L{PubSubService.retract} yields unsupported error. 1860 """ 1861 xml = """ 1862 <iq type='set' to='pubsub.example.org' 1863 from='user@example.org'> 1864 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1865 <retract node='test'> 1866 <item id='item1'/> 1867 <item id='item2'/> 1868 </retract> 1869 </pubsub> 1870 </iq> 1871 """ 1872 1873 def cb(result): 1874 self.assertEquals('feature-not-implemented', result.condition) 1875 self.assertEquals('unsupported', result.appCondition.name) 1876 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 1877 self.assertEquals('retract-items', result.appCondition['feature']) 1878 1879 d = self.handleRequest(xml) 1880 self.assertFailure(d, error.StanzaError) 1881 d.addCallback(cb) 1882 return d 1883 1884 1885 def test_purge(self): 1886 """ 1887 Non-overridden L{PubSubService.purge} yields unsupported error. 1888 """ 1889 xml = """ 1890 <iq type='set' to='pubsub.example.org' 1891 from='user@example.org'> 1892 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 1893 <purge node='test'/> 1894 </pubsub> 1895 </iq> 1896 """ 1897 1898 def cb(result): 1899 self.assertEquals('feature-not-implemented', result.condition) 1900 self.assertEquals('unsupported', result.appCondition.name) 1901 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 1902 self.assertEquals('purge-nodes', result.appCondition['feature']) 1903 1904 d = self.handleRequest(xml) 1905 self.assertFailure(d, error.StanzaError) 1906 d.addCallback(cb) 1907 return d 1908 1909 1910 def test_delete(self): 1911 """ 1912 Non-overridden L{PubSubService.delete} yields unsupported error. 1913 """ 1914 xml = """ 1915 <iq type='set' to='pubsub.example.org' 1916 from='user@example.org'> 1917 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 1918 <delete node='test'/> 1919 </pubsub> 1920 </iq> 1921 """ 1922 1923 def cb(result): 1924 self.assertEquals('feature-not-implemented', result.condition) 1925 self.assertEquals('unsupported', result.appCondition.name) 1926 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 1927 self.assertEquals('delete-nodes', result.appCondition['feature']) 1928 1929 d = self.handleRequest(xml) 1930 self.assertFailure(d, error.StanzaError) 1931 d.addCallback(cb) 1932 return d
Note: See TracBrowser
for help on using the repository browser.