source: ralphm-patches/pubsub_manage_affiliations.patch @ 46:5ec77d2dcdb4

Last change on this file since 46:5ec77d2dcdb4 was 46:5ec77d2dcdb4, checked in by Ralph Meijer <ralphm@…>, 12 years ago

Raise exception on duplicate entities, always use bare JIDs.

File size: 11.3 KB
  • wokkel/iwokkel.py

    # HG changeset patch
    # Parent f69b08281becebb5483f3f2dfb0451ad3086a463
    Add support for managing affiliations of Publish-Subscribe nodes.
    
    diff -r f69b08281bec wokkel/iwokkel.py
    a b  
    767767                 deleted.
    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

    diff -r f69b08281bec wokkel/pubsub.py
    a b  
    220220    @ivar subscriptions: Subscriptions to be modified, as a set of
    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
    225228    verb = None
     
    234237    subscriber = None
    235238    subscriptionIdentifier = None
    236239    subscriptions = None
     240    affiliations = None
    237241
    238242    # Map request iq type and subelement name to request verb
    239243    _requestVerbMap = {
     
    279283        'purge': ['node'],
    280284        'delete': ['node'],
    281285        'affiliationsGet': ['nodeOrEmpty'],
    282         'affiliationsSet': [],
     286        'affiliationsSet': ['nodeOrEmpty', 'affiliations'],
    283287        'subscriptionsGet': ['nodeOrEmpty'],
    284288        'subscriptionsSet': [],
    285289    }
     
    526530            self._render_options(optionsElement)
    527531
    528532
     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
     552
     553
    529554    def parseElement(self, element):
    530555        """
    531556        Parse the publish-subscribe verb and parameters out of a request.
     
    13031328
    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
    13081349    def notifyPublish(self, service, nodeIdentifier, notifications):
  • wokkel/test/test_pubsub.py

    diff -r f69b08281bec wokkel/test/test_pubsub.py
    a b  
    31923192
    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
    31983236        xml = """
     
    32043242        </iq>
    32053243        """
    32063244
    3207         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'])
    3213 
     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)
    32143254        d = self.handleRequest(xml)
    3215         self.assertFailure(d, error.StanzaError)
    32163255        d.addCallback(cb)
    32173256        return d
    32183257
    32193258
    32203259    def test_on_affiliationsSet(self):
    32213260        """
    3222         Setting subscription options is not supported.
     3261        Setting node affiliations has the affiliations to be modified.
    32233262        """
    32243263
    32253264        xml = """
    32263265        <iq type='set' to='pubsub.example.org'
    32273266                       from='user@example.org'>
    32283267          <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
    3229             <affiliations/>
     3268            <affiliations node='test'>
     3269              <affiliation jid='other@example.org' affiliation='publisher'/>
     3270            </affiliations>
    32303271          </pubsub>
    32313272        </iq>
    32323273        """
    32333274
     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
    32343327        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'])
     3328            self.assertEquals('bad-request', result.condition)
    32403329
    32413330        d = self.handleRequest(xml)
    32423331        self.assertFailure(d, error.StanzaError)
     
    39144003        self.assertFailure(d, error.StanzaError)
    39154004        d.addCallback(cb)
    39164005        return d
     4006
     4007
     4008    def test_affiliationsGet(self):
     4009        """
     4010        Non-overridden owner affiliations get yields unsupported error.
     4011        """
     4012
     4013        def cb(result):
     4014            self.assertEquals('feature-not-implemented', result.condition)
     4015            self.assertEquals('unsupported', result.appCondition.name)
     4016            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     4017            self.assertEquals('modify-affiliations',
     4018                              result.appCondition['feature'])
     4019
     4020        d = self.resource.affiliationsGet(pubsub.PubSubRequest())
     4021        self.assertFailure(d, error.StanzaError)
     4022        d.addCallback(cb)
     4023        return d
     4024
     4025
     4026    def test_affiliationsSet(self):
     4027        """
     4028        Non-overridden owner affiliations set yields unsupported error.
     4029        """
     4030
     4031        def cb(result):
     4032            self.assertEquals('feature-not-implemented', result.condition)
     4033            self.assertEquals('unsupported', result.appCondition.name)
     4034            self.assertEquals(NS_PUBSUB_ERRORS, result.appCondition.uri)
     4035            self.assertEquals('modify-affiliations',
     4036                              result.appCondition['feature'])
     4037
     4038        d = self.resource.affiliationsGet(pubsub.PubSubRequest())
     4039        self.assertFailure(d, error.StanzaError)
     4040        d.addCallback(cb)
     4041        return d
Note: See TracBrowser for help on using the repository browser.