From 4aa123d55708ea27211a9c2253d4123250d8c7f0 Mon Sep 17 00:00:00 2001 From: JC Brand Date: Tue, 21 Feb 2017 22:13:49 +0100 Subject: [PATCH] Add timestamps to resources So that when a higher priority resource goes offline, we can fall back to the right chat status if at the next priority level there are multiple resources. https://github.com/jcbrand/converse.js/commit/789654d54e7a8c80b35934f526e05ee7802c790f#comments --- spec/presence.js | 265 ++++++++++++++++++++++++++----------------- src/converse-core.js | 14 ++- 2 files changed, 173 insertions(+), 106 deletions(-) diff --git a/spec/presence.js b/spec/presence.js index d9267ec6d..565d34eba 100644 --- a/spec/presence.js +++ b/spec/presence.js @@ -21,115 +21,174 @@ 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 = $( - ''+ - ' 1'+ - ' '+ - ' '+ - ' ce51d94f7f22b87a21274abb93710b9eb7cc1c65'+ - ' '+ - ' '+ - ''); - _converse.connection._dataRecv(test_utils.createRequest(stanza[0])); - 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'); + var stanza; + runs(function () { + stanza = $( + ''+ + ' 1'+ + ' '+ + ' '+ + ' ce51d94f7f22b87a21274abb93710b9eb7cc1c65'+ + ' '+ + ' '+ + ''); + _converse.connection._dataRecv(test_utils.createRequest(stanza[0])); + expect(contact.get('chat_status')).toBe('online'); + expect(_.keys(contact.get('resources')).length).toBe(1); + expect(contact.get('resources')['priority-1-resource']['priority']).toBe(1); + expect(contact.get('resources')['priority-1-resource']['status']).toBe('online'); - stanza = $( - ''+ - ' '+ - ' 0'+ - ' xa'+ - ' '+ - ' '+ - ''); - _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 = $( + ''+ + ' '+ + ' 0'+ + ' xa'+ + ' '+ + ' '+ + ''); + _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')['priority-0-resource']['priority']).toBe(0); + expect(contact.get('resources')['priority-0-resource']['status']).toBe('xa'); + expect(contact.get('resources')['priority-1-resource']['priority']).toBe(1); + expect(contact.get('resources')['priority-1-resource']['status']).toBe('online'); - stanza = $( - ''+ - ' 2'+ - ' dnd'+ - ''); - _converse.connection._dataRecv(test_utils.createRequest(stanza[0])); - expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('dnd'); - expect(_.keys(contact.get('resources')).length).toBe(3); - 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'); - expect(contact.get('resources')['other-resource']['priority']).toBe(2); - expect(contact.get('resources')['other-resource']['status']).toBe('dnd'); + stanza = $( + ''+ + ' 2'+ + ' dnd'+ + ''); + _converse.connection._dataRecv(test_utils.createRequest(stanza[0])); + expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('dnd'); + expect(_.keys(contact.get('resources')).length).toBe(3); + expect(contact.get('resources')['priority-0-resource']['priority']).toBe(0); + expect(contact.get('resources')['priority-0-resource']['status']).toBe('xa'); + expect(contact.get('resources')['priority-1-resource']['priority']).toBe(1); + expect(contact.get('resources')['priority-1-resource']['status']).toBe('online'); + expect(contact.get('resources')['priority-2-resource']['priority']).toBe(2); + expect(contact.get('resources')['priority-2-resource']['status']).toBe('dnd'); - stanza = $( - ''+ - ' 3'+ - ' away'+ - ''); - _converse.connection._dataRecv(test_utils.createRequest(stanza[0])); - expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('away'); - expect(_.keys(contact.get('resources')).length).toBe(3); - 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'); - expect(contact.get('resources')['other-resource']['priority']).toBe(3); - expect(contact.get('resources')['other-resource']['status']).toBe('away'); + stanza = $( + ''+ + ' 3'+ + ' away'+ + ''); + _converse.connection._dataRecv(test_utils.createRequest(stanza[0])); + expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('away'); + expect(_.keys(contact.get('resources')).length).toBe(4); + expect(contact.get('resources')['priority-0-resource']['priority']).toBe(0); + expect(contact.get('resources')['priority-0-resource']['status']).toBe('xa'); + expect(contact.get('resources')['priority-1-resource']['priority']).toBe(1); + expect(contact.get('resources')['priority-1-resource']['status']).toBe('online'); + expect(contact.get('resources')['priority-2-resource']['priority']).toBe(2); + expect(contact.get('resources')['priority-2-resource']['status']).toBe('dnd'); + expect(contact.get('resources')['priority-3-resource']['priority']).toBe(3); + expect(contact.get('resources')['priority-3-resource']['status']).toBe('away'); + }); + waits(1000); // XXX: Bit of a hack. With jasmine 2 we can mock the date instead. + runs(function () { + stanza = $( + ''+ + ' 1'+ + ' dnd'+ + ''); + _converse.connection._dataRecv(test_utils.createRequest(stanza[0])); + expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('away'); + expect(_.keys(contact.get('resources')).length).toBe(5); + expect(contact.get('resources')['newer-priority-1-resource']['priority']).toBe(1); + expect(contact.get('resources')['newer-priority-1-resource']['status']).toBe('dnd'); + expect(contact.get('resources')['priority-0-resource']['priority']).toBe(0); + expect(contact.get('resources')['priority-0-resource']['status']).toBe('xa'); + expect(contact.get('resources')['priority-1-resource']['priority']).toBe(1); + expect(contact.get('resources')['priority-1-resource']['status']).toBe('online'); + expect(contact.get('resources')['priority-2-resource']['priority']).toBe(2); + expect(contact.get('resources')['priority-2-resource']['status']).toBe('dnd'); + expect(contact.get('resources')['priority-3-resource']['priority']).toBe(3); + expect(contact.get('resources')['priority-3-resource']['status']).toBe('away'); - stanza = $( - ''+ - ''); - _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')['androidkhydmcKW']['priority']).toBe(0); - expect(contact.get('resources')['androidkhydmcKW']['status']).toBe('xa'); - 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 = $( + ''+ + ''); + _converse.connection._dataRecv(test_utils.createRequest(stanza[0])); + expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('dnd'); + expect(_.keys(contact.get('resources')).length).toBe(4); + expect(contact.get('resources')['priority-0-resource']['priority']).toBe(0); + expect(contact.get('resources')['priority-0-resource']['status']).toBe('xa'); + expect(contact.get('resources')['priority-1-resource']['priority']).toBe(1); + expect(contact.get('resources')['priority-1-resource']['status']).toBe('online'); + expect(contact.get('resources')['priority-2-resource']['priority']).toBe(2); + expect(contact.get('resources')['priority-2-resource']['status']).toBe('dnd'); + expect(contact.get('resources')['newer-priority-1-resource']['priority']).toBe(1); + expect(contact.get('resources')['newer-priority-1-resource']['status']).toBe('dnd'); - stanza = $( - ''+ - ''); - _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 = $( + ''+ + ''); + _converse.connection._dataRecv(test_utils.createRequest(stanza[0])); + expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('dnd'); + expect(_.keys(contact.get('resources')).length).toBe(3); + expect(contact.get('resources')['priority-0-resource']['priority']).toBe(0); + expect(contact.get('resources')['priority-0-resource']['status']).toBe('xa'); + expect(contact.get('resources')['priority-1-resource']['priority']).toBe(1); + expect(contact.get('resources')['priority-1-resource']['status']).toBe('online'); + expect(contact.get('resources')['newer-priority-1-resource']['priority']).toBe(1); + expect(contact.get('resources')['newer-priority-1-resource']['status']).toBe('dnd'); - stanza = $( - ''+ - ''); - _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); + stanza = $( + ''+ + ''); + _converse.connection._dataRecv(test_utils.createRequest(stanza[0])); + expect(_converse.roster.get(contact_jid).get('chat_status')).toBe('dnd'); + expect(_.keys(contact.get('resources')).length).toBe(2); + expect(contact.get('resources')['priority-0-resource']['priority']).toBe(0); + expect(contact.get('resources')['priority-0-resource']['status']).toBe('xa'); + expect(contact.get('resources')['newer-priority-1-resource']['priority']).toBe(1); + expect(contact.get('resources')['newer-priority-1-resource']['status']).toBe('dnd'); + + stanza = $( + ''+ + ''); + _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')['priority-0-resource']['priority']).toBe(0); + expect(contact.get('resources')['priority-0-resource']['status']).toBe('xa'); + + stanza = $( + ''+ + ''); + _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); + }); })); }); })); diff --git a/src/converse-core.js b/src/converse-core.js index a9700a3bf..67a68cbdd 100755 --- a/src/converse-core.js +++ b/src/converse-core.js @@ -859,8 +859,9 @@ var resources = this.get('resources'); if (!_.isObject(resources)) { resources = {}; } resources[resource] = { - 'priority': _.isNaN(Number(priority)) ? 0 : Number(priority), - 'status': chat_status + 'priority': _.isNaN(parseInt(priority)) ? 0 : parseInt(priority), + 'status': chat_status, + 'timestamp': moment().format() }; this.set({'resources': resources}); return resources; @@ -884,10 +885,17 @@ getHighestPriorityStatus: function () { /* Return the chat status assigned to the resource with the * highest priority. + * + * If multiple resources have the same priority, take the + * newest one. */ var resources = this.get('resources'); if (_.isObject(resources) && _.size(resources)) { - var val = _.flow(_.values, _.partial(_.sortBy, _, 'priority'), _.reverse)(resources)[0]; + var val = _.flow( + _.values, + _.partial(_.sortBy, _, ['priority', 'timestamp']), + _.reverse + )(resources)[0]; if (!_.isUndefined(val)) { return val.status; }