source:
ralphm-patches/pubsub_request.patch
@
6:46e82ac33f4a
Last change on this file since 6:46e82ac33f4a was 6:46e82ac33f4a, checked in by Ralph Meijer <ralphm@…>, 13 years ago | |
---|---|
File size: 106.9 KB |
-
wokkel/generic.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 0bfc0b2a633c wokkel/generic.py
a b 10 10 from zope.interface import implements 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 16 16 … … 162 162 self.sink.send = lambda obj: self.source.dispatch(obj) 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 167 198 -
wokkel/iwokkel.py
diff -r 0bfc0b2a633c 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 """ 393 371 372 394 373 def getConfigurationOptions(): 395 374 """ 396 375 Retrieve all known node configuration options. … … 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 0bfc0b2a633c wokkel/pubsub.py
a b 16 16 from twisted.words.protocols.jabber import jid, error, xmlstream 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 22 22 … … 31 31 NS_PUBSUB_OWNER = NS_PUBSUB + "#owner" 32 32 NS_PUBSUB_NODE_CONFIG = NS_PUBSUB + "#node_config" 33 33 NS_PUBSUB_META_DATA = NS_PUBSUB + "#meta-data" 34 NS_PUBSUB_SUBSCRIBE_OPTIONS = NS_PUBSUB + "#subscribe_options" 34 35 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 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): 73 42 """ … … 98 67 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 109 84 … … 167 142 168 143 169 144 170 class _PubSubRequest(xmlstream.IQ):145 class PubSubRequest(generic.Stanza): 171 146 """ 172 Publishsubscribe request.147 A publish-subscribe request. 173 148 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}. 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} 183 180 """ 184 181 185 def __init__(self, xs, verb, namespace=NS_PUBSUB, method='set'): 186 xmlstream.IQ.__init__(self, xs, method) 187 self.addElement((namespace, 'pubsub')) 182 verb = None 188 183 189 self.command = self.pubsub.addElement(verb) 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 190 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 } 191 217 192 def send(self, to): 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): 193 250 """ 194 Send out request.251 Find a Data Form. 195 252 196 Extends L{xmlstream.IQ.send} by requiring the C{to} parameter to be 197 a L{JID} instance. 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 198 258 199 @param to: Entity to send the request to. 200 @type to: L{JID} 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): 201 273 """ 202 destination = to.full() 203 return xmlstream.IQ.send(self, destination) 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 206 503 … … 336 633 @param nodeIdentifier: Optional suggestion for the id of the node. 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): 346 641 try: … … 350 645 new_node = nodeIdentifier 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 356 653 def deleteNode(self, service, nodeIdentifier): … … 362 659 @param nodeIdentifier: The identifier of the node. 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 370 668 def subscribe(self, service, nodeIdentifier, subscriber): … … 379 677 will get notifications of new published items. 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): 388 686 subscription = iq.pubsub.subscription["subscription"] … … 397 695 # yielded a stanza error. 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 403 703 def unsubscribe(self, service, nodeIdentifier, subscriber): … … 411 711 @param subscriber: The entity to unsubscribe from the node. 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 421 721 def publish(self, service, nodeIdentifier, items=None): … … 429 729 @param items: Optional list of L{Item}s to publish. 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 441 739 def items(self, service, nodeIdentifier, maxItems=None): … … 449 747 @param maxItems: Optional limit on the number of retrieved items. 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): 459 757 items = [] … … 462 760 items.append(element) 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 468 768 … … 497 797 implements(IPubSubService) 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 523 803 … … 530 810 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 539 816 def getDiscoInfo(self, requestor, target, nodeIdentifier): … … 585 862 return d 586 863 587 864 588 def _findForm(self, element, formNamespace): 589 if not element: 590 return None 865 def _onPubSubRequest(self, iq): 866 request = PubSubRequest.fromElement(iq) 867 handler = getattr(self, '_on_%s' % request.verb) 868 return handler(request) 591 869 592 form = None593 for child in element.elements():594 try:595 form = data_form.Form.fromElement(child)596 except data_form.Error:597 continue598 870 599 if form.formNamespace != NS_PUBSUB_NODE_CONFIG:600 continue871 def _on_publish(self, request): 872 return self.publish(request) 601 873 602 return form603 874 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') 875 def _on_subscribe(self, request): 674 876 675 877 def toResponse(result): 676 878 response = domish.Element((NS_PUBSUB, "pubsub")) … … 681 883 subscription["subscription"] = result.state 682 884 return response 683 885 684 d = self.subscribe(request or, service, nodeIdentifier, subscriber)886 d = self.subscribe(request) 685 887 d.addCallback(toResponse) 686 888 return d 687 889 688 890 689 def _onUnsubscribe(self, iq): 690 requestor, service, nodeIdentifier, subscriber = self._getParameters( 691 iq, 'unsubscribe', 'nodeOrEmpty', 'jid') 891 def _on_unsubscribe(self, request): 892 return self.unsubscribe(request) 692 893 693 return self.unsubscribe(requestor, service, nodeIdentifier, subscriber)694 894 695 696 def _onOptionsGet(self, iq): 895 def _on_optionsGet(self, request): 697 896 raise Unsupported('subscription-options') 698 897 699 898 700 def _on OptionsSet(self, iq):899 def _on_optionsSet(self, request): 701 900 raise Unsupported('subscription-options') 702 901 703 902 704 def _onSubscriptions(self, iq): 705 requestor, service = self._getParameters(iq) 903 def _on_subscriptions(self, request): 706 904 707 905 def toResponse(result): 708 906 response = domish.Element((NS_PUBSUB, 'pubsub')) … … 714 912 item['subscription'] = subscription.state 715 913 return response 716 914 717 d = self.subscriptions(request or, service)915 d = self.subscriptions(request) 718 916 d.addCallback(toResponse) 719 917 return d 720 918 721 919 722 def _onAffiliations(self, iq): 723 requestor, service = self._getParameters(iq) 920 def _on_affiliations(self, request): 724 921 725 922 def toResponse(result): 726 923 response = domish.Element((NS_PUBSUB, 'pubsub')) … … 733 930 734 931 return response 735 932 736 d = self.affiliations(request or, service)933 d = self.affiliations(request) 737 934 d.addCallback(toResponse) 738 935 return d 739 936 740 937 741 def _onCreate(self, iq): 742 requestor, service = self._getParameters(iq) 743 nodeIdentifier = iq.pubsub.create.getAttribute("node") 938 def _on_create(self, request): 744 939 745 940 def toResponse(result): 746 if not nodeIdentifier ornodeIdentifier != result:941 if not request.nodeIdentifier or request.nodeIdentifier != result: 747 942 response = domish.Element((NS_PUBSUB, 'pubsub')) 748 943 create = response.addElement('create') 749 944 create['node'] = result … … 751 946 else: 752 947 return None 753 948 754 d = self.create(request or, service, nodeIdentifier)949 d = self.create(request) 755 950 d.addCallback(toResponse) 756 951 return d 757 952 … … 771 966 fields.append(data_form.Field.fromDict(option)) 772 967 return fields 773 968 969 774 970 def _formFromConfiguration(self, values): 775 971 options = self.getConfigurationOptions() 776 972 fields = self._makeFields(options, values) … … 780 976 781 977 return form 782 978 979 783 980 def _checkConfiguration(self, values): 784 981 options = self.getConfigurationOptions() 785 982 processedValues = {} … … 805 1002 return processedValues 806 1003 807 1004 808 def _onDefault(self, iq): 809 requestor, service = self._getParameters(iq) 1005 def _on_default(self, request): 810 1006 811 1007 def toResponse(options): 812 1008 response = domish.Element((NS_PUBSUB_OWNER, "pubsub")) … … 814 1010 default.addChild(self._formFromConfiguration(options).toElement()) 815 1011 return response 816 1012 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'): 1013 if request.nodeType not in ('leaf', 'collection'): 822 1014 return defer.fail(error.StanzaError('not-acceptable')) 823 1015 824 d = self.getDefaultConfiguration(request or, service, nodeType)1016 d = self.getDefaultConfiguration(request) 825 1017 d.addCallback(toResponse) 826 1018 return d 827 1019 828 1020 829 def _onConfigureGet(self, iq): 830 requestor, service, nodeIdentifier = self._getParameters( 831 iq, 'configure', 'nodeOrEmpty') 832 1021 def _on_configureGet(self, request): 833 1022 def toResponse(options): 834 1023 response = domish.Element((NS_PUBSUB_OWNER, "pubsub")) 835 1024 configure = response.addElement("configure") 836 configure.addChild(self._formFromConfiguration(options).toElement()) 1025 form = self._formFromConfiguration(options) 1026 configure.addChild(form.toElement()) 837 1027 838 if nodeIdentifier:839 configure["node"] = nodeIdentifier1028 if request.nodeIdentifier: 1029 configure["node"] = request.nodeIdentifier 840 1030 841 1031 return response 842 1032 843 d = self.getConfiguration(request or, service, nodeIdentifier)1033 d = self.getConfiguration(request) 844 1034 d.addCallback(toResponse) 845 1035 return d 846 1036 847 1037 848 def _onConfigureSet(self, iq): 849 requestor, service, nodeIdentifier = self._getParameters( 850 iq, 'configure', 'nodeOrEmpty') 1038 def _on_configureSet(self, request): 1039 if request.options: 1040 request.options = self._checkConfiguration(request.options) 1041 return self.setConfiguration(request) 1042 else: 1043 return None 851 1044 852 # Search configuration form with correct FORM_TYPE and process it853 1045 854 form = self._findForm(iq.pubsub.configure, NS_PUBSUB_NODE_CONFIG)855 1046 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() 1047 def _on_items(self, request): 879 1048 880 1049 def toResponse(result): 881 1050 response = domish.Element((NS_PUBSUB, 'pubsub')) 882 1051 items = response.addElement('items') 883 if nodeIdentifier: 884 items["node"] = nodeIdentifier 1052 items["node"] = request.nodeIdentifier 885 1053 886 1054 for item in result: 887 1055 items.addChild(item) 888 1056 889 1057 return response 890 1058 891 d = self.items(requestor, service, nodeIdentifier, maxItems, 892 itemIdentifiers) 1059 d = self.items(request) 893 1060 d.addCallback(toResponse) 894 1061 return d 895 1062 896 1063 897 def _onRetract(self, iq): 898 requestor, service, nodeIdentifier = self._getParameters( 899 iq, 'retract', 'node') 1064 def _on_retract(self, request): 1065 return self.retract(request) 900 1066 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 1067 909 return self.retract(requestor, service, nodeIdentifier,910 itemIdentifiers)1068 def _on_purge(self, request): 1069 return self.purge(request) 911 1070 912 1071 913 def _onPurge(self, iq): 914 requestor, service, nodeIdentifier = self._getParameters( 915 iq, 'purge', 'node') 916 return self.purge(requestor, service, nodeIdentifier) 1072 def _on_delete(self, request): 1073 return self.delete(request) 917 1074 918 1075 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): 1076 def _on_affiliationsGet(self, iq): 926 1077 raise Unsupported('modify-affiliations') 927 1078 928 1079 929 def _on AffiliationsSet(self, iq):1080 def _on_affiliationsSet(self, iq): 930 1081 raise Unsupported('modify-affiliations') 931 1082 932 1083 933 def _on SubscriptionsGet(self, iq):1084 def _on_subscriptionsGet(self, iq): 934 1085 raise Unsupported('manage-subscriptions') 935 1086 936 1087 937 def _on SubscriptionsSet(self, iq):1088 def _on_subscriptionsSet(self, iq): 938 1089 raise Unsupported('manage-subscriptions') 939 1090 940 1091 # public methods … … 990 1141 return [] 991 1142 992 1143 993 def publish(self, request or, service, nodeIdentifier, items):1144 def publish(self, request): 994 1145 raise Unsupported('publish') 995 1146 996 1147 997 def subscribe(self, request or, service, nodeIdentifier, subscriber):1148 def subscribe(self, request): 998 1149 raise Unsupported('subscribe') 999 1150 1000 1151 1001 def unsubscribe(self, request or, service, nodeIdentifier, subscriber):1152 def unsubscribe(self, request): 1002 1153 raise Unsupported('subscribe') 1003 1154 1004 1155 1005 def subscriptions(self, request or, service):1156 def subscriptions(self, request): 1006 1157 raise Unsupported('retrieve-subscriptions') 1007 1158 1008 1159 1009 def affiliations(self, request or, service):1160 def affiliations(self, request): 1010 1161 raise Unsupported('retrieve-affiliations') 1011 1162 1012 1163 1013 def create(self, request or, service, nodeIdentifier):1164 def create(self, request): 1014 1165 raise Unsupported('create-nodes') 1015 1166 1016 1167 … … 1018 1169 return {} 1019 1170 1020 1171 1021 def getDefaultConfiguration(self, request or, service, nodeType):1172 def getDefaultConfiguration(self, request): 1022 1173 raise Unsupported('retrieve-default') 1023 1174 1024 1175 1025 def getConfiguration(self, request or, service, nodeIdentifier):1176 def getConfiguration(self, request): 1026 1177 raise Unsupported('config-node') 1027 1178 1028 1179 1029 def setConfiguration(self, request or, service, nodeIdentifier, options):1180 def setConfiguration(self, request): 1030 1181 raise Unsupported('config-node') 1031 1182 1032 1183 1033 def items(self, requestor, service, nodeIdentifier, maxItems, 1034 itemIdentifiers): 1184 def items(self, request): 1035 1185 raise Unsupported('retrieve-items') 1036 1186 1037 1187 1038 def retract(self, request or, service, nodeIdentifier, itemIdentifiers):1188 def retract(self, request): 1039 1189 raise Unsupported('retract-items') 1040 1190 1041 1191 1042 def purge(self, request or, service, nodeIdentifier):1192 def purge(self, request): 1043 1193 raise Unsupported('purge-nodes') 1044 1194 1045 1195 1046 def delete(self, request or, service, nodeIdentifier):1196 def delete(self, request): 1047 1197 raise Unsupported('delete-nodes') -
wokkel/test/test_pubsub.py
diff -r 0bfc0b2a633c wokkel/test/test_pubsub.py
a b 14 14 from twisted.words.protocols.jabber.jid import JID 15 15 16 16 from wokkel import data_form, iwokkel, pubsub, shim 17 from wokkel.generic import parseXml 17 18 from wokkel.test.helpers import TestableRequestHandlerMixin, XmlStreamStub 18 19 19 20 try: … … 490 491 491 492 492 493 494 class PubSubRequestTest(unittest.TestCase): 495 496 def test_fromElementPublish(self): 497 """ 498 Test parsing a publish request. 499 """ 500 501 xml = """ 502 <iq type='set' to='pubsub.example.org' 503 from='user@example.org'> 504 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 505 <publish node='test'/> 506 </pubsub> 507 </iq> 508 """ 509 510 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 511 self.assertEqual('publish', request.verb) 512 self.assertEqual(JID('user@example.org'), request.sender) 513 self.assertEqual(JID('pubsub.example.org'), request.recipient) 514 self.assertEqual('test', request.nodeIdentifier) 515 self.assertEqual([], request.items) 516 517 518 def test_fromElementPublishItems(self): 519 """ 520 Test parsing a publish request with items. 521 """ 522 523 xml = """ 524 <iq type='set' to='pubsub.example.org' 525 from='user@example.org'> 526 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 527 <publish node='test'> 528 <item id="item1"/> 529 <item id="item2"/> 530 </publish> 531 </pubsub> 532 </iq> 533 """ 534 535 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 536 self.assertEqual(2, len(request.items)) 537 self.assertEqual(u'item1', request.items[0]["id"]) 538 self.assertEqual(u'item2', request.items[1]["id"]) 539 540 541 def test_fromElementPublishNoNode(self): 542 """ 543 A publish request to the root node should raise an exception. 544 """ 545 xml = """ 546 <iq type='set' to='pubsub.example.org' 547 from='user@example.org'> 548 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 549 <publish/> 550 </pubsub> 551 </iq> 552 """ 553 554 err = self.assertRaises(error.StanzaError, 555 pubsub.PubSubRequest.fromElement, 556 parseXml(xml)) 557 self.assertEqual('bad-request', err.condition) 558 self.assertEqual(NS_PUBSUB_ERRORS, err.appCondition.uri) 559 self.assertEqual('nodeid-required', err.appCondition.name) 560 561 562 def test_fromElementSubscribe(self): 563 """ 564 Test parsing a subscription request. 565 """ 566 567 xml = """ 568 <iq type='set' to='pubsub.example.org' 569 from='user@example.org'> 570 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 571 <subscribe node='test' jid='user@example.org/Home'/> 572 </pubsub> 573 </iq> 574 """ 575 576 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 577 self.assertEqual('subscribe', request.verb) 578 self.assertEqual(JID('user@example.org'), request.sender) 579 self.assertEqual(JID('pubsub.example.org'), request.recipient) 580 self.assertEqual('test', request.nodeIdentifier) 581 self.assertEqual(JID('user@example.org/Home'), request.subscriber) 582 583 584 def test_fromElementSubscribeEmptyNode(self): 585 """ 586 Test parsing a subscription request to the root node. 587 """ 588 589 xml = """ 590 <iq type='set' to='pubsub.example.org' 591 from='user@example.org'> 592 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 593 <subscribe jid='user@example.org/Home'/> 594 </pubsub> 595 </iq> 596 """ 597 598 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 599 self.assertEqual('', request.nodeIdentifier) 600 601 602 def test_fromElementSubscribeNoJID(self): 603 """ 604 Subscribe requests without a JID should raise a bad-request exception. 605 """ 606 xml = """ 607 <iq type='set' to='pubsub.example.org' 608 from='user@example.org'> 609 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 610 <subscribe node='test'/> 611 </pubsub> 612 </iq> 613 """ 614 err = self.assertRaises(error.StanzaError, 615 pubsub.PubSubRequest.fromElement, 616 parseXml(xml)) 617 self.assertEqual('bad-request', err.condition) 618 self.assertEqual(NS_PUBSUB_ERRORS, err.appCondition.uri) 619 self.assertEqual('jid-required', err.appCondition.name) 620 621 def test_fromElementUnsubscribe(self): 622 """ 623 Test parsing an unsubscription request. 624 """ 625 626 xml = """ 627 <iq type='set' to='pubsub.example.org' 628 from='user@example.org'> 629 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 630 <unsubscribe node='test' jid='user@example.org/Home'/> 631 </pubsub> 632 </iq> 633 """ 634 635 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 636 self.assertEqual('unsubscribe', request.verb) 637 self.assertEqual(JID('user@example.org'), request.sender) 638 self.assertEqual(JID('pubsub.example.org'), request.recipient) 639 self.assertEqual('test', request.nodeIdentifier) 640 self.assertEqual(JID('user@example.org/Home'), request.subscriber) 641 642 643 def test_fromElementUnsubscribeNoJID(self): 644 """ 645 Unsubscribe requests without a JID should raise a bad-request exception. 646 """ 647 xml = """ 648 <iq type='set' to='pubsub.example.org' 649 from='user@example.org'> 650 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 651 <unsubscribe node='test'/> 652 </pubsub> 653 </iq> 654 """ 655 err = self.assertRaises(error.StanzaError, 656 pubsub.PubSubRequest.fromElement, 657 parseXml(xml)) 658 self.assertEqual('bad-request', err.condition) 659 self.assertEqual(NS_PUBSUB_ERRORS, err.appCondition.uri) 660 self.assertEqual('jid-required', err.appCondition.name) 661 662 663 def test_fromElementOptionsGet(self): 664 """ 665 Test parsing a request for getting subscription options. 666 """ 667 668 xml = """ 669 <iq type='get' to='pubsub.example.org' 670 from='user@example.org'> 671 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 672 <options node='test' jid='user@example.org/Home'/> 673 </pubsub> 674 </iq> 675 """ 676 677 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 678 self.assertEqual('optionsGet', request.verb) 679 680 681 def test_fromElementOptionsSet(self): 682 """ 683 Test parsing a request for setting subscription options. 684 """ 685 686 xml = """ 687 <iq type='set' to='pubsub.example.org' 688 from='user@example.org'> 689 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 690 <options node='test' jid='user@example.org/Home'> 691 <x xmlns='jabber:x:data' type='submit'> 692 <field var='FORM_TYPE' type='hidden'> 693 <value>http://jabber.org/protocol/pubsub#subscribe_options</value> 694 </field> 695 <field var='pubsub#deliver'><value>1</value></field> 696 </x> 697 </options> 698 </pubsub> 699 </iq> 700 """ 701 702 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 703 self.assertEqual('optionsSet', request.verb) 704 self.assertEqual(JID('user@example.org'), request.sender) 705 self.assertEqual(JID('pubsub.example.org'), request.recipient) 706 self.assertEqual('test', request.nodeIdentifier) 707 self.assertEqual(JID('user@example.org/Home'), request.subscriber) 708 self.assertEqual({'pubsub#deliver': '1'}, request.options) 709 710 711 def test_fromElementOptionsSetCancel(self): 712 """ 713 Test parsing a request for cancelling setting subscription options. 714 """ 715 716 xml = """ 717 <iq type='set' to='pubsub.example.org' 718 from='user@example.org'> 719 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 720 <options node='test' jid='user@example.org/Home'> 721 <x xmlns='jabber:x:data' type='cancel'/> 722 </options> 723 </pubsub> 724 </iq> 725 """ 726 727 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 728 self.assertEqual({}, request.options) 729 730 731 def test_fromElementOptionsSetBadFormType(self): 732 """ 733 On a options set request unknown fields should be ignored. 734 """ 735 736 xml = """ 737 <iq type='set' to='pubsub.example.org' 738 from='user@example.org'> 739 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 740 <options node='test' jid='user@example.org/Home'> 741 <x xmlns='jabber:x:data' type='result'> 742 <field var='FORM_TYPE' type='hidden'> 743 <value>http://jabber.org/protocol/pubsub#node_config</value> 744 </field> 745 <field var='pubsub#deliver'><value>1</value></field> 746 </x> 747 </options> 748 </pubsub> 749 </iq> 750 """ 751 752 err = self.assertRaises(error.StanzaError, 753 pubsub.PubSubRequest.fromElement, 754 parseXml(xml)) 755 self.assertEqual('bad-request', err.condition) 756 self.assertEqual(None, err.appCondition) 757 758 759 def test_fromElementOptionsSetNoForm(self): 760 """ 761 On a options set request a form is required. 762 """ 763 764 xml = """ 765 <iq type='set' to='pubsub.example.org' 766 from='user@example.org'> 767 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 768 <options node='test' jid='user@example.org/Home'/> 769 </pubsub> 770 </iq> 771 """ 772 err = self.assertRaises(error.StanzaError, 773 pubsub.PubSubRequest.fromElement, 774 parseXml(xml)) 775 self.assertEqual('bad-request', err.condition) 776 self.assertEqual(None, err.appCondition) 777 778 779 def test_fromElementSubscriptions(self): 780 """ 781 Test parsing a request for all subscriptions. 782 """ 783 784 xml = """ 785 <iq type='get' to='pubsub.example.org' 786 from='user@example.org'> 787 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 788 <subscriptions/> 789 </pubsub> 790 </iq> 791 """ 792 793 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 794 self.assertEqual('subscriptions', request.verb) 795 self.assertEqual(JID('user@example.org'), request.sender) 796 self.assertEqual(JID('pubsub.example.org'), request.recipient) 797 798 799 def test_fromElementAffiliations(self): 800 """ 801 Test parsing a request for all affiliations. 802 """ 803 804 xml = """ 805 <iq type='get' to='pubsub.example.org' 806 from='user@example.org'> 807 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 808 <affiliations/> 809 </pubsub> 810 </iq> 811 """ 812 813 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 814 self.assertEqual('affiliations', request.verb) 815 self.assertEqual(JID('user@example.org'), request.sender) 816 self.assertEqual(JID('pubsub.example.org'), request.recipient) 817 818 819 def test_fromElementCreate(self): 820 """ 821 Test parsing a request to create a node. 822 """ 823 824 xml = """ 825 <iq type='set' to='pubsub.example.org' 826 from='user@example.org'> 827 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 828 <create node='mynode'/> 829 </pubsub> 830 </iq> 831 """ 832 833 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 834 self.assertEqual('create', request.verb) 835 self.assertEqual(JID('user@example.org'), request.sender) 836 self.assertEqual(JID('pubsub.example.org'), request.recipient) 837 self.assertEqual('mynode', request.nodeIdentifier) 838 839 840 def test_fromElementCreateInstant(self): 841 """ 842 Test parsing a request to create an instant node. 843 """ 844 845 xml = """ 846 <iq type='set' to='pubsub.example.org' 847 from='user@example.org'> 848 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 849 <create/> 850 </pubsub> 851 </iq> 852 """ 853 854 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 855 self.assertIdentical(None, request.nodeIdentifier) 856 857 858 def test_fromElementDefault(self): 859 """ 860 Test parsing a request for the default node configuration. 861 """ 862 863 xml = """ 864 <iq type='get' to='pubsub.example.org' 865 from='user@example.org'> 866 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 867 <default/> 868 </pubsub> 869 </iq> 870 """ 871 872 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 873 self.assertEqual('default', request.verb) 874 self.assertEqual(JID('user@example.org'), request.sender) 875 self.assertEqual(JID('pubsub.example.org'), request.recipient) 876 self.assertEqual('leaf', request.nodeType) 877 878 879 def test_fromElementDefaultCollection(self): 880 """ 881 Parsing a request for the default configuration extracts the node type. 882 """ 883 884 xml = """ 885 <iq type='get' to='pubsub.example.org' 886 from='user@example.org'> 887 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 888 <default> 889 <x xmlns='jabber:x:data' type='submit'> 890 <field var='FORM_TYPE' type='hidden'> 891 <value>http://jabber.org/protocol/pubsub#node_config</value> 892 </field> 893 <field var='pubsub#node_type'> 894 <value>collection</value> 895 </field> 896 </x> 897 </default> 898 899 </pubsub> 900 </iq> 901 """ 902 903 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 904 self.assertEqual('collection', request.nodeType) 905 906 907 def test_fromElementConfigureGet(self): 908 """ 909 Test parsing a node configuration get request. 910 """ 911 912 xml = """ 913 <iq type='get' to='pubsub.example.org' 914 from='user@example.org'> 915 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 916 <configure node='test'/> 917 </pubsub> 918 </iq> 919 """ 920 921 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 922 self.assertEqual('configureGet', request.verb) 923 self.assertEqual(JID('user@example.org'), request.sender) 924 self.assertEqual(JID('pubsub.example.org'), request.recipient) 925 self.assertEqual('test', request.nodeIdentifier) 926 927 928 def test_fromElementConfigureSet(self): 929 """ 930 On a node configuration set request the Data Form is parsed. 931 """ 932 933 xml = """ 934 <iq type='set' to='pubsub.example.org' 935 from='user@example.org'> 936 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 937 <configure node='test'> 938 <x xmlns='jabber:x:data' type='submit'> 939 <field var='FORM_TYPE' type='hidden'> 940 <value>http://jabber.org/protocol/pubsub#node_config</value> 941 </field> 942 <field var='pubsub#deliver_payloads'><value>0</value></field> 943 <field var='pubsub#persist_items'><value>1</value></field> 944 </x> 945 </configure> 946 </pubsub> 947 </iq> 948 """ 949 950 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 951 self.assertEqual('configureSet', request.verb) 952 self.assertEqual(JID('user@example.org'), request.sender) 953 self.assertEqual(JID('pubsub.example.org'), request.recipient) 954 self.assertEqual('test', request.nodeIdentifier) 955 self.assertEqual({'pubsub#deliver_payloads': '0', 956 'pubsub#persist_items': '1'}, request.options) 957 958 959 def test_fromElementConfigureSetCancel(self): 960 """ 961 The node configuration is cancelled, so no options. 962 """ 963 964 xml = """ 965 <iq type='set' to='pubsub.example.org' 966 from='user@example.org'> 967 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 968 <configure node='test'> 969 <x xmlns='jabber:x:data' type='cancel'/> 970 </configure> 971 </pubsub> 972 </iq> 973 """ 974 975 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 976 self.assertEqual({}, request.options) 977 978 979 def test_fromElementConfigureSetBadFormType(self): 980 """ 981 On a node configuration set request unknown fields should be ignored. 982 """ 983 984 xml = """ 985 <iq type='set' to='pubsub.example.org' 986 from='user@example.org'> 987 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 988 <configure node='test'> 989 <x xmlns='jabber:x:data' type='result'> 990 <field var='FORM_TYPE' type='hidden'> 991 <value>http://jabber.org/protocol/pubsub#node_config</value> 992 </field> 993 <field var='pubsub#deliver_payloads'><value>0</value></field> 994 <field var='x-myfield'><value>1</value></field> 995 </x> 996 </configure> 997 </pubsub> 998 </iq> 999 """ 1000 1001 err = self.assertRaises(error.StanzaError, 1002 pubsub.PubSubRequest.fromElement, 1003 parseXml(xml)) 1004 self.assertEqual('bad-request', err.condition) 1005 self.assertEqual(None, err.appCondition) 1006 1007 1008 def test_fromElementConfigureSetNoForm(self): 1009 """ 1010 On a node configuration set request a form is required. 1011 """ 1012 1013 xml = """ 1014 <iq type='set' to='pubsub.example.org' 1015 from='user@example.org'> 1016 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 1017 <configure node='test'/> 1018 </pubsub> 1019 </iq> 1020 """ 1021 err = self.assertRaises(error.StanzaError, 1022 pubsub.PubSubRequest.fromElement, 1023 parseXml(xml)) 1024 self.assertEqual('bad-request', err.condition) 1025 self.assertEqual(None, err.appCondition) 1026 1027 1028 def test_fromElementItems(self): 1029 """ 1030 Test parsing an items request. 1031 """ 1032 xml = """ 1033 <iq type='get' to='pubsub.example.org' 1034 from='user@example.org'> 1035 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1036 <items node='test'/> 1037 </pubsub> 1038 </iq> 1039 """ 1040 1041 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 1042 self.assertEqual('items', request.verb) 1043 self.assertEqual(JID('user@example.org'), request.sender) 1044 self.assertEqual(JID('pubsub.example.org'), request.recipient) 1045 self.assertEqual('test', request.nodeIdentifier) 1046 self.assertIdentical(None, request.maxItems) 1047 self.assertEqual([], request.itemIdentifiers) 1048 1049 1050 def test_fromElementRetract(self): 1051 """ 1052 Test parsing a retract request. 1053 """ 1054 1055 xml = """ 1056 <iq type='set' to='pubsub.example.org' 1057 from='user@example.org'> 1058 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1059 <retract node='test'> 1060 <item id='item1'/> 1061 <item id='item2'/> 1062 </retract> 1063 </pubsub> 1064 </iq> 1065 """ 1066 1067 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 1068 self.assertEqual('retract', request.verb) 1069 self.assertEqual(JID('user@example.org'), request.sender) 1070 self.assertEqual(JID('pubsub.example.org'), request.recipient) 1071 self.assertEqual('test', request.nodeIdentifier) 1072 self.assertEqual(['item1', 'item2'], request.itemIdentifiers) 1073 1074 1075 def test_fromElementPurge(self): 1076 """ 1077 Test parsing a purge request. 1078 """ 1079 1080 xml = """ 1081 <iq type='set' to='pubsub.example.org' 1082 from='user@example.org'> 1083 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 1084 <purge node='test'/> 1085 </pubsub> 1086 </iq> 1087 """ 1088 1089 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 1090 self.assertEqual('purge', request.verb) 1091 self.assertEqual(JID('user@example.org'), request.sender) 1092 self.assertEqual(JID('pubsub.example.org'), request.recipient) 1093 self.assertEqual('test', request.nodeIdentifier) 1094 1095 1096 def test_fromElementDelete(self): 1097 """ 1098 Test parsing a delete request. 1099 """ 1100 1101 xml = """ 1102 <iq type='set' to='pubsub.example.org' 1103 from='user@example.org'> 1104 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 1105 <delete node='test'/> 1106 </pubsub> 1107 </iq> 1108 """ 1109 1110 request = pubsub.PubSubRequest.fromElement(parseXml(xml)) 1111 self.assertEqual('delete', request.verb) 1112 self.assertEqual(JID('user@example.org'), request.sender) 1113 self.assertEqual(JID('pubsub.example.org'), request.recipient) 1114 self.assertEqual('test', request.nodeIdentifier) 1115 1116 1117 493 1118 class PubSubServiceTest(unittest.TestCase, TestableRequestHandlerMixin): 494 1119 """ 495 1120 Tests for L{pubsub.PubSubService}. … … 507 1132 verify.verifyObject(iwokkel.IPubSubService, self.service) 508 1133 509 1134 1135 def test_connectionMade(self): 1136 """ 1137 Verify setup of observers in L{pubsub.connectionMade}. 1138 """ 1139 requests = [] 1140 1141 def handleRequest(iq): 1142 requests.append(iq) 1143 1144 self.service.xmlstream = self.stub.xmlstream 1145 self.service.handleRequest = handleRequest 1146 self.service.connectionMade() 1147 1148 for namespace in (NS_PUBSUB, NS_PUBSUB_OWNER): 1149 for stanzaType in ('get', 'set'): 1150 iq = domish.Element((None, 'iq')) 1151 iq['type'] = stanzaType 1152 iq.addElement((namespace, 'pubsub')) 1153 self.stub.xmlstream.dispatch(iq) 1154 1155 self.assertEqual(4, len(requests)) 1156 1157 510 1158 def test_getDiscoInfo(self): 511 1159 """ 512 1160 Test getDiscoInfo calls getNodeInfo and returns some minimal info. … … 524 1172 return d 525 1173 526 1174 527 def test_onPublishNoNode(self):528 """529 The root node is always a collection, publishing is a bad request.530 """531 xml = """532 <iq type='set' to='pubsub.example.org'533 from='user@example.org'>534 <pubsub xmlns='http://jabber.org/protocol/pubsub'>535 <publish/>536 </pubsub>537 </iq>538 """539 540 def cb(result):541 self.assertEquals('bad-request', result.condition)542 543 d = self.handleRequest(xml)544 self.assertFailure(d, error.StanzaError)545 d.addCallback(cb)546 return d547 548 549 1175 def test_onPublish(self): 550 1176 """ 551 1177 A publish request should result in L{PubSubService.publish} being … … 561 1187 </iq> 562 1188 """ 563 1189 564 def publish(requestor, service, nodeIdentifier, items): 565 self.assertEqual(JID('user@example.org'), requestor) 566 self.assertEqual(JID('pubsub.example.org'), service) 567 self.assertEqual('test', nodeIdentifier) 568 self.assertEqual([], items) 1190 def publish(request): 569 1191 return defer.succeed(None) 570 1192 571 1193 self.service.publish = publish 1194 verify.verifyObject(iwokkel.IPubSubService, self.service) 572 1195 return self.handleRequest(xml) 573 1196 574 1197 1198 def test_onSubscribe(self): 1199 """ 1200 A successful subscription should return the current subscription. 1201 """ 1202 1203 xml = """ 1204 <iq type='set' to='pubsub.example.org' 1205 from='user@example.org'> 1206 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1207 <subscribe node='test' jid='user@example.org/Home'/> 1208 </pubsub> 1209 </iq> 1210 """ 1211 1212 def subscribe(request): 1213 return defer.succeed(pubsub.Subscription(request.nodeIdentifier, 1214 request.subscriber, 1215 'subscribed')) 1216 1217 def cb(element): 1218 self.assertEqual('pubsub', element.name) 1219 self.assertEqual(NS_PUBSUB, element.uri) 1220 subscription = element.subscription 1221 self.assertEqual(NS_PUBSUB, subscription.uri) 1222 self.assertEqual('test', subscription['node']) 1223 self.assertEqual('user@example.org/Home', subscription['jid']) 1224 self.assertEqual('subscribed', subscription['subscription']) 1225 1226 self.service.subscribe = subscribe 1227 verify.verifyObject(iwokkel.IPubSubService, self.service) 1228 d = self.handleRequest(xml) 1229 d.addCallback(cb) 1230 return d 1231 1232 1233 def test_onSubscribeEmptyNode(self): 1234 """ 1235 A successful subscription on root node should return no node attribute. 1236 """ 1237 1238 xml = """ 1239 <iq type='set' to='pubsub.example.org' 1240 from='user@example.org'> 1241 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1242 <subscribe jid='user@example.org/Home'/> 1243 </pubsub> 1244 </iq> 1245 """ 1246 1247 def subscribe(request): 1248 return defer.succeed(pubsub.Subscription(request.nodeIdentifier, 1249 request.subscriber, 1250 'subscribed')) 1251 1252 def cb(element): 1253 self.assertFalse(element.subscription.hasAttribute('node')) 1254 1255 self.service.subscribe = subscribe 1256 verify.verifyObject(iwokkel.IPubSubService, self.service) 1257 d = self.handleRequest(xml) 1258 d.addCallback(cb) 1259 return d 1260 1261 1262 def test_onUnsubscribe(self): 1263 """ 1264 A successful unsubscription should return an empty response. 1265 """ 1266 1267 xml = """ 1268 <iq type='set' to='pubsub.example.org' 1269 from='user@example.org'> 1270 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1271 <unsubscribe node='test' jid='user@example.org/Home'/> 1272 </pubsub> 1273 </iq> 1274 """ 1275 1276 def unsubscribe(request): 1277 return defer.succeed(None) 1278 1279 def cb(element): 1280 self.assertIdentical(None, element) 1281 1282 self.service.unsubscribe = unsubscribe 1283 verify.verifyObject(iwokkel.IPubSubService, self.service) 1284 d = self.handleRequest(xml) 1285 d.addCallback(cb) 1286 return d 1287 1288 575 1289 def test_onOptionsGet(self): 576 1290 """ 577 Subscription options arenot supported.1291 Getting subscription options is not supported. 578 1292 """ 579 1293 580 1294 xml = """ 581 1295 <iq type='get' to='pubsub.example.org' 582 1296 from='user@example.org'> 583 1297 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 584 <options/> 1298 <options node='test' jid='user@example.org/Home'/> 1299 </pubsub> 1300 </iq> 1301 """ 1302 1303 def cb(result): 1304 self.assertEquals('feature-not-implemented', result.condition) 1305 self.assertEquals('unsupported', result.appCondition.name) 1306 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 1307 1308 d = self.handleRequest(xml) 1309 self.assertFailure(d, error.StanzaError) 1310 d.addCallback(cb) 1311 return d 1312 1313 1314 def test_onOptionsSet(self): 1315 """ 1316 Setting subscription options is not supported. 1317 """ 1318 1319 xml = """ 1320 <iq type='set' to='pubsub.example.org' 1321 from='user@example.org'> 1322 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1323 <options node='test' jid='user@example.org/Home'> 1324 <x xmlns='jabber:x:data' type='submit'> 1325 <field var='FORM_TYPE' type='hidden'> 1326 <value>http://jabber.org/protocol/pubsub#subscribe_options</value> 1327 </field> 1328 <field var='pubsub#deliver'><value>1</value></field> 1329 </x> 1330 </options> 585 1331 </pubsub> 586 1332 </iq> 587 1333 """ … … 627 1373 self.assertEqual('subscribed', subscription['subscription']) 628 1374 629 1375 630 def subscriptions(requestor, service): 631 self.assertEqual(JID('user@example.org'), requestor) 632 self.assertEqual(JID('pubsub.example.org'), service) 1376 def subscriptions(request): 633 1377 subscription = pubsub.Subscription('test', JID('user@example.org'), 634 1378 'subscribed') 635 1379 return defer.succeed([subscription]) 636 1380 637 1381 self.service.subscriptions = subscriptions 1382 verify.verifyObject(iwokkel.IPubSubService, self.service) 1383 d = self.handleRequest(xml) 1384 d.addCallback(cb) 1385 return d 1386 1387 1388 def test_onAffiliations(self): 1389 """ 1390 A subscriptions request should result in 1391 L{PubSubService.affiliations} being called and the result prepared 1392 for the response. 1393 """ 1394 1395 xml = """ 1396 <iq type='get' to='pubsub.example.org' 1397 from='user@example.org'> 1398 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1399 <affiliations/> 1400 </pubsub> 1401 </iq> 1402 """ 1403 1404 def cb(element): 1405 self.assertEqual('pubsub', element.name) 1406 self.assertEqual(NS_PUBSUB, element.uri) 1407 self.assertEqual(NS_PUBSUB, element.affiliations.uri) 1408 children = list(element.affiliations.elements()) 1409 self.assertEqual(1, len(children)) 1410 affiliation = children[0] 1411 self.assertEqual('affiliation', affiliation.name) 1412 self.assertEqual(NS_PUBSUB, affiliation.uri) 1413 self.assertEqual('test', affiliation['node']) 1414 self.assertEqual('owner', affiliation['affiliation']) 1415 1416 1417 def affiliations(request): 1418 affiliation = ('test', 'owner') 1419 return defer.succeed([affiliation]) 1420 1421 self.service.affiliations = affiliations 1422 verify.verifyObject(iwokkel.IPubSubService, self.service) 1423 d = self.handleRequest(xml) 1424 d.addCallback(cb) 1425 return d 1426 1427 1428 def test_onCreate(self): 1429 """ 1430 Replies to create node requests don't return the created node. 1431 """ 1432 1433 xml = """ 1434 <iq type='set' to='pubsub.example.org' 1435 from='user@example.org'> 1436 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1437 <create node='mynode'/> 1438 </pubsub> 1439 </iq> 1440 """ 1441 1442 def create(request): 1443 return defer.succeed(request.nodeIdentifier) 1444 1445 def cb(element): 1446 self.assertIdentical(None, element) 1447 1448 self.service.create = create 1449 verify.verifyObject(iwokkel.IPubSubService, self.service) 1450 d = self.handleRequest(xml) 1451 d.addCallback(cb) 1452 return d 1453 1454 1455 def test_onCreateChanged(self): 1456 """ 1457 Replies to create node requests return the created node if changed. 1458 """ 1459 1460 xml = """ 1461 <iq type='set' to='pubsub.example.org' 1462 from='user@example.org'> 1463 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1464 <create node='mynode'/> 1465 </pubsub> 1466 </iq> 1467 """ 1468 1469 def create(request): 1470 return defer.succeed(u'myrenamednode') 1471 1472 def cb(element): 1473 self.assertEqual('pubsub', element.name) 1474 self.assertEqual(NS_PUBSUB, element.uri) 1475 self.assertEqual(NS_PUBSUB, element.create.uri) 1476 self.assertEqual(u'myrenamednode', 1477 element.create.getAttribute('node')) 1478 1479 self.service.create = create 1480 verify.verifyObject(iwokkel.IPubSubService, self.service) 1481 d = self.handleRequest(xml) 1482 d.addCallback(cb) 1483 return d 1484 1485 1486 def test_onCreateInstant(self): 1487 """ 1488 Replies to create instant node requests return the created node. 1489 """ 1490 1491 xml = """ 1492 <iq type='set' to='pubsub.example.org' 1493 from='user@example.org'> 1494 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 1495 <create/> 1496 </pubsub> 1497 </iq> 1498 """ 1499 1500 def create(request): 1501 return defer.succeed(u'random') 1502 1503 def cb(element): 1504 self.assertEqual('pubsub', element.name) 1505 self.assertEqual(NS_PUBSUB, element.uri) 1506 self.assertEqual(NS_PUBSUB, element.create.uri) 1507 self.assertEqual(u'random', element.create.getAttribute('node')) 1508 1509 self.service.create = create 1510 verify.verifyObject(iwokkel.IPubSubService, self.service) 638 1511 d = self.handleRequest(xml) 639 1512 d.addCallback(cb) 640 1513 return d … … 665 1538 "label": "Deliver payloads with event notifications"} 666 1539 } 667 1540 668 def getDefaultConfiguration(requestor, service, nodeType): 669 self.assertEqual(JID('user@example.org'), requestor) 670 self.assertEqual(JID('pubsub.example.org'), service) 671 self.assertEqual('leaf', nodeType) 1541 def getDefaultConfiguration(request): 672 1542 return defer.succeed({}) 673 1543 674 1544 def cb(element): … … 686 1556 return d 687 1557 688 1558 1559 def test_onDefaultCollection(self): 1560 """ 1561 Responses to default requests should depend on passed node type. 1562 """ 1563 1564 xml = """ 1565 <iq type='get' to='pubsub.example.org' 1566 from='user@example.org'> 1567 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 1568 <default> 1569 <x xmlns='jabber:x:data' type='submit'> 1570 <field var='FORM_TYPE' type='hidden'> 1571 <value>http://jabber.org/protocol/pubsub#node_config</value> 1572 </field> 1573 <field var='pubsub#node_type'> 1574 <value>collection</value> 1575 </field> 1576 </x> 1577 </default> 1578 1579 </pubsub> 1580 </iq> 1581 """ 1582 1583 def getConfigurationOptions(): 1584 return { 1585 "pubsub#deliver_payloads": 1586 {"type": "boolean", 1587 "label": "Deliver payloads with event notifications"} 1588 } 1589 1590 def getDefaultConfiguration(request): 1591 return defer.succeed({}) 1592 1593 self.service.getConfigurationOptions = getConfigurationOptions 1594 self.service.getDefaultConfiguration = getDefaultConfiguration 1595 verify.verifyObject(iwokkel.IPubSubService, self.service) 1596 return self.handleRequest(xml) 1597 1598 1599 def test_onDefaultUnknownNodeType(self): 1600 """ 1601 A default request should result in 1602 L{PubSubService.getDefaultConfiguration} being called. 1603 """ 1604 1605 xml = """ 1606 <iq type='get' to='pubsub.example.org' 1607 from='user@example.org'> 1608 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 1609 <default> 1610 <x xmlns='jabber:x:data' type='submit'> 1611 <field var='FORM_TYPE' type='hidden'> 1612 <value>http://jabber.org/protocol/pubsub#node_config</value> 1613 </field> 1614 <field var='pubsub#node_type'> 1615 <value>unknown</value> 1616 </field> 1617 </x> 1618 </default> 1619 1620 </pubsub> 1621 </iq> 1622 """ 1623 1624 def getDefaultConfiguration(request): 1625 self.fail("Unexpected call to getConfiguration") 1626 1627 def cb(result): 1628 self.assertEquals('not-acceptable', result.condition) 1629 1630 self.service.getDefaultConfiguration = getDefaultConfiguration 1631 verify.verifyObject(iwokkel.IPubSubService, self.service) 1632 d = self.handleRequest(xml) 1633 self.assertFailure(d, error.StanzaError) 1634 d.addCallback(cb) 1635 return d 1636 1637 689 1638 def test_onConfigureGet(self): 690 1639 """ 691 1640 On a node configuration get request L{PubSubService.getConfiguration} … … 714 1663 "label": "Owner of the node"} 715 1664 } 716 1665 717 def getConfiguration(requestor, service, nodeIdentifier): 718 self.assertEqual(JID('user@example.org'), requestor) 719 self.assertEqual(JID('pubsub.example.org'), service) 720 self.assertEqual('test', nodeIdentifier) 721 1666 def getConfiguration(request): 722 1667 return defer.succeed({'pubsub#deliver_payloads': '0', 723 1668 'pubsub#persist_items': '1', 724 'pubsub#owner': JID('user@example.org')}) 1669 'pubsub#owner': JID('user@example.org'), 1670 'x-myfield': ['a', 'b']}) 725 1671 726 1672 def cb(element): 727 1673 self.assertEqual('pubsub', element.name) … … 749 1695 field.typeCheck() 750 1696 self.assertEqual(JID('user@example.org'), field.value) 751 1697 1698 self.assertNotIn('x-myfield', fields) 1699 1700 752 1701 self.service.getConfigurationOptions = getConfigurationOptions 753 1702 self.service.getConfiguration = getConfiguration 1703 verify.verifyObject(iwokkel.IPubSubService, self.service) 754 1704 d = self.handleRequest(xml) 755 1705 d.addCallback(cb) 756 1706 return d … … 789 1739 "label": "Deliver payloads with event notifications"} 790 1740 } 791 1741 792 def setConfiguration(requestor, service, nodeIdentifier, options): 793 self.assertEqual(JID('user@example.org'), requestor) 794 self.assertEqual(JID('pubsub.example.org'), service) 795 self.assertEqual('test', nodeIdentifier) 1742 def setConfiguration(request): 796 1743 self.assertEqual({'pubsub#deliver_payloads': False, 797 'pubsub#persist_items': True}, options)1744 'pubsub#persist_items': True}, request.options) 798 1745 return defer.succeed(None) 799 1746 800 1747 self.service.getConfigurationOptions = getConfigurationOptions 801 1748 self.service.setConfiguration = setConfiguration 1749 verify.verifyObject(iwokkel.IPubSubService, self.service) 802 1750 return self.handleRequest(xml) 803 1751 804 1752 … … 823 1771 </iq> 824 1772 """ 825 1773 826 def setConfiguration(request or, service, nodeIdentifier, options):1774 def setConfiguration(request): 827 1775 self.fail("Unexpected call to setConfiguration") 828 1776 829 1777 self.service.setConfiguration = setConfiguration 1778 verify.verifyObject(iwokkel.IPubSubService, self.service) 830 1779 return self.handleRequest(xml) 831 1780 832 1781 … … 862 1811 "label": "Deliver payloads with event notifications"} 863 1812 } 864 1813 865 def setConfiguration(requestor, service, nodeIdentifier, options): 866 self.assertEquals(['pubsub#deliver_payloads'], options.keys()) 1814 def setConfiguration(request): 1815 self.assertEquals(['pubsub#deliver_payloads'], 1816 request.options.keys()) 867 1817 868 1818 self.service.getConfigurationOptions = getConfigurationOptions 869 1819 self.service.setConfiguration = setConfiguration 1820 verify.verifyObject(iwokkel.IPubSubService, self.service) 870 1821 return self.handleRequest(xml) 871 1822 872 1823 1824 def test_onConfigureSetBadFormType(self): 1825 """ 1826 On a node configuration set request unknown fields should be ignored. 1827 """ 1828 1829 xml = """ 1830 <iq type='set' to='pubsub.example.org' 1831 from='user@example.org'> 1832 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 1833 <configure node='test'> 1834 <x xmlns='jabber:x:data' type='result'> 1835 <field var='FORM_TYPE' type='hidden'> 1836 <value>http://jabber.org/protocol/pubsub#node_config</value> 1837 </field> 1838 <field var='pubsub#deliver_payloads'><value>0</value></field> 1839 <field var='x-myfield'><value>1</value></field> 1840 </x> 1841 </configure> 1842 </pubsub> 1843 </iq> 1844 """ 1845 1846 def cb(result): 1847 self.assertEquals('bad-request', result.condition) 1848 1849 d = self.handleRequest(xml) 1850 self.assertFailure(d, error.StanzaError) 1851 d.addCallback(cb) 1852 return d 1853 1854 873 1855 def test_onItems(self): 874 1856 """ 875 1857 On a items request, return all items for the given node. … … 883 1865 </iq> 884 1866 """ 885 1867 886 def items(requestor, service, nodeIdentifier, maxItems, items): 887 self.assertEqual(JID('user@example.org'), requestor) 888 self.assertEqual(JID('pubsub.example.org'), service) 889 self.assertEqual('test', nodeIdentifier) 890 self.assertIdentical(None, maxItems) 891 self.assertEqual([], items) 1868 def items(request): 892 1869 return defer.succeed([pubsub.Item('current')]) 893 1870 894 1871 def cb(element): … … 925 1902 </iq> 926 1903 """ 927 1904 928 def retract(requestor, service, nodeIdentifier, itemIdentifiers): 929 self.assertEqual(JID('user@example.org'), requestor) 930 self.assertEqual(JID('pubsub.example.org'), service) 931 self.assertEqual('test', nodeIdentifier) 932 self.assertEqual(['item1', 'item2'], itemIdentifiers) 1905 def retract(request): 933 1906 return defer.succeed(None) 934 1907 935 1908 self.service.retract = retract … … 951 1924 </iq> 952 1925 """ 953 1926 954 def purge(requestor, service, nodeIdentifier): 955 self.assertEqual(JID('user@example.org'), requestor) 956 self.assertEqual(JID('pubsub.example.org'), service) 957 self.assertEqual('test', nodeIdentifier) 1927 def purge(request): 958 1928 return defer.succeed(None) 959 1929 960 1930 self.service.purge = purge … … 976 1946 </iq> 977 1947 """ 978 1948 979 def delete(requestor, service, nodeIdentifier): 980 self.assertEqual(JID('user@example.org'), requestor) 981 self.assertEqual(JID('pubsub.example.org'), service) 982 self.assertEqual('test', nodeIdentifier) 1949 def delete(request): 983 1950 return defer.succeed(None) 984 1951 985 1952 self.service.delete = delete … … 1031 1998 self.assertEqual(NS_PUBSUB_EVENT, message.event.delete.redirect.uri) 1032 1999 self.assertTrue(message.event.delete.redirect.hasAttribute('uri')) 1033 2000 self.assertEqual(redirectURI, message.event.delete.redirect['uri']) 2001 2002 2003 def test_onSubscriptionsGet(self): 2004 """ 2005 Getting subscription options is not supported. 2006 """ 2007 2008 xml = """ 2009 <iq type='get' to='pubsub.example.org' 2010 from='user@example.org'> 2011 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 2012 <subscriptions/> 2013 </pubsub> 2014 </iq> 2015 """ 2016 2017 def cb(result): 2018 self.assertEquals('feature-not-implemented', result.condition) 2019 self.assertEquals('unsupported', result.appCondition.name) 2020 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2021 self.assertEquals('manage-subscriptions', 2022 result.appCondition['feature']) 2023 2024 d = self.handleRequest(xml) 2025 self.assertFailure(d, error.StanzaError) 2026 d.addCallback(cb) 2027 return d 2028 2029 2030 def test_onSubscriptionsSet(self): 2031 """ 2032 Setting subscription options is not supported. 2033 """ 2034 2035 xml = """ 2036 <iq type='set' to='pubsub.example.org' 2037 from='user@example.org'> 2038 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 2039 <subscriptions/> 2040 </pubsub> 2041 </iq> 2042 """ 2043 2044 def cb(result): 2045 self.assertEquals('feature-not-implemented', result.condition) 2046 self.assertEquals('unsupported', result.appCondition.name) 2047 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2048 self.assertEquals('manage-subscriptions', 2049 result.appCondition['feature']) 2050 2051 d = self.handleRequest(xml) 2052 self.assertFailure(d, error.StanzaError) 2053 d.addCallback(cb) 2054 return d 2055 2056 2057 def test_onAffiliationsGet(self): 2058 """ 2059 Getting subscription options is not supported. 2060 """ 2061 2062 xml = """ 2063 <iq type='get' to='pubsub.example.org' 2064 from='user@example.org'> 2065 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 2066 <affiliations/> 2067 </pubsub> 2068 </iq> 2069 """ 2070 2071 def cb(result): 2072 self.assertEquals('feature-not-implemented', result.condition) 2073 self.assertEquals('unsupported', result.appCondition.name) 2074 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2075 self.assertEquals('modify-affiliations', 2076 result.appCondition['feature']) 2077 2078 d = self.handleRequest(xml) 2079 self.assertFailure(d, error.StanzaError) 2080 d.addCallback(cb) 2081 return d 2082 2083 2084 def test_onAffiliationsSet(self): 2085 """ 2086 Setting subscription options is not supported. 2087 """ 2088 2089 xml = """ 2090 <iq type='set' to='pubsub.example.org' 2091 from='user@example.org'> 2092 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 2093 <affiliations/> 2094 </pubsub> 2095 </iq> 2096 """ 2097 2098 def cb(result): 2099 self.assertEquals('feature-not-implemented', result.condition) 2100 self.assertEquals('unsupported', result.appCondition.name) 2101 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2102 self.assertEquals('modify-affiliations', 2103 result.appCondition['feature']) 2104 2105 d = self.handleRequest(xml) 2106 self.assertFailure(d, error.StanzaError) 2107 d.addCallback(cb) 2108 return d 2109 2110 2111 def test_publish(self): 2112 """ 2113 Non-overridden L{PubSubService.publish} yields unsupported error. 2114 """ 2115 2116 xml = """ 2117 <iq type='set' to='pubsub.example.org' 2118 from='user@example.org'> 2119 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 2120 <publish node='mynode'/> 2121 </pubsub> 2122 </iq> 2123 """ 2124 2125 def cb(result): 2126 self.assertEquals('feature-not-implemented', result.condition) 2127 self.assertEquals('unsupported', result.appCondition.name) 2128 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2129 self.assertEquals('publish', result.appCondition['feature']) 2130 2131 d = self.handleRequest(xml) 2132 self.assertFailure(d, error.StanzaError) 2133 d.addCallback(cb) 2134 return d 2135 2136 2137 def test_subscribe(self): 2138 """ 2139 Non-overridden L{PubSubService.subscribe} yields unsupported error. 2140 """ 2141 2142 xml = """ 2143 <iq type='set' to='pubsub.example.org' 2144 from='user@example.org'> 2145 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 2146 <subscribe node='test' jid='user@example.org/Home'/> 2147 </pubsub> 2148 </iq> 2149 """ 2150 2151 def cb(result): 2152 self.assertEquals('feature-not-implemented', result.condition) 2153 self.assertEquals('unsupported', result.appCondition.name) 2154 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2155 self.assertEquals('subscribe', result.appCondition['feature']) 2156 2157 d = self.handleRequest(xml) 2158 self.assertFailure(d, error.StanzaError) 2159 d.addCallback(cb) 2160 return d 2161 2162 2163 def test_unsubscribe(self): 2164 """ 2165 Non-overridden L{PubSubService.unsubscribe} yields unsupported error. 2166 """ 2167 2168 xml = """ 2169 <iq type='set' to='pubsub.example.org' 2170 from='user@example.org'> 2171 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 2172 <unsubscribe node='test' jid='user@example.org/Home'/> 2173 </pubsub> 2174 </iq> 2175 """ 2176 2177 def cb(result): 2178 self.assertEquals('feature-not-implemented', result.condition) 2179 self.assertEquals('unsupported', result.appCondition.name) 2180 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2181 self.assertEquals('subscribe', result.appCondition['feature']) 2182 2183 d = self.handleRequest(xml) 2184 self.assertFailure(d, error.StanzaError) 2185 d.addCallback(cb) 2186 return d 2187 2188 2189 def test_subscriptions(self): 2190 """ 2191 Non-overridden L{PubSubService.subscriptions} yields unsupported error. 2192 """ 2193 2194 xml = """ 2195 <iq type='get' to='pubsub.example.org' 2196 from='user@example.org'> 2197 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 2198 <subscriptions/> 2199 </pubsub> 2200 </iq> 2201 """ 2202 2203 def cb(result): 2204 self.assertEquals('feature-not-implemented', result.condition) 2205 self.assertEquals('unsupported', result.appCondition.name) 2206 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2207 self.assertEquals('retrieve-subscriptions', 2208 result.appCondition['feature']) 2209 2210 d = self.handleRequest(xml) 2211 self.assertFailure(d, error.StanzaError) 2212 d.addCallback(cb) 2213 return d 2214 2215 2216 def test_affiliations(self): 2217 """ 2218 Non-overridden L{PubSubService.affiliations} yields unsupported error. 2219 """ 2220 2221 xml = """ 2222 <iq type='get' to='pubsub.example.org' 2223 from='user@example.org'> 2224 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 2225 <affiliations/> 2226 </pubsub> 2227 </iq> 2228 """ 2229 2230 def cb(result): 2231 self.assertEquals('feature-not-implemented', result.condition) 2232 self.assertEquals('unsupported', result.appCondition.name) 2233 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2234 self.assertEquals('retrieve-affiliations', 2235 result.appCondition['feature']) 2236 2237 d = self.handleRequest(xml) 2238 self.assertFailure(d, error.StanzaError) 2239 d.addCallback(cb) 2240 return d 2241 2242 2243 def test_create(self): 2244 """ 2245 Non-overridden L{PubSubService.create} yields unsupported error. 2246 """ 2247 2248 xml = """ 2249 <iq type='set' to='pubsub.example.org' 2250 from='user@example.org'> 2251 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 2252 <create node='mynode'/> 2253 </pubsub> 2254 </iq> 2255 """ 2256 2257 def cb(result): 2258 self.assertEquals('feature-not-implemented', result.condition) 2259 self.assertEquals('unsupported', result.appCondition.name) 2260 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2261 self.assertEquals('create-nodes', result.appCondition['feature']) 2262 2263 d = self.handleRequest(xml) 2264 self.assertFailure(d, error.StanzaError) 2265 d.addCallback(cb) 2266 return d 2267 2268 2269 def test_getDefaultConfiguration(self): 2270 """ 2271 Non-overridden L{PubSubService.getDefaultConfiguration} yields 2272 unsupported error. 2273 """ 2274 2275 xml = """ 2276 <iq type='get' to='pubsub.example.org' 2277 from='user@example.org'> 2278 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 2279 <default/> 2280 </pubsub> 2281 </iq> 2282 """ 2283 2284 def cb(result): 2285 self.assertEquals('feature-not-implemented', result.condition) 2286 self.assertEquals('unsupported', result.appCondition.name) 2287 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2288 self.assertEquals('retrieve-default', result.appCondition['feature']) 2289 2290 d = self.handleRequest(xml) 2291 self.assertFailure(d, error.StanzaError) 2292 d.addCallback(cb) 2293 return d 2294 2295 2296 def test_getConfiguration(self): 2297 """ 2298 Non-overridden L{PubSubService.getConfiguration} yields unsupported 2299 error. 2300 """ 2301 2302 xml = """ 2303 <iq type='get' to='pubsub.example.org' 2304 from='user@example.org'> 2305 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 2306 <configure/> 2307 </pubsub> 2308 </iq> 2309 """ 2310 2311 def cb(result): 2312 self.assertEquals('feature-not-implemented', result.condition) 2313 self.assertEquals('unsupported', result.appCondition.name) 2314 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2315 self.assertEquals('config-node', result.appCondition['feature']) 2316 2317 d = self.handleRequest(xml) 2318 self.assertFailure(d, error.StanzaError) 2319 d.addCallback(cb) 2320 return d 2321 2322 2323 def test_setConfiguration(self): 2324 """ 2325 Non-overridden L{PubSubService.setConfiguration} yields unsupported 2326 error. 2327 """ 2328 2329 xml = """ 2330 <iq type='set' to='pubsub.example.org' 2331 from='user@example.org'> 2332 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 2333 <configure node='test'> 2334 <x xmlns='jabber:x:data' type='submit'> 2335 <field var='FORM_TYPE' type='hidden'> 2336 <value>http://jabber.org/protocol/pubsub#node_config</value> 2337 </field> 2338 <field var='pubsub#deliver_payloads'><value>0</value></field> 2339 <field var='pubsub#persist_items'><value>1</value></field> 2340 </x> 2341 </configure> 2342 </pubsub> 2343 </iq> 2344 """ 2345 2346 def cb(result): 2347 self.assertEquals('feature-not-implemented', result.condition) 2348 self.assertEquals('unsupported', result.appCondition.name) 2349 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2350 self.assertEquals('config-node', result.appCondition['feature']) 2351 2352 d = self.handleRequest(xml) 2353 self.assertFailure(d, error.StanzaError) 2354 d.addCallback(cb) 2355 return d 2356 2357 2358 def test_items(self): 2359 """ 2360 Non-overridden L{PubSubService.items} yields unsupported error. 2361 """ 2362 xml = """ 2363 <iq type='get' to='pubsub.example.org' 2364 from='user@example.org'> 2365 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 2366 <items node='test'/> 2367 </pubsub> 2368 </iq> 2369 """ 2370 2371 def cb(result): 2372 self.assertEquals('feature-not-implemented', result.condition) 2373 self.assertEquals('unsupported', result.appCondition.name) 2374 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2375 self.assertEquals('retrieve-items', result.appCondition['feature']) 2376 2377 d = self.handleRequest(xml) 2378 self.assertFailure(d, error.StanzaError) 2379 d.addCallback(cb) 2380 return d 2381 2382 2383 def test_retract(self): 2384 """ 2385 Non-overridden L{PubSubService.retract} yields unsupported error. 2386 """ 2387 xml = """ 2388 <iq type='set' to='pubsub.example.org' 2389 from='user@example.org'> 2390 <pubsub xmlns='http://jabber.org/protocol/pubsub'> 2391 <retract node='test'> 2392 <item id='item1'/> 2393 <item id='item2'/> 2394 </retract> 2395 </pubsub> 2396 </iq> 2397 """ 2398 2399 def cb(result): 2400 self.assertEquals('feature-not-implemented', result.condition) 2401 self.assertEquals('unsupported', result.appCondition.name) 2402 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2403 self.assertEquals('retract-items', result.appCondition['feature']) 2404 2405 d = self.handleRequest(xml) 2406 self.assertFailure(d, error.StanzaError) 2407 d.addCallback(cb) 2408 return d 2409 2410 2411 def test_purge(self): 2412 """ 2413 Non-overridden L{PubSubService.purge} yields unsupported error. 2414 """ 2415 xml = """ 2416 <iq type='set' to='pubsub.example.org' 2417 from='user@example.org'> 2418 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 2419 <purge node='test'/> 2420 </pubsub> 2421 </iq> 2422 """ 2423 2424 def cb(result): 2425 self.assertEquals('feature-not-implemented', result.condition) 2426 self.assertEquals('unsupported', result.appCondition.name) 2427 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2428 self.assertEquals('purge-nodes', result.appCondition['feature']) 2429 2430 d = self.handleRequest(xml) 2431 self.assertFailure(d, error.StanzaError) 2432 d.addCallback(cb) 2433 return d 2434 2435 2436 def test_delete(self): 2437 """ 2438 Non-overridden L{PubSubService.delete} yields unsupported error. 2439 """ 2440 xml = """ 2441 <iq type='set' to='pubsub.example.org' 2442 from='user@example.org'> 2443 <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'> 2444 <delete node='test'/> 2445 </pubsub> 2446 </iq> 2447 """ 2448 2449 def cb(result): 2450 self.assertEquals('feature-not-implemented', result.condition) 2451 self.assertEquals('unsupported', result.appCondition.name) 2452 self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri) 2453 self.assertEquals('delete-nodes', result.appCondition['feature']) 2454 2455 d = self.handleRequest(xml) 2456 self.assertFailure(d, error.StanzaError) 2457 d.addCallback(cb) 2458 return d
Note: See TracBrowser
for help on using the repository browser.