Commit 462a43b8 authored by JC Brand's avatar JC Brand

Add new config option `muc_nickname_from_jid`

which if set to `true` will let converse.js automatically take the node part of
a user's JID as their nickname when entering a room.

If there is a nickname clash, then the nickname will be disambiguated by adding
integers to it.

For example, john will become john-1, then john-2 and so forth.
parent 9b130f92
# Changelog
## 1.0.6 (Unreleased)
- #674 Polish translation updated to the current master. [ser]
- New config option [muc_nickname_from_jid](https://conversejs.org/docs/html/configuration.html#muc_nickname_from_jid) [jcbrand]
## 1.0.5 (2016-07-28)
- In case of nickname conflict when joining a room, allow the user to choose a new one.
[jcbrand]
......
......@@ -639,6 +639,21 @@ different approach.
If you're using MAM for archiving chat room messages, you might want to set
this option to zero.
muc_nickname_from_jid
---------------------
* Default: ``false``
When set to ``true``, then users will not be prompted to provide nicknames for
chat rooms. Instead, the node part of a user's JID (i.e. JID = node@domain/resource)
will be used. If the user's nickname is already taken by another user in the
chat room, then an integer will be added to make it unique.
So, for example, if john@example.com joins a chatroom, his nickname will
automatically be "john". If now john@differentdomain.com tries to join the
room, his nickname will be "john-2", and if john@somethingelse.com joins, then
his nickname will be "john-3", and so forth.
notify_all_room_messages
------------------------
......
......@@ -630,7 +630,7 @@
.c('status').attrs({code:'307'}).nodeTree;
var view = this.chatboxviews.get('lounge@localhost');
view.onChatRoomPresence(presence, {nick: 'dummy', name: 'lounge@localhost'});
view.onChatRoomPresence(presence);
expect(view.$('.chat-area').is(':visible')).toBeFalsy();
expect(view.$('.occupants').is(':visible')).toBeFalsy();
var $chat_body = view.$('.chatroom-body');
......@@ -796,7 +796,7 @@
var view = this.chatboxviews.get('problematic@muc.localhost');
spyOn(view, 'renderPasswordForm').andCallThrough();
runs(function () {
view.onChatRoomPresence(presence, {'nick': 'dummy'});
view.onChatRoomPresence(presence);
});
waits(250);
runs(function () {
......@@ -816,11 +816,11 @@
.c('x').attrs({xmlns:'http://jabber.org/protocol/muc'}).up()
.c('error').attrs({by:'lounge@localhost', type:'auth'})
.c('registration-required').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
var view = this.chatboxviews.get('problematic@muc.localhost');
var view = converse.chatboxviews.get('problematic@muc.localhost');
spyOn(view, 'showErrorMessage').andCallThrough();
view.onChatRoomPresence(presence, {'nick': 'dummy'});
view.onChatRoomPresence(presence);
expect(view.$el.find('.chatroom-body p:last').text()).toBe('You are not on the member list of this room');
}.bind(converse));
});
it("will show an error message if the user has been banned", function () {
var presence = $pres().attrs({
......@@ -831,43 +831,81 @@
.c('x').attrs({xmlns:'http://jabber.org/protocol/muc'}).up()
.c('error').attrs({by:'lounge@localhost', type:'auth'})
.c('forbidden').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
var view = this.chatboxviews.get('problematic@muc.localhost');
var view = converse.chatboxviews.get('problematic@muc.localhost');
spyOn(view, 'showErrorMessage').andCallThrough();
view.onChatRoomPresence(presence, {'nick': 'dummy'});
view.onChatRoomPresence(presence);
expect(view.$el.find('.chatroom-body p:last').text()).toBe('You have been banned from this room');
}.bind(converse));
});
it("will show an error message if no nickname was specified for the user", function () {
it("will render a nickname form if a nickname conflict happens and muc_nickname_from_jid=false", function () {
var presence = $pres().attrs({
from:'lounge@localhost/thirdwitch',
id:'n13mt3l',
to:'dummy@localhost/pda',
type:'error'})
.c('x').attrs({xmlns:'http://jabber.org/protocol/muc'}).up()
.c('error').attrs({by:'lounge@localhost', type:'modify'})
.c('jid-malformed').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
var view = this.chatboxviews.get('problematic@muc.localhost');
.c('error').attrs({by:'lounge@localhost', type:'cancel'})
.c('conflict').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
var view = converse.chatboxviews.get('problematic@muc.localhost');
spyOn(view, 'showErrorMessage').andCallThrough();
view.onChatRoomPresence(presence, {'nick': 'dummy'});
expect(view.$el.find('.chatroom-body p:last').text()).toBe('No nickname was specified');
}.bind(converse));
view.onChatRoomPresence(presence);
expect(view.$el.find('.chatroom-body form.chatroom-form label:first').text()).toBe('Please choose your nickname');
});
it("will automatically choose a new nickname if a nickname conflict happens and muc_nickname_from_jid=true", function () {
/*
<presence
from='coven@chat.shakespeare.lit/thirdwitch'
id='n13mt3l'
to='hag66@shakespeare.lit/pda'
type='error'>
<x xmlns='http://jabber.org/protocol/muc'/>
<error by='coven@chat.shakespeare.lit' type='cancel'>
<conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</presence>
*/
converse.muc_nickname_from_jid = true;
it("will show an error message if the user is not allowed to have created the room", function () {
var presence = $pres().attrs({
from:'lounge@localhost/thirdwitch',
var attrs = {
from:'lounge@localhost/dummy',
id:'n13mt3l',
to:'dummy@localhost/pda',
type:'error'})
type:'error'
};
var presence = $pres().attrs(attrs)
.c('x').attrs({xmlns:'http://jabber.org/protocol/muc'}).up()
.c('error').attrs({by:'lounge@localhost', type:'cancel'})
.c('not-allowed').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
var view = this.chatboxviews.get('problematic@muc.localhost');
.c('conflict').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
var view = converse.chatboxviews.get('problematic@muc.localhost');
spyOn(view, 'showErrorMessage').andCallThrough();
view.onChatRoomPresence(presence, {'nick': 'dummy'});
expect(view.$el.find('.chatroom-body p:last').text()).toBe('You are not allowed to create new rooms');
}.bind(converse));
spyOn(view, 'join').andCallThrough();
it("will show an error message if the user's nickname doesn't conform to room policy", function () {
// Simulate repeatedly that there's already someone in the room
// with that nickname
view.onChatRoomPresence(presence);
expect(view.join).toHaveBeenCalledWith('dummy-2');
attrs.from = 'lounge@localhost/dummy-2';
presence = $pres().attrs(attrs)
.c('x').attrs({xmlns:'http://jabber.org/protocol/muc'}).up()
.c('error').attrs({by:'lounge@localhost', type:'cancel'})
.c('conflict').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
view.onChatRoomPresence(presence);
expect(view.join).toHaveBeenCalledWith('dummy-3');
attrs.from = 'lounge@localhost/dummy-3';
presence = $pres().attrs(attrs)
.c('x').attrs({xmlns:'http://jabber.org/protocol/muc'}).up()
.c('error').attrs({by:'lounge@localhost', type:'cancel'})
.c('conflict').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
view.onChatRoomPresence(presence);
expect(view.join).toHaveBeenCalledWith('dummy-4');
});
it("will show an error message if the user is not allowed to have created the room", function () {
var presence = $pres().attrs({
from:'lounge@localhost/thirdwitch',
id:'n13mt3l',
......@@ -875,14 +913,14 @@
type:'error'})
.c('x').attrs({xmlns:'http://jabber.org/protocol/muc'}).up()
.c('error').attrs({by:'lounge@localhost', type:'cancel'})
.c('not-acceptable').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
.c('not-allowed').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
var view = this.chatboxviews.get('problematic@muc.localhost');
spyOn(view, 'showErrorMessage').andCallThrough();
view.onChatRoomPresence(presence, {'nick': 'dummy'});
expect(view.$el.find('.chatroom-body p:last').text()).toBe("Your nickname doesn't conform to this room's policies");
view.onChatRoomPresence(presence);
expect(view.$el.find('.chatroom-body p:last').text()).toBe('You are not allowed to create new rooms');
}.bind(converse));
it("will show an error message if the user's nickname is already taken", function () {
it("will show an error message if the user's nickname doesn't conform to room policy", function () {
var presence = $pres().attrs({
from:'lounge@localhost/thirdwitch',
id:'n13mt3l',
......@@ -890,13 +928,12 @@
type:'error'})
.c('x').attrs({xmlns:'http://jabber.org/protocol/muc'}).up()
.c('error').attrs({by:'lounge@localhost', type:'cancel'})
.c('conflict').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
var view = this.chatboxviews.get('problematic@muc.localhost');
.c('not-acceptable').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
var view = converse.chatboxviews.get('problematic@muc.localhost');
spyOn(view, 'showErrorMessage').andCallThrough();
view.onChatRoomPresence(presence, {'nick': 'dummy'});
expect(view.$el.find('.chatroom-body p:last').text()).toBe(
"The nickname you chose is reserved or currently in use, please choose a different one.");
}.bind(converse));
view.onChatRoomPresence(presence);
expect(view.$el.find('.chatroom-body p:last').text()).toBe("Your nickname doesn't conform to this room's policies");
});
it("will show an error message if the room doesn't yet exist", function () {
var presence = $pres().attrs({
......@@ -907,11 +944,11 @@
.c('x').attrs({xmlns:'http://jabber.org/protocol/muc'}).up()
.c('error').attrs({by:'lounge@localhost', type:'cancel'})
.c('item-not-found').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
var view = this.chatboxviews.get('problematic@muc.localhost');
var view = converse.chatboxviews.get('problematic@muc.localhost');
spyOn(view, 'showErrorMessage').andCallThrough();
view.onChatRoomPresence(presence, {'nick': 'dummy'});
view.onChatRoomPresence(presence);
expect(view.$el.find('.chatroom-body p:last').text()).toBe("This room does not (yet) exist");
}.bind(converse));
});
it("will show an error message if the room has reached its maximum number of occupants", function () {
var presence = $pres().attrs({
......@@ -922,11 +959,11 @@
.c('x').attrs({xmlns:'http://jabber.org/protocol/muc'}).up()
.c('error').attrs({by:'lounge@localhost', type:'cancel'})
.c('service-unavailable').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
var view = this.chatboxviews.get('problematic@muc.localhost');
var view = converse.chatboxviews.get('problematic@muc.localhost');
spyOn(view, 'showErrorMessage').andCallThrough();
view.onChatRoomPresence(presence, {'nick': 'dummy'});
view.onChatRoomPresence(presence);
expect(view.$el.find('.chatroom-body p:last').text()).toBe("This room has reached its maximum number of occupants");
}.bind(converse));
});
}.bind(converse));
}.bind(converse, mock, test_utils));
}));
......@@ -159,6 +159,7 @@
this.updateSettings({
allow_muc_invitations: true,
allow_muc: true,
muc_nickname_from_jid: false, // Use the node part of the user's JID as room nickname
auto_join_on_invite: false, // Auto-join chatroom on invite
auto_join_rooms: [], // List of maps {'jid': 'room@example.org', 'nick': 'WizardKing69' },
// providing room jids and nicks or simply a list JIDs.
......@@ -694,7 +695,7 @@
'node': 'x-roomuser-item'
}),
this.onNickNameFound.bind(this),
this.renderNicknameForm.bind(this)
this.onNickNameNotFound.bind(this)
);
},
......@@ -708,13 +709,51 @@
.find('query[node="x-roomuser-item"] identity')
.attr('name');
if (!nick) {
this.renderNicknameForm();
this.onNickNameNotFound();
} else {
this.join(nick);
}
},
onNickNameNotFound: function (message) {
if (converse.muc_nickname_from_jid) {
// We try to enter the room with the node part of
// the user's JID.
this.join(Strophe.unescapeNode(Strophe.getNodeFromJid(converse.bare_jid)));
} else {
this.renderNicknameForm(message);
}
},
onNicknameClash: function (presence) {
/* When the nickname is already taken, we either render a
* form for the user to choose a new nickname, or we
* try to make the nickname unique by adding an integer to
* it. So john will become john-2, and then john-3 and so on.
*
* Which option is take depends on the value of
* muc_nickname_from_jid.
*/
if (converse.muc_nickname_from_jid) {
var nick = presence.getAttribute('from').split('/')[1];
if (nick === Strophe.unescapeNode(Strophe.getNodeFromJid(converse.bare_jid))) {
this.join(nick + '-2');
} else {
var del= nick.lastIndexOf("-");
var num = nick.substring(del+1, nick.length);
this.join(nick.substring(0, del+1) + String(Number(num)+1));
}
} else {
this.renderNicknameForm(
__("The nickname you chose is reserved or currently in use, please choose a different one.")
);
}
},
renderNicknameForm: function (message) {
/* Render a form which allows the user to choose their
* nickname.
*/
this.$('.chatroom-body').children().addClass('hidden');
this.$('span.centered.spinner').remove();
if (typeof message !== "string") {
......@@ -883,9 +922,10 @@
return el;
},
showErrorMessage: function ($error) {
showErrorMessage: function (presence) {
// We didn't enter the room, so we must remove it from the MUC
// add-on
var $error = $(presence).find('error');
if ($error.attr('type') === 'auth') {
if ($error.find('not-authorized').length) {
this.renderPasswordForm();
......@@ -904,7 +944,7 @@
} else if ($error.find('not-acceptable').length) {
this.showDisconnectMessage(__("Your nickname doesn't conform to this room's policies"));
} else if ($error.find('conflict').length) {
this.renderNicknameForm(__("The nickname you chose is reserved or currently in use, please choose a different one."));
this.onNicknameClash(presence);
} else if ($error.find('item-not-found').length) {
this.showDisconnectMessage(__("This room does not (yet) exist"));
} else if ($error.find('service-unavailable').length) {
......@@ -940,7 +980,7 @@
var nick = this.model.get('nick');
if ($presence.attr('type') === 'error') {
this.model.set('connection_status', Strophe.Status.DISCONNECTED);
this.showErrorMessage($presence.find('error'));
this.showErrorMessage(pres);
} else {
is_self = ($presence.find("status[code='110']").length) ||
($presence.attr('from') === this.model.get('id')+'/'+Strophe.escapeNode(nick));
......
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