Ignore:
Timestamp:
Apr 22, 2009, 5:02:02 PM (13 years ago)
Author:
Ralph Meijer <ralphm@…>
Branch:
default
Convert:
svn:b33ecbfc-034c-dc11-8662-000475d9059e/trunk@169
Message:

Add a PubSubRequest? class, to parse and render publish-subscribe requests.

Author: ralphm.
Fixes #45.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • wokkel/pubsub.py

    r52 r57  
    1717from twisted.words.xish import domish
    1818
    19 from wokkel import disco, data_form, shim
     19from wokkel import disco, data_form, generic, shim
    2020from wokkel.subprotocols import IQHandlerMixin, XMPPHandler
    2121from wokkel.iwokkel import IPubSubClient, IPubSubService
     
    3232NS_PUBSUB_NODE_CONFIG = NS_PUBSUB + "#node_config"
    3333NS_PUBSUB_META_DATA = NS_PUBSUB + "#meta-data"
    34 
    35 # In publish-subscribe namespace XPath query selector.
    36 IN_NS_PUBSUB = '[@xmlns="' + NS_PUBSUB + '"]'
    37 IN_NS_PUBSUB_OWNER = '[@xmlns="' + NS_PUBSUB_OWNER + '"]'
    38 
    39 # Publish-subscribe XPath queries
    40 PUBSUB_ELEMENT = '/pubsub' + IN_NS_PUBSUB
    41 PUBSUB_OWNER_ELEMENT = '/pubsub' + IN_NS_PUBSUB_OWNER
    42 PUBSUB_GET = IQ_GET + PUBSUB_ELEMENT
    43 PUBSUB_SET = IQ_SET + PUBSUB_ELEMENT
    44 PUBSUB_OWNER_GET = IQ_GET + PUBSUB_OWNER_ELEMENT
    45 PUBSUB_OWNER_SET = IQ_SET + PUBSUB_OWNER_ELEMENT
    46 
    47 # Publish-subscribe command XPath queries
    48 PUBSUB_PUBLISH = PUBSUB_SET + '/publish' + IN_NS_PUBSUB
    49 PUBSUB_CREATE = PUBSUB_SET + '/create' + IN_NS_PUBSUB
    50 PUBSUB_SUBSCRIBE = PUBSUB_SET + '/subscribe' + IN_NS_PUBSUB
    51 PUBSUB_UNSUBSCRIBE = PUBSUB_SET + '/unsubscribe' + IN_NS_PUBSUB
    52 PUBSUB_OPTIONS_GET = PUBSUB_GET + '/options' + IN_NS_PUBSUB
    53 PUBSUB_OPTIONS_SET = PUBSUB_SET + '/options' + IN_NS_PUBSUB
    54 PUBSUB_DEFAULT = PUBSUB_OWNER_GET + '/default' + IN_NS_PUBSUB_OWNER
    55 PUBSUB_CONFIGURE_GET = PUBSUB_OWNER_GET + '/configure' + IN_NS_PUBSUB_OWNER
    56 PUBSUB_CONFIGURE_SET = PUBSUB_OWNER_SET + '/configure' + IN_NS_PUBSUB_OWNER
    57 PUBSUB_SUBSCRIPTIONS = PUBSUB_GET + '/subscriptions' + IN_NS_PUBSUB
    58 PUBSUB_AFFILIATIONS = PUBSUB_GET + '/affiliations' + IN_NS_PUBSUB
    59 PUBSUB_AFFILIATIONS_GET = PUBSUB_OWNER_GET + '/affiliations' + \
    60                           IN_NS_PUBSUB_OWNER
    61 PUBSUB_AFFILIATIONS_SET = PUBSUB_OWNER_SET + '/affiliations' + \
    62                           IN_NS_PUBSUB_OWNER
    63 PUBSUB_SUBSCRIPTIONS_GET = PUBSUB_OWNER_GET + '/subscriptions' + \
    64                           IN_NS_PUBSUB_OWNER
    65 PUBSUB_SUBSCRIPTIONS_SET = PUBSUB_OWNER_SET + '/subscriptions' + \
    66                           IN_NS_PUBSUB_OWNER
    67 PUBSUB_ITEMS = PUBSUB_GET + '/items' + IN_NS_PUBSUB
    68 PUBSUB_RETRACT = PUBSUB_SET + '/retract' + IN_NS_PUBSUB
    69 PUBSUB_PURGE = PUBSUB_OWNER_SET + '/purge' + IN_NS_PUBSUB_OWNER
    70 PUBSUB_DELETE = PUBSUB_OWNER_SET + '/delete' + IN_NS_PUBSUB_OWNER
     34NS_PUBSUB_SUBSCRIBE_OPTIONS = NS_PUBSUB + "#subscribe_options"
     35
     36# XPath to match pubsub requests
     37PUBSUB_REQUEST = '/iq[@type="get" or @type="set"]/' + \
     38                    'pubsub[@xmlns="' + NS_PUBSUB + '" or ' + \
     39                           '@xmlns="' + NS_PUBSUB_OWNER + '"]'
    7140
    7241class SubscriptionPending(Exception):
     
    9968
    10069
    101 class BadRequest(PubSubError):
     70class BadRequest(error.StanzaError):
    10271    """
    10372    Bad request stanza error.
    10473    """
    10574    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)
    10782
    10883
     
    168143
    169144
    170 class _PubSubRequest(xmlstream.IQ):
    171     """
    172     Publish subscribe request.
    173 
    174     @ivar verb: Request verb
    175     @type verb: C{str}
    176     @ivar namespace: Request namespace.
    177     @type namespace: C{str}
    178     @ivar method: Type attribute of the IQ request. Either C{'set'} or C{'get'}
    179     @type method: C{str}
    180     @ivar command: Command element of the request. This is the direct child of
    181                    the C{pubsub} element in the C{namespace} with the name
    182                    C{verb}.
    183     """
    184 
    185     def __init__(self, xs, verb, namespace=NS_PUBSUB, method='set'):
    186         xmlstream.IQ.__init__(self, xs, method)
    187         self.addElement((namespace, 'pubsub'))
    188 
    189         self.command = self.pubsub.addElement(verb)
    190 
    191 
    192     def send(self, to):
    193         """
    194         Send out request.
    195 
    196         Extends L{xmlstream.IQ.send} by requiring the C{to} parameter to be
    197         a L{JID} instance.
    198 
    199         @param to: Entity to send the request to.
    200         @type to: L{JID}
    201         """
    202         destination = to.full()
    203         return xmlstream.IQ.send(self, destination)
     145class PubSubRequest(generic.Stanza):
     146    """
     147    A publish-subscribe request.
     148
     149    The set of instance variables used depends on the type of request. If
     150    a variable is not applicable or not passed in the request, its value is
     151    C{None}.
     152
     153    @ivar verb: The type of publish-subscribe request. See L{_requestVerbMap}.
     154    @type verb: C{str}.
     155
     156    @ivar affiliations: Affiliations to be modified.
     157    @type affiliations: C{set}
     158    @ivar items: The items to be published, as L{domish.Element}s.
     159    @type items: C{list}
     160    @ivar itemIdentifiers: Identifiers of the items to be retrieved or
     161                           retracted.
     162    @type itemIdentifiers: C{set}
     163    @ivar maxItems: Maximum number of items to retrieve.
     164    @type maxItems: C{int}.
     165    @ivar nodeIdentifier: Identifier of the node the request is about.
     166    @type nodeIdentifier: C{unicode}
     167    @ivar nodeType: The type of node that should be created, or for which the
     168                    configuration is retrieved. C{'leaf'} or C{'collection'}.
     169    @type nodeType: C{str}
     170    @ivar options: Configurations options for nodes, subscriptions and publish
     171                   requests.
     172    @type options: L{data_form.Form}
     173    @ivar subscriber: The subscribing entity.
     174    @type subscriber: L{JID}
     175    @ivar subscriptionIdentifier: Identifier for a specific subscription.
     176    @type subscriptionIdentifier: C{unicode}
     177    @ivar subscriptions: Subscriptions to be modified, as a set of
     178                         L{Subscription}.
     179    @type subscriptions: C{set}
     180    """
     181
     182    verb = None
     183
     184    affiliations = None
     185    items = None
     186    itemIdentifiers = None
     187    maxItems = None
     188    nodeIdentifier = None
     189    nodeType = None
     190    options = None
     191    subscriber = None
     192    subscriptionIdentifier = None
     193    subscriptions = None
     194
     195    # Map request iq type and subelement name to request verb
     196    _requestVerbMap = {
     197        ('set', NS_PUBSUB, 'publish'): 'publish',
     198        ('set', NS_PUBSUB, 'subscribe'): 'subscribe',
     199        ('set', NS_PUBSUB, 'unsubscribe'): 'unsubscribe',
     200        ('get', NS_PUBSUB, 'options'): 'optionsGet',
     201        ('set', NS_PUBSUB, 'options'): 'optionsSet',
     202        ('get', NS_PUBSUB, 'subscriptions'): 'subscriptions',
     203        ('get', NS_PUBSUB, 'affiliations'): 'affiliations',
     204        ('set', NS_PUBSUB, 'create'): 'create',
     205        ('get', NS_PUBSUB_OWNER, 'default'): 'default',
     206        ('get', NS_PUBSUB_OWNER, 'configure'): 'configureGet',
     207        ('set', NS_PUBSUB_OWNER, 'configure'): 'configureSet',
     208        ('get', NS_PUBSUB, 'items'): 'items',
     209        ('set', NS_PUBSUB, 'retract'): 'retract',
     210        ('set', NS_PUBSUB_OWNER, 'purge'): 'purge',
     211        ('set', NS_PUBSUB_OWNER, 'delete'): 'delete',
     212        ('get', NS_PUBSUB_OWNER, 'affiliations'): 'affiliationsGet',
     213        ('set', NS_PUBSUB_OWNER, 'affiliations'): 'affiliationsSet',
     214        ('get', NS_PUBSUB_OWNER, 'subscriptions'): 'subscriptionsGet',
     215        ('set', NS_PUBSUB_OWNER, 'subscriptions'): 'subscriptionsSet',
     216    }
     217
     218    # Map request verb to request iq type and subelement name
     219    _verbRequestMap = dict(((v, k) for k, v in _requestVerbMap.iteritems()))
     220
     221    # Map request verb to parameter handler names
     222    _parameters = {
     223        'publish': ['node', 'items'],
     224        'subscribe': ['nodeOrEmpty', 'jid'],
     225        'unsubscribe': ['nodeOrEmpty', 'jid'],
     226        'optionsGet': ['nodeOrEmpty', 'jid'],
     227        'optionsSet': ['nodeOrEmpty', 'jid', 'options'],
     228        'subscriptions': [],
     229        'affiliations': [],
     230        'create': ['nodeOrNone'],
     231        'default': ['default'],
     232        'configureGet': ['nodeOrEmpty'],
     233        'configureSet': ['nodeOrEmpty', 'configure'],
     234        'items': ['node', 'maxItems', 'itemIdentifiers'],
     235        'retract': ['node', 'itemIdentifiers'],
     236        'purge': ['node'],
     237        'delete': ['node'],
     238        'affiliationsGet': [],
     239        'affiliationsSet': [],
     240        'subscriptionsGet': [],
     241        'subscriptionsSet': [],
     242    }
     243
     244    def __init__(self, verb=None):
     245        self.verb = verb
     246
     247
     248    @staticmethod
     249    def _findForm(element, formNamespace):
     250        """
     251        Find a Data Form.
     252
     253        Look for an element that represents a Data Form with the specified
     254        form namespace as a child element of the given element.
     255        """
     256        if not element:
     257            return None
     258
     259        form = None
     260        for child in element.elements():
     261            try:
     262                form = data_form.Form.fromElement(child)
     263            except data_form.Error:
     264                continue
     265
     266            if form.formNamespace != NS_PUBSUB_NODE_CONFIG:
     267                continue
     268
     269        return form
     270
     271
     272    def _parse_node(self, verbElement):
     273        """
     274        Parse the required node identifier out of the verbElement.
     275        """
     276        try:
     277            self.nodeIdentifier = verbElement["node"]
     278        except KeyError:
     279            raise BadRequest('nodeid-required')
     280
     281
     282    def _render_node(self, verbElement):
     283        """
     284        Render the required node identifier on the verbElement.
     285        """
     286        if not self.nodeIdentifier:
     287            raise Exception("Node identifier is required")
     288
     289        verbElement['node'] = self.nodeIdentifier
     290
     291
     292    def _parse_nodeOrEmpty(self, verbElement):
     293        """
     294        Parse the node identifier out of the verbElement. May be empty.
     295        """
     296        self.nodeIdentifier = verbElement.getAttribute("node", '')
     297
     298
     299    def _render_nodeOrEmpty(self, verbElement):
     300        """
     301        Render the node identifier on the verbElement. May be empty.
     302        """
     303        if self.nodeIdentifier:
     304            verbElement['node'] = self.nodeIdentifier
     305
     306
     307    def _parse_nodeOrNone(self, verbElement):
     308        """
     309        Parse the optional node identifier out of the verbElement.
     310        """
     311        self.nodeIdentifier = verbElement.getAttribute("node")
     312
     313
     314    def _render_nodeOrNone(self, verbElement):
     315        """
     316        Render the optional node identifier on the verbElement.
     317        """
     318        if self.nodeIdentifier:
     319            verbElement['node'] = self.nodeIdentifier
     320
     321
     322    def _parse_items(self, verbElement):
     323        """
     324        Parse items out of the verbElement for publish requests.
     325        """
     326        self.items = []
     327        for element in verbElement.elements():
     328            if element.uri == NS_PUBSUB and element.name == 'item':
     329                self.items.append(element)
     330
     331
     332    def _render_items(self, verbElement):
     333        """
     334        Render items into the verbElement for publish requests.
     335        """
     336        if self.items:
     337            for item in self.items:
     338                verbElement.addChild(item)
     339
     340
     341    def _parse_jid(self, verbElement):
     342        """
     343        Parse subscriber out of the verbElement for un-/subscribe requests.
     344        """
     345        try:
     346            self.subscriber = jid.internJID(verbElement["jid"])
     347        except KeyError:
     348            raise BadRequest('jid-required')
     349
     350
     351    def _render_jid(self, verbElement):
     352        """
     353        Render subscriber into the verbElement for un-/subscribe requests.
     354        """
     355        verbElement['jid'] = self.subscriber.full()
     356
     357
     358    def _parse_default(self, verbElement):
     359        """
     360        Parse node type out of a request for the default node configuration.
     361        """
     362        form = PubSubRequest._findForm(verbElement, NS_PUBSUB_NODE_CONFIG)
     363        if form and form.formType == 'submit':
     364            values = form.getValues()
     365            self.nodeType = values.get('pubsub#node_type', 'leaf')
     366        else:
     367            self.nodeType = 'leaf'
     368
     369
     370    def _parse_configure(self, verbElement):
     371        """
     372        Parse options out of a request for setting the node configuration.
     373        """
     374        form = PubSubRequest._findForm(verbElement, NS_PUBSUB_NODE_CONFIG)
     375        if form:
     376            if form.formType == 'submit':
     377                self.options = form.getValues()
     378            elif form.formType == 'cancel':
     379                self.options = {}
     380            else:
     381                raise BadRequest(text="Unexpected form type %r" % form.formType)
     382        else:
     383            raise BadRequest(text="Missing configuration form")
     384
     385
     386
     387    def _parse_itemIdentifiers(self, verbElement):
     388        """
     389        Parse item identifiers out of items and retract requests.
     390        """
     391        self.itemIdentifiers = []
     392        for element in verbElement.elements():
     393            if element.uri == NS_PUBSUB and element.name == 'item':
     394                try:
     395                    self.itemIdentifiers.append(element["id"])
     396                except KeyError:
     397                    raise BadRequest()
     398
     399
     400    def _render_itemIdentifiers(self, verbElement):
     401        """
     402        Render item identifiers into items and retract requests.
     403        """
     404        if self.itemIdentifiers:
     405            for itemIdentifier in self.itemIdentifiers:
     406                item = verbElement.addElement('item')
     407                item['id'] = itemIdentifier
     408
     409
     410    def _parse_maxItems(self, verbElement):
     411        """
     412        Parse maximum items out of an items request.
     413        """
     414        value = verbElement.getAttribute('max_items')
     415
     416        if value:
     417            try:
     418                self.maxItems = int(value)
     419            except ValueError:
     420                raise BadRequest(text="Field max_items requires a positive " +
     421                                      "integer value")
     422
     423
     424    def _render_maxItems(self, verbElement):
     425        """
     426        Parse maximum items into an items request.
     427        """
     428        if self.maxItems:
     429            verbElement['max_items'] = unicode(self.maxItems)
     430
     431
     432    def _parse_options(self, verbElement):
     433        form = PubSubRequest._findForm(verbElement, NS_PUBSUB_SUBSCRIBE_OPTIONS)
     434        if form:
     435            if form.formType == 'submit':
     436                self.options = form.getValues()
     437            elif form.formType == 'cancel':
     438                self.options = {}
     439            else:
     440                raise BadRequest(text="Unexpected form type %r" % form.formType)
     441        else:
     442            raise BadRequest(text="Missing options form")
     443
     444    def parseElement(self, element):
     445        """
     446        Parse the publish-subscribe verb and parameters out of a request.
     447        """
     448        generic.Stanza.parseElement(self, element)
     449
     450        for child in element.pubsub.elements():
     451            key = (self.stanzaType, child.uri, child.name)
     452            try:
     453                verb = self._requestVerbMap[key]
     454            except KeyError:
     455                continue
     456            else:
     457                self.verb = verb
     458                break
     459
     460        if not self.verb:
     461            raise NotImplementedError()
     462
     463        for parameter in self._parameters[verb]:
     464            getattr(self, '_parse_%s' % parameter)(child)
     465
     466
     467    def send(self, xs):
     468        """
     469        Send this request to its recipient.
     470
     471        This renders all of the relevant parameters for this specific
     472        requests into an L{xmlstream.IQ}, and invoke its C{send} method.
     473        This returns a deferred that fires upon reception of a response. See
     474        L{xmlstream.IQ} for details.
     475
     476        @param xs: The XML stream to send the request on.
     477        @type xs: L{xmlstream.XmlStream}
     478        @rtype: L{defer.Deferred}.
     479        """
     480
     481        try:
     482            (self.stanzaType,
     483             childURI,
     484             childName) = self._verbRequestMap[self.verb]
     485        except KeyError:
     486            raise NotImplementedError()
     487
     488        iq = xmlstream.IQ(xs, self.stanzaType)
     489        iq.addElement((childURI, 'pubsub'))
     490        verbElement = iq.pubsub.addElement(childName)
     491
     492        if self.sender:
     493            iq['from'] = self.sender.full()
     494        if self.recipient:
     495            iq['to'] = self.recipient.full()
     496
     497        for parameter in self._parameters[self.verb]:
     498            getattr(self, '_render_%s' % parameter)(verbElement)
     499
     500        return iq.send()
    204501
    205502
     
    337634        @type nodeIdentifier: C{unicode}
    338635        """
    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
    344639
    345640        def cb(iq):
     
    351646            return new_node
    352647
    353         return request.send(service).addCallback(cb)
     648        d = request.send(self.xmlstream)
     649        d.addCallback(cb)
     650        return d
    354651
    355652
     
    363660        @type nodeIdentifier: C{unicode}
    364661        """
    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)
    368666
    369667
     
    380678        @type subscriber: L{JID}
    381679        """
    382         request = _PubSubRequest(self.xmlstream, 'subscribe')
    383         if nodeIdentifier:
    384             request.command['node'] = nodeIdentifier
    385         request.command['jid'] = subscriber.full()
     680        request = PubSubRequest('subscribe')
     681        request.recipient = service
     682        request.nodeIdentifier = nodeIdentifier
     683        request.subscriber = subscriber
    386684
    387685        def cb(iq):
     
    398696                return None
    399697
    400         return request.send(service).addCallback(cb)
     698        d = request.send(self.xmlstream)
     699        d.addCallback(cb)
     700        return d
    401701
    402702
     
    412712        @type subscriber: L{JID}
    413713        """
    414         request = _PubSubRequest(self.xmlstream, 'unsubscribe')
    415         if nodeIdentifier:
    416             request.command['node'] = nodeIdentifier
    417         request.command['jid'] = subscriber.full()
    418         return request.send(service)
     714        request = PubSubRequest('unsubscribe')
     715        request.recipient = service
     716        request.nodeIdentifier = nodeIdentifier
     717        request.subscriber = subscriber
     718        return request.send(self.xmlstream)
    419719
    420720
     
    430730        @type items: C{list}
    431731        """
    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)
    439737
    440738
     
    450748        @type maxItems: C{int}
    451749        """
    452         request = _PubSubRequest(self.xmlstream, 'items', method='get')
    453         if nodeIdentifier:
    454             request.command['node'] = nodeIdentifier
     750        request = PubSubRequest('items')
     751        request.recipient = service
     752        request.nodeIdentifier = nodeIdentifier
    455753        if maxItems:
    456             request.command["max_items"] = str(int(maxItems))
     754            request.maxItems = str(int(maxItems))
    457755
    458756        def cb(iq):
     
    463761            return items
    464762
    465         return request.send(service).addCallback(cb)
     763        d = request.send(self.xmlstream)
     764        d.addCallback(cb)
     765        return d
    466766
    467767
     
    498798
    499799    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',
    521801            }
    522802
     
    531811
    532812    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)
    537814
    538815
     
    586863
    587864
    588     def _findForm(self, element, formNamespace):
    589         if not element:
    590             return None
    591 
    592         form = None
    593         for child in element.elements():
    594             try:
    595                 form = data_form.Form.fromElement(child)
    596             except data_form.Error:
    597                 continue
    598 
    599             if form.formNamespace != NS_PUBSUB_NODE_CONFIG:
    600                 continue
    601 
    602         return form
    603 
    604 
    605     def _getParameter_node(self, commandElement):
    606         try:
    607             return commandElement["node"]
    608         except KeyError:
    609             raise BadRequest('nodeid-required')
    610 
    611 
    612     def _getParameter_nodeOrEmpty(self, commandElement):
    613         return commandElement.getAttribute("node", '')
    614 
    615 
    616     def _getParameter_jid(self, commandElement):
    617         try:
    618             return jid.internJID(commandElement["jid"])
    619         except KeyError:
    620             raise BadRequest('jid-required')
    621 
    622 
    623     def _getParameter_max_items(self, commandElement):
    624         value = commandElement.getAttribute('max_items')
    625 
    626         if value:
    627             try:
    628                 return int(value)
    629             except ValueError:
    630                 raise BadRequest(text="Field max_items requires a positive " +
    631                                       "integer value")
    632         else:
    633             return None
    634 
    635 
    636     def _getParameters(self, iq, *names):
    637         requestor = jid.internJID(iq["from"]).userhostJID()
    638         service = jid.internJID(iq["to"])
    639 
    640         params = [requestor, service]
    641 
    642         if names:
    643             command = names[0]
    644             commandElement = getattr(iq.pubsub, command)
    645             if not commandElement:
    646                 raise Exception("Could not find command element %r" % command)
    647 
    648         for name in names[1:]:
    649             try:
    650                 getter = getattr(self, '_getParameter_' + name)
    651             except KeyError:
    652                 raise Exception("No parameter getter for this name")
    653 
    654             params.append(getter(commandElement))
    655 
    656         return params
    657 
    658 
    659     def _onPublish(self, iq):
    660         requestor, service, nodeIdentifier = self._getParameters(
    661                 iq, 'publish', 'node')
    662 
    663         items = []
    664         for element in iq.pubsub.publish.elements():
    665             if element.uri == NS_PUBSUB and element.name == 'item':
    666                 items.append(element)
    667 
    668         return self.publish(requestor, service, nodeIdentifier, items)
    669 
    670 
    671     def _onSubscribe(self, iq):
    672         requestor, service, nodeIdentifier, subscriber = self._getParameters(
    673                 iq, 'subscribe', 'nodeOrEmpty', 'jid')
     865    def _onPubSubRequest(self, iq):
     866        request = PubSubRequest.fromElement(iq)
     867        handler = getattr(self, '_on_%s' % request.verb)
     868        return handler(request)
     869
     870
     871    def _on_publish(self, request):
     872        return self.publish(request.sender, request.recipient,
     873                            request.nodeIdentifier, request.items)
     874
     875
     876    def _on_subscribe(self, request):
    674877
    675878        def toResponse(result):
     
    682885            return response
    683886
    684         d = self.subscribe(requestor, service, nodeIdentifier, subscriber)
     887        d = self.subscribe(request.sender, request.recipient,
     888                           request.nodeIdentifier, request.subscriber)
    685889        d.addCallback(toResponse)
    686890        return d
    687891
    688892
    689     def _onUnsubscribe(self, iq):
    690         requestor, service, nodeIdentifier, subscriber = self._getParameters(
    691                 iq, 'unsubscribe', 'nodeOrEmpty', 'jid')
    692 
    693         return self.unsubscribe(requestor, service, nodeIdentifier, subscriber)
    694 
    695 
    696     def _onOptionsGet(self, iq):
     893    def _on_unsubscribe(self, request):
     894        return self.unsubscribe(request.sender, request.recipient,
     895                                request.nodeIdentifier, request.subscriber)
     896
     897
     898    def _on_optionsGet(self, request):
    697899        raise Unsupported('subscription-options')
    698900
    699901
    700     def _onOptionsSet(self, iq):
     902    def _on_optionsSet(self, request):
    701903        raise Unsupported('subscription-options')
    702904
    703905
    704     def _onSubscriptions(self, iq):
    705         requestor, service = self._getParameters(iq)
     906    def _on_subscriptions(self, request):
    706907
    707908        def toResponse(result):
     
    715916            return response
    716917
    717         d = self.subscriptions(requestor, service)
     918        d = self.subscriptions(request.sender, request.recipient)
    718919        d.addCallback(toResponse)
    719920        return d
    720921
    721922
    722     def _onAffiliations(self, iq):
    723         requestor, service = self._getParameters(iq)
     923    def _on_affiliations(self, request):
    724924
    725925        def toResponse(result):
     
    734934            return response
    735935
    736         d = self.affiliations(requestor, service)
     936        d = self.affiliations(request.sender, request.recipient)
    737937        d.addCallback(toResponse)
    738938        return d
    739939
    740940
    741     def _onCreate(self, iq):
    742         requestor, service = self._getParameters(iq)
    743         nodeIdentifier = iq.pubsub.create.getAttribute("node")
     941    def _on_create(self, request):
    744942
    745943        def toResponse(result):
    746             if not nodeIdentifier or nodeIdentifier != result:
     944            if not request.nodeIdentifier or request.nodeIdentifier != result:
    747945                response = domish.Element((NS_PUBSUB, 'pubsub'))
    748946                create = response.addElement('create')
     
    752950                return None
    753951
    754         d = self.create(requestor, service, nodeIdentifier)
     952        d = self.create(request.sender, request.recipient,
     953                        request.nodeIdentifier)
    755954        d.addCallback(toResponse)
    756955        return d
     
    772971        return fields
    773972
     973
    774974    def _formFromConfiguration(self, values):
    775975        options = self.getConfigurationOptions()
     
    780980
    781981        return form
     982
    782983
    783984    def _checkConfiguration(self, values):
     
    8061007
    8071008
    808     def _onDefault(self, iq):
    809         requestor, service = self._getParameters(iq)
     1009    def _on_default(self, request):
    8101010
    8111011        def toResponse(options):
     
    8151015            return response
    8161016
    817         form = self._findForm(iq.pubsub.config, NS_PUBSUB_NODE_CONFIG)
    818         values = form and form.formType == 'result' and form.getValues() or {}
    819         nodeType = values.get('pubsub#node_type', 'leaf')
    820 
    821         if nodeType not in ('leaf', 'collections'):
     1017        if request.nodeType not in ('leaf', 'collection'):
    8221018            return defer.fail(error.StanzaError('not-acceptable'))
    8231019
    824         d = self.getDefaultConfiguration(requestor, service, nodeType)
     1020        d = self.getDefaultConfiguration(request.sender, request.recipient,
     1021                                         request.nodeType)
    8251022        d.addCallback(toResponse)
    8261023        return d
    8271024
    8281025
    829     def _onConfigureGet(self, iq):
    830         requestor, service, nodeIdentifier = self._getParameters(
    831                 iq, 'configure', 'nodeOrEmpty')
    832 
     1026    def _on_configureGet(self, request):
    8331027        def toResponse(options):
    8341028            response = domish.Element((NS_PUBSUB_OWNER, "pubsub"))
    8351029            configure = response.addElement("configure")
    836             configure.addChild(self._formFromConfiguration(options).toElement())
    837 
    838             if nodeIdentifier:
    839                 configure["node"] = nodeIdentifier
     1030            form = self._formFromConfiguration(options)
     1031            configure.addChild(form.toElement())
     1032
     1033            if request.nodeIdentifier:
     1034                configure["node"] = request.nodeIdentifier
    8401035
    8411036            return response
    8421037
    843         d = self.getConfiguration(requestor, service, nodeIdentifier)
     1038        d = self.getConfiguration(request.sender, request.recipient,
     1039                                  request.nodeIdentifier)
    8441040        d.addCallback(toResponse)
    8451041        return d
    8461042
    8471043
    848     def _onConfigureSet(self, iq):
    849         requestor, service, nodeIdentifier = self._getParameters(
    850                 iq, 'configure', 'nodeOrEmpty')
    851 
    852         # Search configuration form with correct FORM_TYPE and process it
    853 
    854         form = self._findForm(iq.pubsub.configure, NS_PUBSUB_NODE_CONFIG)
    855 
    856         if form:
    857             if form.formType == 'submit':
    858                 options = self._checkConfiguration(form.getValues())
    859 
    860                 return self.setConfiguration(requestor, service,
    861                                              nodeIdentifier, options)
    862             elif form.formType == 'cancel':
    863                 return None
    864 
    865         raise BadRequest()
    866 
    867 
    868     def _onItems(self, iq):
    869         requestor, service, nodeIdentifier, maxItems = self._getParameters(
    870                 iq, 'items', 'nodeOrEmpty', 'max_items')
    871 
    872         itemIdentifiers = []
    873         for child in iq.pubsub.items.elements():
    874             if child.name == 'item' and child.uri == NS_PUBSUB:
    875                 try:
    876                     itemIdentifiers.append(child["id"])
    877                 except KeyError:
    878                     raise BadRequest()
     1044    def _on_configureSet(self, request):
     1045        if request.options:
     1046            request.options = self._checkConfiguration(request.options)
     1047            return self.setConfiguration(request.sender, request.recipient,
     1048                                         request.nodeIdentifier,
     1049                                         request.options)
     1050        else:
     1051            return None
     1052
     1053
     1054
     1055    def _on_items(self, request):
    8791056
    8801057        def toResponse(result):
    8811058            response = domish.Element((NS_PUBSUB, 'pubsub'))
    8821059            items = response.addElement('items')
    883             if nodeIdentifier:
    884                 items["node"] = nodeIdentifier
     1060            items["node"] = request.nodeIdentifier
    8851061
    8861062            for item in result:
     
    8891065            return response
    8901066
    891         d = self.items(requestor, service, nodeIdentifier, maxItems,
    892                        itemIdentifiers)
     1067        d = self.items(request.sender, request.recipient,
     1068                       request.nodeIdentifier, request.maxItems,
     1069                       request.itemIdentifiers)
    8931070        d.addCallback(toResponse)
    8941071        return d
    8951072
    8961073
    897     def _onRetract(self, iq):
    898         requestor, service, nodeIdentifier = self._getParameters(
    899                 iq, 'retract', 'node')
    900 
    901         itemIdentifiers = []
    902         for child in iq.pubsub.retract.elements():
    903             if child.uri == NS_PUBSUB and child.name == 'item':
    904                 try:
    905                     itemIdentifiers.append(child["id"])
    906                 except KeyError:
    907                     raise BadRequest()
    908 
    909         return self.retract(requestor, service, nodeIdentifier,
    910                             itemIdentifiers)
    911 
    912 
    913     def _onPurge(self, iq):
    914         requestor, service, nodeIdentifier = self._getParameters(
    915                 iq, 'purge', 'node')
    916         return self.purge(requestor, service, nodeIdentifier)
    917 
    918 
    919     def _onDelete(self, iq):
    920         requestor, service, nodeIdentifier = self._getParameters(
    921                 iq, 'delete', 'node')
    922         return self.delete(requestor, service, nodeIdentifier)
    923 
    924 
    925     def _onAffiliationsGet(self, iq):
     1074    def _on_retract(self, request):
     1075        return self.retract(request.sender, request.recipient,
     1076                            request.nodeIdentifier, request.itemIdentifiers)
     1077
     1078
     1079    def _on_purge(self, request):
     1080        return self.purge(request.sender, request.recipient,
     1081                          request.nodeIdentifier)
     1082
     1083
     1084    def _on_delete(self, request):
     1085        return self.delete(request.sender, request.recipient,
     1086                           request.nodeIdentifier)
     1087
     1088
     1089    def _on_affiliationsGet(self, iq):
    9261090        raise Unsupported('modify-affiliations')
    9271091
    9281092
    929     def _onAffiliationsSet(self, iq):
     1093    def _on_affiliationsSet(self, iq):
    9301094        raise Unsupported('modify-affiliations')
    9311095
    9321096
    933     def _onSubscriptionsGet(self, iq):
     1097    def _on_subscriptionsGet(self, iq):
    9341098        raise Unsupported('manage-subscriptions')
    9351099
    9361100
    937     def _onSubscriptionsSet(self, iq):
     1101    def _on_subscriptionsSet(self, iq):
    9381102        raise Unsupported('manage-subscriptions')
    9391103
Note: See TracChangeset for help on using the changeset viewer.