[sugar] review: Guillaume's 'activity' branch of Gadget

Guillaume Desmottes guillaume.desmottes at collabora.co.uk
Wed Jun 11 06:04:53 EDT 2008


Le mardi 10 juin 2008 à 14:42 +0100, Dafydd Harries a écrit : 
> > diff --git a/gadget/component.py b/gadget/component.py
> > index b5fc702..dd85a03 100644
> > --- a/gadget/component.py
> > +++ b/gadget/component.py
> > @@ -92,8 +92,9 @@ class Room(object):
> >      def __init__(self, own_nick):
> >          self.own_nick = own_nick
> >          self.membership = None
> > -        self.members = {}
> > +        self.members = set()
> >          self.properties = {}
> > +        self.id = None
> >  
> 
> Would it be possible to just have a Room.activity property and use that to
> store members/id?
> 

I'll remove the Room object and move membership management to Activity
as we discussed yesterday.


> >  class GadgetService(component.Service):
> >      debug = False
> > @@ -333,7 +334,7 @@ class GadgetService(component.Service):
> >      def message(self, stanza):
> >          type = stanza.getAttribute('type', 'normal')
> >  
> > -        if type in ('chat', 'groupchat'):
> > +        if type in ('chat'):
> >              return
> 
> This doesn't do quite what you want. "()" doesn't create a tuple, "," does, so
> this is the same as "type in 'chat'", which will be true if type is a
> substring of "chat". Better to just say "==".
> 

Right. Forgot about that, good catch. Fixed.

> >  
> >          if type == 'normal':
> > @@ -343,12 +344,17 @@ class GadgetService(component.Service):
> >                      return
> >                  elif (elem.uri == ns.ACTIVITY_PROP and
> >                        elem.name == 'properties'):
> > -                    self.message_activity_properties(stanza, elem)
> > +                    self.message_pre_invite_activity_properties(stanza, elem)
> >                      return
> >                  elif elem.uri == ns.PUBSUB_EVENT and elem.name == 'event':
> >                      self.message_pubsub_notification(stanza, elem)
> >                      return
> >  
> > +        elif type == 'groupchat':
> > +            for elem in stanza.elements():
> > +                if elem.uri == ns.ACTIVITY_PROP and elem.name == 'properties':
> > +                    self.message_activity_properties(stanza, elem)
> 
> You should return here. Perhaps we should dispatch messages more like we
> dispatch IQs, i.e. using a dict.
> 

fixed. I added a FIXME suggestion a better dispatch system.

> > +
> >          # FIXME: handle close query stanza
> >          log.msg('got unhandled <message>')
> >  
> > @@ -357,7 +363,7 @@ class GadgetService(component.Service):
> >              if elem.uri == ns.MUC_USER and elem.name == 'invite':
> >                  self.message_muc_invite(stanza, elem)
> >  
> > -    def create_room(self, jid, properties):
> > +    def create_room(self, jid, properties, id):
> 
> Hmm, can we put the id before the properties? I think it's more aesthetically
> pleasing that way.
> 

done.

> >          if jid in self.mucs:
> >              # We already have a room by this name.
> >              return
> > @@ -366,9 +372,10 @@ class GadgetService(component.Service):
> >          # join it.
> >          room = Room('inspector')
> >          room.properties = properties
> > +        room.id = id
> >          self.mucs[jid] = room
> >  
> > -    def message_activity_properties(self, stanza, properties_elem):
> > +    def message_pre_invite_activity_properties(self, stanza, properties_elem):
> >          # XXX Restrictions on from address?
> >  
> >          try:
> > @@ -384,7 +391,7 @@ class GadgetService(component.Service):
> >          if not (properties and activity and room_jid):
> >              return
> >  
> > -        self.create_room(room_jid, properties)
> > +        self.create_room(room_jid, properties, activity)
> 
> Perhaps we should rename 'activity' to 'activity_id' for clarity.
> 

done.

> >      def message_muc_invite(self, stanza, invite):
> >          to = stanza.getAttribute('to')
> > @@ -502,17 +509,54 @@ class GadgetService(component.Service):
> >                  # Presence for our in-room self; we've finished joining the
> >                  # room.
> >                  room.membership = 'joined'
> > +
> > +                # activities are created and added to the model when the
> > +                # inspector actually joined the muc.
> 
> English nitpicks: Your tenses don't agree here. "are created" ... "joined".
> s/joined/join/. If you use a full stop, you should also capitalise the first
> letter.
> 

fixed.

> > +                # If we'll do it before, we won't be able to properly track
> > +                # activity's properties and members.
> 
> I don't understand this comment.
> 

Humm me neither actually :) Removed.

> > +                activity = self.model.activity_add(room.id, room_jid,
> > +                        room.properties)
> > +
> > +                # Activity and Room now share the same set() object
> > +                activity.members = room.members
> >                  return
> >  
> > +        item = xpath_query('/presence/x[@xmlns="%s"]/item' % ns.MUC_USER,
> > +                stanza)
> > +        if not item or item[0].getAttribute('jid') is None:
> > +            log.msg("full jid of %s missing. Can't update activity members"
> > +                    % jid.resource)
> 
> English nitpicks: you should capitalise "full" and have a full stop after
> the second sentence.
> 

fixed.

> > +            return
> > +
> > +        full_jid = JID(item[0]['jid']).userhost()
> 
> Hmm, "full_jid" seems like a bad name, since it implies a JID with a resource.
> Perhaps it should be "real_jid" or just "jid".
> 

renamed to real_jid

> > +
> > +        activities = self.model.activity_by_room(room_jid)
> > +
> >          if type is None:
> >              log.msg('room %s has member %s' % (room_jid, jid.resource))
> > -            room.members[jid.resource] = True
> > +            room.members.add(full_jid)
> > +
> >          elif type == 'unavailable':
> >              if room_jid in self.mucs:
> >                  room = self.mucs[room_jid]
> >  
> > -                if jid.resource in room.members:
> > -                    del room.members[jid.resource]
> > +                if full_jid in room.members:
> > +                    room.members.remove(full_jid)
> > +
> > +                    if len(room.members) == 0:
> > +                        self.leave_activity(room_jid, room.id)
> > +
> > +    def leave_activity(self, room_jid, activity_id):
> 
> If we have Room.activity you won't need to pass around the ID here.

> > +        log.msg('leave room %s' % room_jid)
> > +
> 
> Should be "leaving room".
> 

fixed.

> > +        presence = domish.Element((None, 'presence'))
> > +        presence['to'] = '%s/inspector' % room_jid
> 
> You should use the JID class to generate the JID, and use Room.own_nick for
> the resource.
> 

done.

> > +        presence['type'] = 'unavailable'
> > +        x = presence.addElement((ns.MUC_USER, 'x'))
> > +        self.send(presence)
> > +
> > +        self.model.activity_remove(activity_id)
> > +        del self.mucs[room_jid]
> >  
> >      def message_pubsub_notification(self, stanza, event):
> >          items = event.firstChildElement()
> > @@ -533,3 +577,33 @@ class GadgetService(component.Service):
> >                  self.model.buddy_add(jid, props)
> >  
> >              # FIXME: send notification messages to interested buddies
> > +
> > +    def message_activity_properties(self, stanza, properties_elem):
> > +        id = properties_elem.getAttribute('activity')
> > +        room_jid = properties_elem.getAttribute('room')
> > +        jid = JID(stanza['from'])
> > +
> > +        if room_jid != jid.userhost():
> > +            log.msg("Ignored activity properties message from %s trying to change properties for another room"
> > +                    % stanza['from'])
> 
> Can you wrap this to 79 characters? You can just split the string literal in
> two.
> 
done.

> > +            return
> > +
> > +        try:
> > +            properties = parse_properties(properties_elem)
> > +        except PropertyTypeError:
> > +            log.msg("Ignored activity properties message from %s containing an invalid property"
> > +                    % stanza['from'])
> 
> Same here.
> 
done.

> > +            return
> > +
> > +        if not self.model.has_activity(id):
> > +            log.msg("Ignored activity properties message from %s about an invalid activity: %s "
> > +                    % stanza['from'], id)
> 
> And here.
> 
done.

> > +            return
> > +
> > +        # is activity private?
> > +        if properties.get('private') in (('bool', '1'), ('bool', 'true')):
> 
> Perhaps we should do some kind of normalisation in parse_properties, and maybe
> ignore malformed values.
> 

We already check this:
        if type == 'bool' and value not in ['1', '0', 'true', 'false']:
            raise PropertyTypeError(type, elems.uri)

Do you think we should check that the 'private' properties is always of
type 'bool'?

> > +            log.msg('Activity %s is not private. Leave it' % id)
> 
> s/Leave/Leaving/.
> 
fixed.



> > @@ -214,7 +214,7 @@ class RoomMembershipTest(TestCase):
> >          self.done = defer.Deferred()
> >          self.server.addOnetimeObserver('//presence', self.presence)
> >          # Simulate invitation process.
> > -        self.service.create_room('chat at conf.foo.org', {})
> > +        self.service.create_room('chat at conf.foo.org', {}, 'activity1')
> >          self.service.invited('inspector at gadget.bar.org', 'chat at conf.foo.org')
> >          return self.done
> >  
> > @@ -222,11 +222,15 @@ class RoomMembershipTest(TestCase):
> >          presence = domish.Element((ns.CLIENT, 'presence'))
> >          presence['from'] = 'chat at conf.foo.org/amy'
> >          x = presence.addElement((ns.MUC_USER, 'x'))
> > +        item = x.addElement('item')
> > +        item['jid'] = 'amy at foo.org/resource'
> >          self.server.send(presence)
> >  
> >          presence = domish.Element((ns.CLIENT, 'presence'))
> >          presence['from'] = 'chat at conf.foo.org/bob'
> >          x = presence.addElement((ns.MUC_USER, 'x'))
> > +        item = x.addElement('item')
> > +        item['jid'] = 'bob at foo.org/resource'
> >          self.server.send(presence)
> 
> We should probably have a test that includes a MUC presence message without a
> jid.

Good idea. Added.

> Perhaps we should factor out the code for creating MUC presence messages here.

done. I created a send_muc_presence method in TestCase as lot of tests need it.


I fixed all the typo in tests.


Thanks for the review,


	G.



More information about the Sugar mailing list