Changeset 93:8f0856ddc616


Ignore:
Timestamp:
Feb 12, 2011, 10:58:46 PM (10 years ago)
Author:
Ralph Meijer <ralphm@…>
Branch:
default
Message:

Add support for managing affiliations of Publish-Subscribe nodes, server-side.

Location:
wokkel
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • wokkel/iwokkel.py

    r59 r93  
    1 # Copyright (c) 2003-2008 Ralph Meijer
     1# Copyright (c) 2003-2011 Ralph Meijer
    22# See LICENSE for details.
    33
     
    768768        @rtype: L{defer.Deferred}
    769769        """
     770
     771
     772    def affiliationsGet(request):
     773        """
     774        Called when a affiliations retrieval request (owner) has been received.
     775
     776        @param request: The publish-subscribe request.
     777        @type request: L{wokkel.pubsub.PubSubRequest}
     778        @return: A deferred that fires with a C{dict} of affiliations with the
     779            entity as key (L{JID}) and the affiliation state as value
     780            (C{unicode}).  The affiliation can be C{u'owner'}, C{u'publisher'},
     781            or C{u'outcast'}.
     782        @rtype: L{defer.Deferred}
     783
     784        @note: Affiliations are always on the bare JID. An implementation of
     785        this method MUST NOT return JIDs with a resource part.
     786        """
     787
     788
     789    def affiliationsSet(request):
     790        """
     791        Called when a affiliations modify request has been received.
     792
     793        @param request: The publish-subscribe request.
     794        @type request: L{wokkel.pubsub.PubSubRequest}
     795        @return: A deferred that fires with C{None} when the affiliation
     796            changes were succesfully processed..
     797        @rtype: L{defer.Deferred}
     798
     799        @note: Affiliations are always on the bare JID. The JIDs in
     800        L{wokkel.pubsub.PubSubRequest.affiliations} are already stripped of
     801        any resource.
     802        """
  • wokkel/pubsub.py

    r92 r93  
    221221                         L{Subscription}.
    222222    @type subscriptions: C{set}
     223    @ivar affiliations: Affiliations to be modified, as a dictionary of entity
     224                        (L{JID} to affiliation (C{unicode}).
     225    @type affiliations: C{dict}
    223226    """
    224227
     
    235238    subscriptionIdentifier = None
    236239    subscriptions = None
     240    affiliations = None
    237241
    238242    # Map request iq type and subelement name to request verb
     
    280284        'delete': ['node'],
    281285        'affiliationsGet': ['nodeOrEmpty'],
    282         'affiliationsSet': [],
     286        'affiliationsSet': ['nodeOrEmpty', 'affiliations'],
    283287        'subscriptionsGet': ['nodeOrEmpty'],
    284288        'subscriptionsSet': [],
     
    525529            optionsElement = verbElement.parent.addElement('options')
    526530            self._render_options(optionsElement)
     531
     532
     533    def _parse_affiliations(self, verbElement):
     534        self.affiliations = {}
     535        for element in verbElement.elements():
     536            if (element.uri == NS_PUBSUB_OWNER and
     537                element.name == 'affiliation'):
     538                try:
     539                    entity = jid.internJID(element['jid']).userhostJID()
     540                except KeyError:
     541                    raise BadRequest(text='Missing jid attribute')
     542
     543                if entity in self.affiliations:
     544                    raise BadRequest(text='Multiple affiliations for an entity')
     545
     546                try:
     547                    affiliation = element['affiliation']
     548                except KeyError:
     549                    raise BadRequest(text='Missing affiliation attribute')
     550
     551                self.affiliations[entity] = affiliation
    527552
    528553
     
    13041329        return message
    13051330
     1331
     1332    def _toResponse_affiliationsGet(self, result, resource, request):
     1333        response = domish.Element((NS_PUBSUB_OWNER, 'pubsub'))
     1334        affiliations = response.addElement('affiliations')
     1335
     1336        if request.nodeIdentifier:
     1337            affiliations['node'] = request.nodeIdentifier
     1338
     1339        for entity, affiliation in result.iteritems():
     1340            item = affiliations.addElement('affiliation')
     1341            item['jid'] = entity.full()
     1342            item['affiliation'] = affiliation
     1343
     1344        return response
     1345
     1346
    13061347    # public methods
    13071348
  • wokkel/test/test_pubsub.py

    r92 r93  
    31933193    def test_on_affiliationsGet(self):
    31943194        """
    3195         Getting subscription options is not supported.
     3195        Getting node affiliations should have.
     3196        """
     3197
     3198        xml = """
     3199        <iq type='get' to='pubsub.example.org'
     3200                       from='user@example.org'>
     3201          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
     3202            <affiliations node='test'/>
     3203          </pubsub>
     3204        </iq>
     3205        """
     3206
     3207        def affiliationsGet(request):
     3208            self.assertEquals('test', request.nodeIdentifier)
     3209            return defer.succeed({JID('user@example.org'): 'owner'})
     3210
     3211        def cb(element):
     3212            self.assertEquals(u'pubsub', element.name)
     3213            self.assertEquals(NS_PUBSUB_OWNER, element.uri)
     3214            self.assertEquals(NS_PUBSUB_OWNER, element.affiliations.uri)
     3215            self.assertEquals(u'test', element.affiliations[u'node'])
     3216            children = list(element.affiliations.elements())
     3217            self.assertEquals(1, len(children))
     3218            affiliation = children[0]
     3219            self.assertEquals(u'affiliation', affiliation.name)
     3220            self.assertEquals(NS_PUBSUB_OWNER, affiliation.uri)
     3221            self.assertEquals(u'user@example.org', affiliation[u'jid'])
     3222            self.assertEquals(u'owner', affiliation[u'affiliation'])
     3223
     3224        self.resource.affiliationsGet = affiliationsGet
     3225        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
     3226        d = self.handleRequest(xml)
     3227        d.addCallback(cb)
     3228        return d
     3229
     3230
     3231    def test_on_affiliationsGetEmptyNode(self):
     3232        """
     3233        Getting node affiliations without node should assume empty node.
    31963234        """
    31973235
     
    32053243        """
    32063244
     3245        def affiliationsGet(request):
     3246            self.assertIdentical('', request.nodeIdentifier)
     3247            return defer.succeed({})
     3248
     3249        def cb(element):
     3250            self.assertFalse(element.affiliations.hasAttribute(u'node'))
     3251
     3252        self.resource.affiliationsGet = affiliationsGet
     3253        verify.verifyObject(iwokkel.IPubSubResource, self.resource)
     3254        d = self.handleRequest(xml)
     3255        d.addCallback(cb)
     3256        return d
     3257
     3258
     3259    def test_on_affiliationsSet(self):
     3260        """
     3261        Setting node affiliations has the affiliations to be modified.
     3262        """
     3263
     3264        xml = """
     3265        <iq type='set' to='pubsub.example.org'
     3266                       from='user@example.org'>
     3267          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
     3268            <affiliations node='test'>
     3269              <affiliation jid='other@example.org' affiliation='publisher'/>
     3270            </affiliations>
     3271          </pubsub>
     3272        </iq>
     3273        """
     3274
     3275        def affiliationsSet(request):
     3276            self.assertEquals(u'test', request.nodeIdentifier)
     3277            otherJID = JID(u'other@example.org')
     3278            self.assertIn(otherJID, request.affiliations)
     3279            self.assertEquals(u'publisher', request.affiliations[otherJID])
     3280
     3281        self.resource.affiliationsSet = affiliationsSet
     3282        return self.handleRequest(xml)
     3283
     3284
     3285    def test_on_affiliationsSetBareJID(self):
     3286        """
     3287        Affiliations are always on the bare JID.
     3288        """
     3289
     3290        xml = """
     3291        <iq type='set' to='pubsub.example.org'
     3292                       from='user@example.org'>
     3293          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
     3294            <affiliations node='test'>
     3295              <affiliation jid='other@example.org/Home'
     3296                           affiliation='publisher'/>
     3297            </affiliations>
     3298          </pubsub>
     3299        </iq>
     3300        """
     3301
     3302        def affiliationsSet(request):
     3303            otherJID = JID(u'other@example.org')
     3304            self.assertIn(otherJID, request.affiliations)
     3305
     3306        self.resource.affiliationsSet = affiliationsSet
     3307        return self.handleRequest(xml)
     3308
     3309
     3310    def test_on_affiliationsSetMultipleForSameEntity(self):
     3311        """
     3312        Setting node affiliations can only have one item per entity.
     3313        """
     3314
     3315        xml = """
     3316        <iq type='set' to='pubsub.example.org'
     3317                       from='user@example.org'>
     3318          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
     3319            <affiliations node='test'>
     3320              <affiliation jid='other@example.org' affiliation='publisher'/>
     3321              <affiliation jid='other@example.org' affiliation='owner'/>
     3322            </affiliations>
     3323          </pubsub>
     3324        </iq>
     3325        """
     3326
    32073327        def cb(result):
    3208             self.assertEquals('feature-not-implemented', result.condition)
    3209             self.assertEquals('unsupported', result.appCondition.name)
    3210             self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
    3211             self.assertEquals('modify-affiliations',
    3212                               result.appCondition['feature'])
     3328            self.assertEquals('bad-request', result.condition)
    32133329
    32143330        d = self.handleRequest(xml)
     
    32183334
    32193335
    3220     def test_on_affiliationsSet(self):
    3221         """
    3222         Setting subscription options is not supported.
     3336    def test_on_affiliationsSetMissingJID(self):
     3337        """
     3338        Setting node affiliations must include a JID per affiliation.
    32233339        """
    32243340
     
    32273343                       from='user@example.org'>
    32283344          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
    3229             <affiliations/>
     3345            <affiliations node='test'>
     3346              <affiliation affiliation='publisher'/>
     3347            </affiliations>
    32303348          </pubsub>
    32313349        </iq>
     
    32333351
    32343352        def cb(result):
    3235             self.assertEquals('feature-not-implemented', result.condition)
    3236             self.assertEquals('unsupported', result.appCondition.name)
    3237             self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
    3238             self.assertEquals('modify-affiliations',
    3239                               result.appCondition['feature'])
     3353            self.assertEquals('bad-request', result.condition)
     3354
     3355        d = self.handleRequest(xml)
     3356        self.assertFailure(d, error.StanzaError)
     3357        d.addCallback(cb)
     3358        return d
     3359
     3360
     3361    def test_on_affiliationsSetMissingAffiliation(self):
     3362        """
     3363        Setting node affiliations must include an affiliation.
     3364        """
     3365
     3366        xml = """
     3367        <iq type='set' to='pubsub.example.org'
     3368                       from='user@example.org'>
     3369          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
     3370            <affiliations node='test'>
     3371              <affiliation jid='other@example.org'/>
     3372            </affiliations>
     3373          </pubsub>
     3374        </iq>
     3375        """
     3376
     3377        def cb(result):
     3378            self.assertEquals('bad-request', result.condition)
    32403379
    32413380        d = self.handleRequest(xml)
     
    39154054        d.addCallback(cb)
    39164055        return d
     4056
     4057
     4058    def test_affiliationsGet(self):
     4059        """
     4060        Non-overridden owner affiliations get yields unsupported error.
     4061        """
     4062
     4063        def cb(result):
     4064            self.assertEquals('feature-not-implemented', result.condition)
     4065            self.assertEquals('unsupported', result.appCondition.name)
     4066            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     4067            self.assertEquals('modify-affiliations',
     4068                              result.appCondition['feature'])
     4069
     4070        d = self.resource.affiliationsGet(pubsub.PubSubRequest())
     4071        self.assertFailure(d, error.StanzaError)
     4072        d.addCallback(cb)
     4073        return d
     4074
     4075
     4076    def test_affiliationsSet(self):
     4077        """
     4078        Non-overridden owner affiliations set yields unsupported error.
     4079        """
     4080
     4081        def cb(result):
     4082            self.assertEquals('feature-not-implemented', result.condition)
     4083            self.assertEquals('unsupported', result.appCondition.name)
     4084            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     4085            self.assertEquals('modify-affiliations',
     4086                              result.appCondition['feature'])
     4087
     4088        d = self.resource.affiliationsSet(pubsub.PubSubRequest())
     4089        self.assertFailure(d, error.StanzaError)
     4090        d.addCallback(cb)
     4091        return d
Note: See TracChangeset for help on using the changeset viewer.