Improve upon the previous implementation. If the resource with the highest priority goes offline or becomes unavailable, then the chat status of the contact must fall back to that of the resource with the next highest priority. In your example from #785, if the resource with priority 1 goes offline or becomes unavailable, then in your implementation the chat status would stay at online, although it must actually go to xa. The solution is to update the resources attribute on the contact to not just be an array or strings, but instead to be a map of resources to priorities and statuses and to use that data structure.
This commit is contained in:
parent
15d2640c43
commit
789654d54e
@ -16,7 +16,6 @@
|
||||
* Templates are no longer stored as attributes on the `_converse` object.
|
||||
If you need a particular template, use `require` to load it.
|
||||
|
||||
- Add Presence Priority Handling [w3host]
|
||||
- The chat room `description` is now shown in the heading, not the `subject`.
|
||||
[jcbrand]
|
||||
- Chat room features are shown in the sidebar. [jcbrand]
|
||||
@ -53,6 +52,8 @@
|
||||
- #366 Show the chat room occupant's JID in the tooltip (if you're allowed to see it). [jcbrand]
|
||||
- #694 The `notification_option` wasn't being used consistently. [jcbrand]
|
||||
- #770 Allow setting contact attrs on chats.open [Ape]
|
||||
- #785 Add presence priority handling [w3host, jcbrand]
|
||||
|
||||
|
||||
## 2.0.6 (2017-02-13)
|
||||
- Escape user-generated input to prevent JS-injection attacks. (Thanks to SamWhited) [jcbrand]
|
||||
|
@ -1,3 +1,4 @@
|
||||
/*jshint sub:true*/
|
||||
(function (root, factory) {
|
||||
define([
|
||||
"jquery",
|
||||
@ -17,6 +18,7 @@
|
||||
test_utils.openControlBox();
|
||||
test_utils.createContacts(_converse, 'current'); // Create some contacts so that we can test positioning
|
||||
var contact_jid = mock.cur_names[8].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
var contact = _converse.roster.get(contact_jid);
|
||||
var stanza = $(
|
||||
'<presence xmlns="jabber:client"'+
|
||||
' to="dummy@localhost/converse.js-21770972"'+
|
||||
@ -30,7 +32,10 @@
|
||||
' <delay xmlns="urn:xmpp:delay" stamp="2017-02-15T20:26:05Z" from="jabbim.hu"/>'+
|
||||
'</presence>');
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
|
||||
expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('online');
|
||||
expect(contact.get('chat_status')).toBe('online');
|
||||
expect(_.keys(contact.get('resources')).length).toBe(1);
|
||||
expect(contact.get('resources')['c71f218b-0797-4732-8a88-b42cb1d8557a']['priority']).toBe(1);
|
||||
expect(contact.get('resources')['c71f218b-0797-4732-8a88-b42cb1d8557a']['status']).toBe('online');
|
||||
|
||||
stanza = $(
|
||||
'<presence xmlns="jabber:client"'+
|
||||
@ -46,6 +51,33 @@
|
||||
'</presence>');
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
|
||||
expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('online');
|
||||
expect(_.keys(contact.get('resources')).length).toBe(2);
|
||||
expect(contact.get('resources')['c71f218b-0797-4732-8a88-b42cb1d8557a']['priority']).toBe(1);
|
||||
expect(contact.get('resources')['c71f218b-0797-4732-8a88-b42cb1d8557a']['status']).toBe('online');
|
||||
expect(contact.get('resources')['androidkhydmcKW']['priority']).toBe(0);
|
||||
expect(contact.get('resources')['androidkhydmcKW']['status']).toBe('xa');
|
||||
|
||||
stanza = $(
|
||||
'<presence xmlns="jabber:client"'+
|
||||
' to="dummy@localhost/converse.js-21770972"'+
|
||||
' type="unavailable"'+
|
||||
' from="'+contact_jid+'/c71f218b-0797-4732-8a88-b42cb1d8557a">'+
|
||||
'</presence>');
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
|
||||
expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('xa');
|
||||
expect(_.keys(contact.get('resources')).length).toBe(1);
|
||||
expect(contact.get('resources')['androidkhydmcKW']['priority']).toBe(0);
|
||||
expect(contact.get('resources')['androidkhydmcKW']['status']).toBe('xa');
|
||||
|
||||
stanza = $(
|
||||
'<presence xmlns="jabber:client"'+
|
||||
' to="dummy@localhost/converse.js-21770972"'+
|
||||
' type="unavailable"'+
|
||||
' from="'+contact_jid+'/androidkhydmcKW">'+
|
||||
'</presence>');
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza[0]));
|
||||
expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('offline');
|
||||
expect(_.keys(contact.get('resources')).length).toBe(0);
|
||||
}));
|
||||
});
|
||||
}));
|
||||
|
@ -775,7 +775,7 @@
|
||||
'fullname': bare_jid,
|
||||
'chat_status': 'offline',
|
||||
'user_id': Strophe.getNodeFromJid(jid),
|
||||
'resources': resource ? [resource] : [],
|
||||
'resources': resource ? {'resource':0} : {},
|
||||
'groups': [],
|
||||
'image_type': DEFAULT_IMAGE_TYPE,
|
||||
'image': DEFAULT_IMAGE,
|
||||
@ -855,23 +855,44 @@
|
||||
return this;
|
||||
},
|
||||
|
||||
addResource: function (resource, priority, chat_status) {
|
||||
var resources = this.get('resources');
|
||||
if (!_.isObject(resources)) { resources = {}; }
|
||||
resources[resource] = {
|
||||
'priority': _.isNaN(Number(priority)) ? 0 : Number(priority),
|
||||
'status': chat_status
|
||||
};
|
||||
this.set({'resources': resources});
|
||||
return resources;
|
||||
},
|
||||
|
||||
removeResource: function (resource) {
|
||||
var resources = this.get('resources'), idx;
|
||||
if (resource) {
|
||||
idx = _.indexOf(resources, resource);
|
||||
if (idx !== -1) {
|
||||
resources.splice(idx, 1);
|
||||
this.save({'resources': resources});
|
||||
/* Remove the passed in resource from the contact's resources
|
||||
* map.
|
||||
* Return the amount of resources left over.
|
||||
*/
|
||||
var resources = this.get('resources');
|
||||
if (!_.isObject(resources)) {
|
||||
resources = {};
|
||||
} else {
|
||||
delete resources[resource];
|
||||
}
|
||||
this.save({'resources': resources});
|
||||
return _.size(resources);
|
||||
},
|
||||
|
||||
getHighestPriorityStatus: function () {
|
||||
/* Return the chat status assigned to the resource with the
|
||||
* highest priority.
|
||||
*/
|
||||
var resources = this.get('resources');
|
||||
if (_.isObject(resources) && _.size(resources)) {
|
||||
var val = _(resources).values().sortBy('priority').get(0);
|
||||
if (!_.isUndefined(val)) {
|
||||
return val.status;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// if there is no resource (resource is null), it probably
|
||||
// means that the user is now completely offline. To make sure
|
||||
// that there isn't any "ghost" resources left, we empty the array
|
||||
this.save({'resources': []});
|
||||
return 0;
|
||||
}
|
||||
return resources.length;
|
||||
return 'offline';
|
||||
},
|
||||
|
||||
removeFromRoster: function (callback) {
|
||||
@ -1023,45 +1044,6 @@
|
||||
return deferred.promise();
|
||||
},
|
||||
|
||||
addResource: function (bare_jid, resource) {
|
||||
var item = this.get(bare_jid),
|
||||
resources;
|
||||
if (item) {
|
||||
resources = item.get('resources');
|
||||
if (resources) {
|
||||
if (!_.includes(resources, resource)) {
|
||||
resources.push(resource);
|
||||
item.set({'resources': resources});
|
||||
}
|
||||
} else {
|
||||
item.set({'resources': [resource]});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setPriority: function (bare_jid, resource, priority) {
|
||||
var item = this.get(bare_jid),
|
||||
stored_priority;
|
||||
if (item) {
|
||||
stored_priority = item.get('priority');
|
||||
if (stored_priority) {
|
||||
if (priority >= stored_priority) {
|
||||
item.set({'priority': priority});
|
||||
item.set({'priority_updated_by': resource});
|
||||
return true;
|
||||
} else if (resource === item.get('priority_updated_by')) {
|
||||
item.set({'priority': priority});
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
item.set({'priority': priority});
|
||||
item.set({'priority_updated_by': resource});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
subscribeBack: function (bare_jid) {
|
||||
var contact = this.get(bare_jid);
|
||||
if (contact instanceof _converse.RosterContact) {
|
||||
@ -1267,17 +1249,14 @@
|
||||
} else if (presence_type === 'subscribe') {
|
||||
this.handleIncomingSubscription(presence);
|
||||
} else if (presence_type === 'unavailable' && contact) {
|
||||
// update priority to default level
|
||||
this.setPriority(bare_jid, resource, 0);
|
||||
// Only set the user to offline if there aren't any
|
||||
// other resources still available.
|
||||
if (contact.removeResource(resource) === 0) {
|
||||
contact.save({'chat_status': "offline"});
|
||||
}
|
||||
contact.removeResource(resource);
|
||||
contact.save({'chat_status': contact.getHighestPriorityStatus()});
|
||||
} else if (contact) { // presence_type is undefined
|
||||
this.addResource(bare_jid, resource);
|
||||
if (this.setPriority(bare_jid, resource, priority)) {
|
||||
contact.save({'chat_status': chat_status});
|
||||
var resources = contact.addResource(resource, priority, chat_status);
|
||||
if (priority >= _(resources).values().map('priority').max()) {
|
||||
// Only save if it's the resource with the highest
|
||||
// priority
|
||||
contact.save({'chat_status': chat_status});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user