Commit 0464060f authored by JC Brand's avatar JC Brand

Initial attempt at adding support for multi-session nicks

updates #1197
parent 682bace8
......@@ -68708,7 +68708,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
verifyRoles(roles) {
const me = this.model.occupants.findWhere({
'jid': _converse.bare_jid
'bare_jid': _converse.bare_jid
});
if (!_.includes(roles, me.get('role'))) {
......@@ -68721,7 +68721,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
verifyAffiliations(affiliations) {
const me = this.model.occupants.findWhere({
'jid': _converse.bare_jid
'bare_jid': _converse.bare_jid
});
if (!_.includes(affiliations, me.get('affiliation'))) {
......@@ -68744,7 +68744,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
if (!this.model.occupants.findWhere({
'nick': args[0]
}) && !this.model.occupants.findWhere({
'jid': args[0]
'bare_jid': args[0]
})) {
this.showErrorMessage(__('Error: couldn\'t find a groupchat participant "%1$s"', args[0]));
return false;
......@@ -70358,10 +70358,8 @@ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
return null;
}
const occupant = this.occupants.findOccupant({
const occupant = this.occupants.findWhere({
'nick': longest_match
}) || this.occupants.findOccupant({
'jid': longest_match
});
if (!occupant) {
......@@ -70375,8 +70373,8 @@ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
'type': 'mention'
};
if (occupant.get('jid')) {
obj.uri = `xmpp:${occupant.get('jid')}`;
if (occupant.get('bare_jid')) {
obj.uri = `xmpp:${occupant.get('bare_jid')}`;
}
return obj;
......@@ -70980,30 +70978,41 @@ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
return true;
}
const occupant = this.occupants.findOccupant(data);
const occupant = this.occupants.findWhere({
'nick': data.nick
});
if (data.type === 'unavailable' && occupant) {
// We only destroy the occupant if this is not a nickname change operation.
// and if they're not on the member lists.
if (!_.includes(data.states, converse.MUC_NICK_CHANGED_CODE) && !occupant.isMember()) {
// We only destroy the occupant if this is not a nickname change operation.
// and if they're not on the member lists.
// Before destroying we set the new data, so
// that we can show the disconnection message.
occupant.set(data);
// TODO: see whether we need to check for multiple jids
const attributes = _.extend(data, {
'bare_jid': data.jid ? Strophe.getBareJidFromJid(data.jid) : undefined,
'jids': data.jid ? [data.jid] : []
});
occupant.set(attributes);
occupant.destroy();
return;
}
}
const jid = Strophe.getBareJidFromJid(data.jid);
const attributes = _.extend(data, {
'jid': jid ? jid : undefined,
'resource': data.jid ? Strophe.getResourceFromJid(data.jid) : undefined
});
if (occupant) {
const attributes = _.extend(data, {
'bare_jid': data.jid ? Strophe.getBareJidFromJid(data.jid) : undefined,
'jids': data.jid ? _.concat(occupant.get('jids'), data.jid) : []
});
occupant.save(attributes);
} else {
const attributes = _.extend(data, {
'bare_jid': data.jid ? Strophe.getBareJidFromJid(data.jid) : undefined,
'jids': data.jid ? [data.jid] : []
});
this.occupants.create(attributes);
}
},
......@@ -71263,7 +71272,8 @@ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
});
_converse.ChatRoomOccupant = Backbone.Model.extend({
defaults: {
'show': 'offline'
'show': 'offline',
'jids': []
},
initialize(attributes) {
......@@ -71328,7 +71338,7 @@ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
});
_.each(removed_members, occupant => {
if (occupant.get('jid') === _converse.bare_jid) {
if (occupant.get('bare_jid') === _converse.bare_jid) {
return;
}
......@@ -71338,17 +71348,9 @@ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
});
_.each(new_members, attrs => {
let occupant;
if (attrs.jid) {
occupant = this.findOccupant({
'jid': attrs.jid
});
} else {
occupant = this.findOccupant({
'nick': attrs.nick
});
}
const occupant = this.findWhere({
'nick': attrs.nick
});
if (occupant) {
occupant.save(attrs);
......@@ -71357,27 +71359,6 @@ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
}
});
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
},
findOccupant(data) {
/* Try to find an existing occupant based on the passed in
* data object.
*
* If we have a JID, we use that as lookup variable,
* otherwise we use the nick. We don't always have both,
* but should have at least one or the other.
*/
const jid = Strophe.getBareJidFromJid(data.jid);
if (jid !== null) {
return this.where({
'jid': jid
}).pop();
} else {
return this.where({
'nick': data.nick
}).pop();
}
}
});
......@@ -12,7 +12,8 @@
Backbone = converse.env.Backbone,
u = converse.env.utils;
return describe("Chatrooms", function () {
describe("Chatrooms", function () {
describe("The \"rooms\" API", function () {
it("has a method 'close' which closes rooms by JID or all rooms when called with no arguments",
......@@ -1150,6 +1151,41 @@
}).catch(_.partial(console.error, _));
}));
it("can handle multi-session nicknames",
mock.initConverseWithPromises(null, ['rosterGroupsFetched'], {}, function (done, _converse) {
test_utils.openAndEnterChatRoom(_converse, 'coven', 'chat.shakespeare.lit', 'oldhag').then(() => {
let presence = $pres({
'to':'dummy@localhost/pda',
'from':"coven@chat.shakespeare.lit/my1stNick"
}).c('x').attrs({xmlns:'http://jabber.org/protocol/muc#user'})
.c('item').attrs({
jid: 'someone@localhost/foo',
role: 'moderator',
});
_converse.connection._dataRecv(test_utils.createRequest(presence));
const view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
let occupants = view.el.querySelector('.occupant-list').querySelectorAll('li .occupant-nick');
expect(occupants.length).toBe(2);
expect(occupants.pop().textContent.trim()).toBe("my1stNick");
presence = $pres({
'to':'dummy@localhost/pda',
'from':"coven@chat.shakespeare.lit/my2ndNick"
}).c('x').attrs({xmlns:'http://jabber.org/protocol/muc#user'})
.c('item').attrs({
jid: 'someone@localhost/bar',
role: 'moderator',
});
_converse.connection._dataRecv(test_utils.createRequest(presence));
occupants = view.el.querySelector('.occupant-list').querySelectorAll('li .occupant-nick');
expect(occupants.length).toBe(3);
expect(occupants.pop().textContent.trim()).toBe("my2ndNick");
done();
});
}));
it("escapes occupant nicknames when rendering them, to avoid JS-injection attacks",
mock.initConverseWithPromises(null, ['rosterGroupsFetched'], {}, function (done, _converse) {
......@@ -1229,8 +1265,7 @@
.c('item').attrs({
jid: contact_jid,
role: 'visitor',
}).up()
.c('status').attrs({code:'110'}).nodeTree;
});
_converse.connection._dataRecv(test_utils.createRequest(presence));
occupants = view.el.querySelector('.occupant-list').querySelectorAll('li');
......
......@@ -833,7 +833,7 @@
},
verifyRoles (roles) {
const me = this.model.occupants.findWhere({'jid': _converse.bare_jid});
const me = this.model.occupants.findWhere({'bare_jid': _converse.bare_jid});
if (!_.includes(roles, me.get('role'))) {
this.showErrorMessage(__(`Forbidden: you do not have the necessary role in order to do that.`))
return false;
......@@ -842,7 +842,7 @@
},
verifyAffiliations (affiliations) {
const me = this.model.occupants.findWhere({'jid': _converse.bare_jid});
const me = this.model.occupants.findWhere({'bare_jid': _converse.bare_jid});
if (!_.includes(affiliations, me.get('affiliation'))) {
this.showErrorMessage(__(`Forbidden: you do not have the necessary affiliation in order to do that.`))
return false;
......@@ -860,7 +860,7 @@
);
return false;
}
if (!this.model.occupants.findWhere({'nick': args[0]}) && !this.model.occupants.findWhere({'jid': args[0]})) {
if (!this.model.occupants.findWhere({'nick': args[0]}) && !this.model.occupants.findWhere({'bare_jid': args[0]})) {
this.showErrorMessage(__('Error: couldn\'t find a groupchat participant "%1$s"', args[0]));
return false;
}
......
......@@ -341,8 +341,7 @@
// match.
return null;
}
const occupant = this.occupants.findOccupant({'nick': longest_match}) ||
this.occupants.findOccupant({'jid': longest_match});
const occupant = this.occupants.findWhere({'nick': longest_match});
if (!occupant) {
return null;
}
......@@ -352,8 +351,8 @@
'value': longest_match,
'type': 'mention'
};
if (occupant.get('jid')) {
obj.uri = `xmpp:${occupant.get('jid')}`
if (occupant.get('bare_jid')) {
obj.uri = `xmpp:${occupant.get('bare_jid')}`
}
return obj;
},
......@@ -873,26 +872,34 @@
if (data.type === 'error' || (!data.jid && !data.nick)) {
return true;
}
const occupant = this.occupants.findOccupant(data);
const occupant = this.occupants.findWhere({'nick': data.nick});
if (data.type === 'unavailable' && occupant) {
// We only destroy the occupant if this is not a nickname change operation.
// and if they're not on the member lists.
if (!_.includes(data.states, converse.MUC_NICK_CHANGED_CODE) && !occupant.isMember()) {
// We only destroy the occupant if this is not a nickname change operation.
// and if they're not on the member lists.
// Before destroying we set the new data, so
// that we can show the disconnection message.
occupant.set(data);
// TODO: see whether we need to check for multiple jids
const attributes = _.extend(data, {
'bare_jid': data.jid ? Strophe.getBareJidFromJid(data.jid) : undefined,
'jids': data.jid ? [data.jid] : []
});
occupant.set(attributes);
occupant.destroy();
return;
}
}
const jid = Strophe.getBareJidFromJid(data.jid);
const attributes = _.extend(data, {
'jid': jid ? jid : undefined,
'resource': data.jid ? Strophe.getResourceFromJid(data.jid) : undefined
});
if (occupant) {
const attributes = _.extend(data, {
'bare_jid': data.jid ? Strophe.getBareJidFromJid(data.jid) : undefined,
'jids': data.jid ? _.concat(occupant.get('jids'), data.jid) : []
});
occupant.save(attributes);
} else {
const attributes = _.extend(data, {
'bare_jid': data.jid ? Strophe.getBareJidFromJid(data.jid) : undefined,
'jids': data.jid ? [data.jid] : []
});
this.occupants.create(attributes);
}
},
......@@ -1113,7 +1120,8 @@
_converse.ChatRoomOccupant = Backbone.Model.extend({
defaults: {
'show': 'offline'
'show': 'offline',
'jids': []
},
initialize (attributes) {
......@@ -1175,19 +1183,14 @@
!f.includes(m.get('jid'), new_jids);
});
_.each(removed_members, (occupant) => {
if (occupant.get('jid') === _converse.bare_jid) { return; }
_.each(removed_members, occupant => {
if (occupant.get('bare_jid') === _converse.bare_jid) { return; }
if (occupant.get('show') === 'offline') {
occupant.destroy();
}
});
_.each(new_members, (attrs) => {
let occupant;
if (attrs.jid) {
occupant = this.findOccupant({'jid': attrs.jid});
} else {
occupant = this.findOccupant({'nick': attrs.nick});
}
_.each(new_members, attrs => {
const occupant = this.findWhere({'nick': attrs.nick});
if (occupant) {
occupant.save(attrs);
} else {
......@@ -1195,22 +1198,6 @@
}
});
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
},
findOccupant (data) {
/* Try to find an existing occupant based on the passed in
* data object.
*
* If we have a JID, we use that as lookup variable,
* otherwise we use the nick. We don't always have both,
* but should have at least one or the other.
*/
const jid = Strophe.getBareJidFromJid(data.jid);
if (jid !== null) {
return this.where({'jid': jid}).pop();
} else {
return this.where({'nick': data.nick}).pop();
}
}
});
......@@ -1218,7 +1205,7 @@
_converse.RoomsPanelModel = Backbone.Model.extend({
defaults: {
'muc_domain': '',
},
}
});
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment