Explorar el Código

Initial work on managing a room's member's list.

JC Brand hace 9 años
padre
commit
60f433d12e
Se han modificado 2 ficheros con 137 adiciones y 24 borrados
  1. 136 23
      src/converse-muc.js
  2. 1 1
      src/templates/occupant.html

+ 136 - 23
src/converse-muc.js

@@ -202,6 +202,8 @@
                     this.occupantsview.chatroomview = this;
                     this.occupantsview.chatroomview = this;
                     this.render().$el.hide();
                     this.render().$el.hide();
                     this.occupantsview.model.fetch({add:true});
                     this.occupantsview.model.fetch({add:true});
+                    _.each(['member', 'owner', 'admin'], this.fetchMembersList.bind(this));
+
                     this.join(null, {'maxstanzas': converse.muc_history_max_stanzas});
                     this.join(null, {'maxstanzas': converse.muc_history_max_stanzas});
                     this.fetchMessages().insertIntoDOM();
                     this.fetchMessages().insertIntoDOM();
                     // XXX: adding the event below to the events map above doesn't work.
                     // XXX: adding the event below to the events map above doesn't work.
@@ -254,6 +256,54 @@
                     converse.ChatBoxView.prototype.close.apply(this, arguments);
                     converse.ChatBoxView.prototype.close.apply(this, arguments);
                 },
                 },
 
 
+                updateMembersList: function () {
+                    /* Update the room's member-lists by sending a delta of
+                     * changed memberships (for all affiliations).
+                     */
+                    var iq = $iq({'to':this.model.get('jid'), 'type':'set', 'from':converse.connection.jid})
+                        .c("query", {'xmlns': Strophe.NS.MUC_ADMIN});
+                    this.occupantsview.model.each(function (occupant) {
+                        var affiliation = occupant.get('affiliation');
+                        iq.c('item', {
+                                'affiliation': affiliation !== 'none' ? affiliation : 'member',
+                                'jid': Strophe.getBareJidFromJid(occupant.get('jid'))
+                            });
+                    });
+                    return converse.connection.sendIQ(
+                        iq.tree(),
+                        this.onMembersListChanged.bind(this),
+                        this.onMembersListChangedError.bind(this)
+                    );
+                },
+
+                fetchMembersList: function (affiliation) {
+                    /* Fetch the member-list for a particular affiliation.
+                     *
+                     * Unfortunately it doesn't seem to work when trying to
+                     * fetch a list for all affiliations, so we need to fetch
+                     * them one by one.
+                     */
+                    var iq = $iq({
+                        'to': this.model.get('jid'),
+                        'type': "get",
+                        'from': converse.connection.jid
+                    }).c("query", {'xmlns': Strophe.NS.MUC_ADMIN})
+                        .c("item", {'affiliation': affiliation});
+                    return converse.connection.sendIQ(
+                        iq.tree(),
+                        this.occupantsview.updateOccupantsOnMembersList.bind(this.occupantsview),
+                        _.bind(this.onMembersListError, this, affiliation)
+                    );
+                },
+
+                onMembersListError: function (affiliation, iq) {
+                    if (iq.getElementsByTagName('forbidden').length) {
+                        converse.log("You are forbidden from retrieving the "+affiliation+"-list for "+this.model.get('jid'));
+                    } else {
+                        converse.log("Could not retrieve "+affiliation+"-list for "+this.model.get('jid'), "error");
+                    }
+                },
+
                 toggleOccupants: function (ev, preserve_state) {
                 toggleOccupants: function (ev, preserve_state) {
                     if (ev) {
                     if (ev) {
                         ev.preventDefault();
                         ev.preventDefault();
@@ -617,7 +667,15 @@
                 },
                 },
 
 
                 onConfigSaved: function (stanza) {
                 onConfigSaved: function (stanza) {
-                    // TODO: provide feedback
+                    // this.updateMembersList();
+                },
+
+                onMembersListChanged: function (stanza) {
+                    converse.log("The membership-list for "+this.model.get('jid')+" has been succesfully updated");
+                },
+
+                onMembersListChangedError: function (stanza) {
+                    this.showStatusNotification(__("An error occurred while trying to update the members list."));
                 },
                 },
 
 
                 onErrorConfigSaved: function (stanza) {
                 onErrorConfigSaved: function (stanza) {
@@ -926,25 +984,36 @@
                 }
                 }
             });
             });
 
 
-            converse.ChatRoomOccupant = Backbone.Model;
+            converse.ChatRoomOccupant = Backbone.Model.extend({
+                initialize: function () {
+                    this.set({'id': converse.connection.getUniqueId()});
+                }
+            });
             converse.ChatRoomOccupantView = Backbone.View.extend({
             converse.ChatRoomOccupantView = Backbone.View.extend({
                 tagName: 'li',
                 tagName: 'li',
                 initialize: function () {
                 initialize: function () {
-                    this.model.on('add', this.render, this);
                     this.model.on('change', this.render, this);
                     this.model.on('change', this.render, this);
                     this.model.on('destroy', this.destroy, this);
                     this.model.on('destroy', this.destroy, this);
                 },
                 },
                 render: function () {
                 render: function () {
-                    var $new = converse.templates.occupant(
-                        _.extend(
-                            this.model.toJSON(), {
-                                'desc_moderator': __('This user is a moderator'),
-                                'desc_occupant': __('This user can send messages in this room'),
-                                'desc_visitor': __('This user can NOT send messages in this room')
-                        })
+                    var new_el = converse.templates.occupant(
+                        _.extend({
+                            'nick': this.model.get('jid') || '',
+                            'role': null,
+                            'desc_moderator': __('This user is a moderator'),
+                            'desc_occupant': __('This user can send messages in this room'),
+                            'desc_visitor': __('This user can NOT send messages in this room')
+                            }, this.model.toJSON())
                     );
                     );
-                    this.$el.replaceWith($new);
-                    this.setElement($new, true);
+                    var $parents = this.$el.parents();
+                    if ($parents.length) {
+                        this.$el.replaceWith(new_el);
+                        this.setElement($parents.first().children('#'+this.model.get('id')), true);
+                        this.delegateEvents();
+                    } else {
+                        this.$el.replaceWith(new_el);
+                        this.setElement(new_el, true);
+                    }
                     return this;
                     return this;
                 },
                 },
 
 
@@ -980,9 +1049,9 @@
                 },
                 },
 
 
                 onOccupantAdded: function (item) {
                 onOccupantAdded: function (item) {
-                    var view = this.get(item.get('id'));
+                    var view = this.get(item.get('jid'));
                     if (!view) {
                     if (!view) {
-                        view = this.add(item.get('id'), new converse.ChatRoomOccupantView({model: item}));
+                        view = this.add(item.get('jid'), new converse.ChatRoomOccupantView({model: item}));
                     } else {
                     } else {
                         delete view.model; // Remove ref to old model to help garbage collection
                         delete view.model; // Remove ref to old model to help garbage collection
                         view.model = item;
                         view.model = item;
@@ -994,7 +1063,6 @@
                 parsePresence: function (pres) {
                 parsePresence: function (pres) {
                     var id = Strophe.getResourceFromJid(pres.getAttribute("from"));
                     var id = Strophe.getResourceFromJid(pres.getAttribute("from"));
                     var data = {
                     var data = {
-                        id: id,
                         nick: id,
                         nick: id,
                         type: pres.getAttribute("type"),
                         type: pres.getAttribute("type"),
                         states: []
                         states: []
@@ -1030,25 +1098,70 @@
                 },
                 },
 
 
                 updateOccupantsOnPresence: function (pres) {
                 updateOccupantsOnPresence: function (pres) {
-                    var occupant;
+                    var occupant, attributes;
                     var data = this.parsePresence(pres);
                     var data = this.parsePresence(pres);
+                    if (data.type === 'error') {
+                        return true;
+                    }
+                    // If we have a JID, we use that to look up the user,
+                    // otherwise we use the nick. We don't always have both,
+                    // but should have at least one or the other.
+                    var jid = Strophe.getBareJidFromJid(data.jid);
+                    if (jid !== null) {
+                        occupant = this.model.where({'jid': jid}).pop();
+                    } else {
+                        occupant = this.model.where({'nick': data.nick}).pop();
+                    }
+
                     switch (data.type) {
                     switch (data.type) {
-                        case 'error':
-                            return true;
                         case 'unavailable':
                         case 'unavailable':
-                            occupant = this.model.get(data.id);
-                            if (occupant) { occupant.destroy(); }
+                            if (occupant) {
+                                occupant[0].destroy();
+                            }
                             break;
                             break;
                         default:
                         default:
-                            occupant = this.model.get(data.id);
+                            attributes = _.extend(data, {
+                                'jid': jid ? jid : undefined,
+                                'resource': data.jid ? Strophe.getResourceFromJid(data.jid) : undefined,
+                                'online': true
+                            });
                             if (occupant) {
                             if (occupant) {
-                                occupant.save(data);
+                                occupant.save(attributes);
                             } else {
                             } else {
-                                this.model.create(data);
+                                this.model.create(attributes);
                             }
                             }
                     }
                     }
                 },
                 },
 
 
+                updateOccupantsOnMembersList: function (iq) {
+                    /* <iq from='coven@chat.shakespeare.lit'
+                            id='member3'
+                            to='crone1@shakespeare.lit/desktop'
+                            type='result'>
+                        <query xmlns='http://jabber.org/protocol/muc#admin'>
+                            <item affiliation='member'
+                                jid='hag66@shakespeare.lit'
+                                nick='thirdwitch'
+                                role='participant'/>
+                        </query>
+                        </iq>
+                    */
+                    _.each($(iq).find('query item'), function (item) {
+                        var jid = item.getAttribute('jid');
+                        var occupant = this.model.where({'jid': jid}).pop();
+                        var data = {
+                            'jid': item.getAttribute('jid'),
+                            'affiliation': item.getAttribute('affiliation')
+                        };
+                        if (occupant) {
+                            occupant.save(data);
+                        } else {
+                            this.model.create(data);
+                        }
+                    }.bind(this));
+                    return;
+                },
+
                 initInviteWidget: function () {
                 initInviteWidget: function () {
                     var $el = this.$('input.invited-contact');
                     var $el = this.$('input.invited-contact');
                     $el.typeahead({
                     $el.typeahead({

+ 1 - 1
src/templates/occupant.html

@@ -1,4 +1,4 @@
-<li class="{{role}}"
+<li class="{{role}}" id="{{id}}"
     {[ if (role === "moderator") { ]}
     {[ if (role === "moderator") { ]}
        title="{{desc_moderator}}"
        title="{{desc_moderator}}"
     {[ } ]}
     {[ } ]}