Changeset 83:81daaca3d75f


Ignore:
Timestamp:
Jan 5, 2010, 2:55:40 PM (12 years ago)
Author:
Ralph Meijer <ralphm@…>
Branch:
default
Message:

Add support for subscription options in subscribe requests

Fixes #63.

Location:
wokkel
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • wokkel/pubsub.py

    r82 r83  
    229229    _parameters = {
    230230        'publish': ['node', 'items'],
    231         'subscribe': ['nodeOrEmpty', 'jid'],
     231        'subscribe': ['nodeOrEmpty', 'jid', 'optionsWithSubscribe'],
    232232        'unsubscribe': ['nodeOrEmpty', 'jid'],
    233233        'optionsGet': ['nodeOrEmpty', 'jid'],
     
    373373                form = data_form.findForm(element, NS_PUBSUB_NODE_CONFIG)
    374374                if form:
    375                     if form.formType == 'submit':
    376                         self.options = form
    377                     else:
     375                    if form.formType != 'submit':
    378376                        raise BadRequest(text=u"Unexpected form type '%s'" %
    379377                                              form.formType)
     
    381379                    form = data_form.Form('submit',
    382380                                          formNamespace=NS_PUBSUB_NODE_CONFIG)
    383                     self.options = form
     381                self.options = form
    384382
    385383
     
    452450
    453451
     452
     453    def _render_options(self, verbElement):
     454        verbElement.addChild(self.options.toElement())
     455
     456
     457    def _parse_optionsWithSubscribe(self, verbElement):
     458        for element in verbElement.parent.elements():
     459            if element.name == 'options' and element.uri == NS_PUBSUB:
     460                form = data_form.findForm(element,
     461                                          NS_PUBSUB_SUBSCRIBE_OPTIONS)
     462                if form:
     463                    if form.formType != 'submit':
     464                        raise BadRequest(text=u"Unexpected form type '%s'" %
     465                                              form.formType)
     466                else:
     467                    form = data_form.Form('submit',
     468                                          formNamespace=NS_PUBSUB_SUBSCRIBE_OPTIONS)
     469                self.options = form
     470
     471
     472    def _render_optionsWithSubscribe(self, verbElement):
     473        if self.options:
     474            optionsElement = verbElement.parent.addElement('options')
     475            self._render_options(optionsElement)
     476
     477
    454478    def parseElement(self, element):
    455479        """
     
    458482        generic.Stanza.parseElement(self, element)
    459483
     484        verbs = []
     485        children = []
    460486        for child in element.pubsub.elements():
    461487            key = (self.stanzaType, child.uri, child.name)
     
    464490            except KeyError:
    465491                continue
     492
     493            verbs.append(verb)
     494            children.append(child)
     495
     496        if not verbs:
     497            raise NotImplementedError()
     498
     499        if len(verbs) > 1:
     500            if 'optionsSet' in verbs and 'subscribe' in verbs:
     501                self.verb = 'subscribe'
     502                child = children[verbs.index('subscribe')]
    466503            else:
    467                 self.verb = verb
    468                 break
    469 
    470         if not self.verb:
    471             raise NotImplementedError()
    472 
    473         for parameter in self._parameters[verb]:
     504                raise NotImplementedError()
     505        else:
     506            self.verb = verbs[0]
     507
     508        for parameter in self._parameters[self.verb]:
    474509            getattr(self, '_parse_%s' % parameter)(child)
     510
    475511
    476512
     
    687723
    688724
    689     def subscribe(self, service, nodeIdentifier, subscriber, sender=None):
     725    def subscribe(self, service, nodeIdentifier, subscriber,
     726                        options=None, sender=None):
    690727        """
    691728        Subscribe to a publish subscribe node.
     
    698735                           will get notifications of new published items.
    699736        @type subscriber: L{JID}
     737        @param options: Subscription options.
     738        @type options: C{dict}.
    700739        """
    701740        request = PubSubRequest('subscribe')
     
    704743        request.subscriber = subscriber
    705744        request.sender = sender
     745
     746        if options:
     747            form = data_form.Form(formType='submit',
     748                                  formNamespace=NS_PUBSUB_SUBSCRIBE_OPTIONS)
     749            form.makeFields(options)
     750            request.options = form
    706751
    707752        def cb(iq):
     
    788833        d = request.send(self.xmlstream)
    789834        d.addCallback(cb)
     835        return d
     836
     837
     838    def getOptions(self, service, nodeIdentifier, subscriber, sender=None):
     839        """
     840        Get subscription options.
     841
     842        @param service: The publish subscribe service that keeps the node.
     843        @type service: L{JID}
     844
     845        @param nodeIdentifier: The identifier of the node.
     846        @type nodeIdentifier: C{unicode}
     847
     848        @param subscriber: The entity subscribed to the node.
     849        @type subscriber: L{JID}
     850
     851        @rtype: L{data_form.Form}
     852        """
     853        request = PubSubRequest('optionsGet')
     854        request.recipient = service
     855        request.nodeIdentifier = nodeIdentifier
     856        request.subscriber = subscriber
     857        request.sender = sender
     858
     859        def cb(iq):
     860            form = data_form.findForm(iq.pubsub.options,
     861                                      NS_PUBSUB_SUBSCRIBE_OPTIONS)
     862            form.typeCheck()
     863            return form
     864
     865        d = request.send(self.xmlstream)
     866        d.addCallback(cb)
     867        return d
     868
     869
     870    def setOptions(self, service, nodeIdentifier, subscriber,
     871                         options, sender=None):
     872        """
     873        Set subscription options.
     874
     875        @param service: The publish subscribe service that keeps the node.
     876        @type service: L{JID}
     877
     878        @param nodeIdentifier: The identifier of the node.
     879        @type nodeIdentifier: C{unicode}
     880
     881        @param subscriber: The entity subscribed to the node.
     882        @type subscriber: L{JID}
     883
     884        @param options: Subscription options.
     885        @type options: C{dict}.
     886        """
     887        request = PubSubRequest('optionsSet')
     888        request.recipient = service
     889        request.nodeIdentifier = nodeIdentifier
     890        request.subscriber = subscriber
     891        request.sender = sender
     892
     893        form = data_form.Form(formType='submit',
     894                              formNamespace=NS_PUBSUB_SUBSCRIBE_OPTIONS)
     895        form.makeFields(options)
     896        request.options = form
     897
     898        d = request.send(self.xmlstream)
    790899        return d
    791900
  • wokkel/test/test_pubsub.py

    r82 r83  
    2525NS_PUBSUB_OWNER = 'http://jabber.org/protocol/pubsub#owner'
    2626NS_PUBSUB_META_DATA = 'http://jabber.org/protocol/pubsub#meta-data'
     27NS_PUBSUB_SUBSCRIBE_OPTIONS = 'http://jabber.org/protocol/pubsub#subscribe_options'
    2728
    2829def calledAsync(fn):
     
    483484
    484485
     486    def test_subscribeWithOptions(self):
     487        options = {'pubsub#deliver': False}
     488
     489        d = self.protocol.subscribe(JID('pubsub.example.org'), 'test',
     490                                    JID('user@example.org'),
     491                                    options=options)
     492        iq = self.stub.output[-1]
     493
     494        # Check options present
     495        childNames = []
     496        for element in iq.pubsub.elements():
     497            if element.uri == NS_PUBSUB:
     498                childNames.append(element.name)
     499
     500        self.assertEqual(['subscribe', 'options'], childNames)
     501        form = data_form.findForm(iq.pubsub.options,
     502                                  NS_PUBSUB_SUBSCRIBE_OPTIONS)
     503        self.assertEqual('submit', form.formType)
     504        form.typeCheck({'pubsub#deliver': {'type': 'boolean'}})
     505        self.assertEqual(options, form.getValues())
     506
     507        # Send response
     508        response = toResponse(iq, 'result')
     509        pubsub = response.addElement((NS_PUBSUB, 'pubsub'))
     510        subscription = pubsub.addElement('subscription')
     511        subscription['node'] = 'test'
     512        subscription['jid'] = 'user@example.org'
     513        subscription['subscription'] = 'subscribed'
     514        self.stub.send(response)
     515
     516        return d
     517
     518
    485519    def test_subscribeWithSender(self):
    486520        """
     
    626660
    627661
     662    def test_getOptions(self):
     663        def cb(form):
     664            self.assertEqual('form', form.formType)
     665            self.assertEqual(NS_PUBSUB_SUBSCRIBE_OPTIONS, form.formNamespace)
     666            field = form.fields['pubsub#deliver']
     667            self.assertEqual('boolean', field.fieldType)
     668            self.assertIdentical(True, field.value)
     669            self.assertEqual('Enable delivery?', field.label)
     670
     671        d = self.protocol.getOptions(JID('pubsub.example.org'), 'test',
     672                                     JID('user@example.org'),
     673                                     sender=JID('user@example.org'))
     674        d.addCallback(cb)
     675
     676        iq = self.stub.output[-1]
     677        self.assertEqual('pubsub.example.org', iq.getAttribute('to'))
     678        self.assertEqual('get', iq.getAttribute('type'))
     679        self.assertEqual('pubsub', iq.pubsub.name)
     680        self.assertEqual(NS_PUBSUB, iq.pubsub.uri)
     681        children = list(domish.generateElementsQNamed(iq.pubsub.children,
     682                                                      'options', NS_PUBSUB))
     683        self.assertEqual(1, len(children))
     684        child = children[0]
     685        self.assertEqual('test', child['node'])
     686
     687        self.assertEqual(0, len(child.children))
     688
     689        # Send response
     690        form = data_form.Form('form', formNamespace=NS_PUBSUB_SUBSCRIBE_OPTIONS)
     691        form.addField(data_form.Field('boolean', var='pubsub#deliver',
     692                                                 label='Enable delivery?',
     693                                                 value=True))
     694        response = toResponse(iq, 'result')
     695        response.addElement((NS_PUBSUB, 'pubsub'))
     696        response.pubsub.addElement('options')
     697        response.pubsub.options.addChild(form.toElement())
     698        self.stub.send(response)
     699
     700        return d
     701
     702
     703    def test_setOptions(self):
     704        """
     705        setOptions should send out a options-set request.
     706        """
     707        options = {'pubsub#deliver': False}
     708
     709        d = self.protocol.setOptions(JID('pubsub.example.org'), 'test',
     710                                     JID('user@example.org'),
     711                                     options,
     712                                     sender=JID('user@example.org'))
     713
     714        iq = self.stub.output[-1]
     715        self.assertEqual('pubsub.example.org', iq.getAttribute('to'))
     716        self.assertEqual('set', iq.getAttribute('type'))
     717        self.assertEqual('pubsub', iq.pubsub.name)
     718        self.assertEqual(NS_PUBSUB, iq.pubsub.uri)
     719        children = list(domish.generateElementsQNamed(iq.pubsub.children,
     720                                                      'options', NS_PUBSUB))
     721        self.assertEqual(1, len(children))
     722        child = children[0]
     723        self.assertEqual('test', child['node'])
     724
     725        form = data_form.findForm(child, NS_PUBSUB_SUBSCRIBE_OPTIONS)
     726        self.assertEqual('submit', form.formType)
     727        form.typeCheck({'pubsub#deliver': {'type': 'boolean'}})
     728        self.assertEqual(options, form.getValues())
     729
     730        response = toResponse(iq, 'result')
     731        self.stub.send(response)
     732
     733        return d
     734
    628735
    629736class PubSubRequestTest(unittest.TestCase):
     737
     738    def test_fromElementUnknown(self):
     739        """
     740        An unknown verb raises NotImplementedError.
     741        """
     742
     743        xml = """
     744        <iq type='set' to='pubsub.example.org'
     745                       from='user@example.org'>
     746          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     747            <non-existing-verb/>
     748          </pubsub>
     749        </iq>
     750        """
     751
     752        self.assertRaises(NotImplementedError,
     753                          pubsub.PubSubRequest.fromElement, parseXml(xml))
     754
     755
     756    def test_fromElementKnownBadCombination(self):
     757        """
     758        Multiple verbs in an unknown configuration raises NotImplementedError.
     759        """
     760
     761        xml = """
     762        <iq type='set' to='pubsub.example.org'
     763                       from='user@example.org'>
     764          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     765             <publish/>
     766             <create/>
     767          </pubsub>
     768        </iq>
     769        """
     770
     771        self.assertRaises(NotImplementedError,
     772                          pubsub.PubSubRequest.fromElement, parseXml(xml))
    630773
    631774    def test_fromElementPublish(self):
     
    753896        self.assertEqual(NS_PUBSUB_ERRORS, err.appCondition.uri)
    754897        self.assertEqual('jid-required', err.appCondition.name)
     898
     899
     900    def test_fromElementSubscribeWithOptions(self):
     901        """
     902        Test parsing a subscription request.
     903        """
     904
     905        xml = """
     906        <iq type='set' to='pubsub.example.org'
     907                       from='user@example.org'>
     908          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     909            <subscribe node='test' jid='user@example.org/Home'/>
     910            <options>
     911              <x xmlns="jabber:x:data" type='submit'>
     912                <field var='FORM_TYPE' type='hidden'>
     913                  <value>http://jabber.org/protocol/pubsub#subscribe_options</value>
     914                </field>
     915                <field var='pubsub#deliver' type='boolean'
     916                       label='Enable delivery?'>
     917                  <value>1</value>
     918                </field>
     919              </x>
     920            </options>
     921          </pubsub>
     922        </iq>
     923        """
     924
     925        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
     926        self.assertEqual('subscribe', request.verb)
     927        request.options.typeCheck({'pubsub#deliver': {'type': 'boolean'}})
     928        self.assertEqual({'pubsub#deliver': True}, request.options.getValues())
     929
     930
     931    def test_fromElementSubscribeWithOptionsBadFormType(self):
     932        """
     933        The options form should have the right type.
     934        """
     935
     936        xml = """
     937        <iq type='set' to='pubsub.example.org'
     938                       from='user@example.org'>
     939          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     940            <subscribe node='test' jid='user@example.org/Home'/>
     941            <options>
     942              <x xmlns="jabber:x:data" type='result'>
     943                <field var='FORM_TYPE' type='hidden'>
     944                  <value>http://jabber.org/protocol/pubsub#subscribe_options</value>
     945                </field>
     946                <field var='pubsub#deliver' type='boolean'
     947                       label='Enable delivery?'>
     948                  <value>1</value>
     949                </field>
     950              </x>
     951            </options>
     952          </pubsub>
     953        </iq>
     954        """
     955
     956        err = self.assertRaises(error.StanzaError,
     957                                pubsub.PubSubRequest.fromElement,
     958                                parseXml(xml))
     959        self.assertEqual('bad-request', err.condition)
     960        self.assertEqual("Unexpected form type 'result'", err.text)
     961        self.assertEqual(None, err.appCondition)
     962
     963
     964    def test_fromElementSubscribeWithOptionsEmpty(self):
     965        """
     966        When no (suitable) form is found, the options are empty.
     967        """
     968
     969        xml = """
     970        <iq type='set' to='pubsub.example.org'
     971                       from='user@example.org'>
     972          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
     973            <subscribe node='test' jid='user@example.org/Home'/>
     974            <options/>
     975          </pubsub>
     976        </iq>
     977        """
     978
     979        request = pubsub.PubSubRequest.fromElement(parseXml(xml))
     980        self.assertEqual('subscribe', request.verb)
     981        self.assertEqual({}, request.options.getValues())
     982
    755983
    756984    def test_fromElementUnsubscribe(self):
Note: See TracChangeset for help on using the changeset viewer.