Commit 49b99d96 authored by JC Brand's avatar JC Brand

Refactored status message rendering code

As a result we now implement more status codes from the spec.
Specifically the codes related to forced removal form the room

Also fixed a bug related to wrong authentication when logging in.
parent b0f0eb2b
...@@ -8,6 +8,8 @@ Changelog ...@@ -8,6 +8,8 @@ Changelog
[jcbrand] [jcbrand]
- Bugfix: Cannot join chatroom when clicking from a list of rooms. - Bugfix: Cannot join chatroom when clicking from a list of rooms.
[jcbrand] [jcbrand]
- Add better support for kicking or banning users from chatrooms.
[jcbrand]
0.3 (2013-05-21) 0.3 (2013-05-21)
---------------- ----------------
......
...@@ -391,7 +391,7 @@ ...@@ -391,7 +391,7 @@
else if (match[1] === "help") { else if (match[1] === "help") {
msgs = [ msgs = [
'<strong>/help</strong>: Show this menu', '<strong>/help</strong>: Show this menu',
'<strong>/me</strong>: Refer to yourself in the third person', '<strong>/me</strong>: Write in the third person',
'<strong>/clear</strong>: Remove messages' '<strong>/clear</strong>: Remove messages'
]; ];
this.addHelpMessages(msgs); this.addHelpMessages(msgs);
...@@ -1048,6 +1048,9 @@ ...@@ -1048,6 +1048,9 @@
case 'msg': case 'msg':
// TODO: Private messages // TODO: Private messages
break; break;
case 'clear':
this.$el.find('.chat-content').empty();
break;
case 'topic': case 'topic':
converse.connection.muc.setTopic(this.model.get('jid'), match[2]); converse.connection.muc.setTopic(this.model.get('jid'), match[2]);
break; break;
...@@ -1065,7 +1068,9 @@ ...@@ -1065,7 +1068,9 @@
break; break;
case 'help': case 'help':
$chat_content = this.$el.find('.chat-content'); $chat_content = this.$el.find('.chat-content');
$chat_content.append('<div class="chat-help"><strong>/help</strong>: Show this menu</div>' + $chat_content.append(
'<div class="chat-help"><strong>/help</strong>: Show this menu</div>' +
'<div class="chat-help"><strong>/clear</strong>: Write in the third person</div>' +
'<div class="chat-help"><strong>/topic</strong>: Set chatroom topic</div>'); '<div class="chat-help"><strong>/topic</strong>: Set chatroom topic</div>');
/* TODO: /* TODO:
$chat_content.append($('<div class="chat-help"><strong>/kick</strong>: Kick out user</div>')); $chat_content.append($('<div class="chat-help"><strong>/kick</strong>: Kick out user</div>'));
...@@ -1291,11 +1296,120 @@ ...@@ -1291,11 +1296,120 @@
this.$el.find('.chatroom-form').on('submit', $.proxy(this.submitPassword, this)); this.$el.find('.chatroom-form').on('submit', $.proxy(this.submitPassword, this));
}, },
renderErrorMessage: function (msg) { showDisconnectMessage: function (msg) {
this.$el.find('.chat-area').hide();
this.$el.find('.participants').hide();
this.$el.find('img.centered.spinner').remove(); this.$el.find('img.centered.spinner').remove();
this.$el.find('.chat-body').append($('<p>'+msg+'</p>')); this.$el.find('.chat-body').append($('<p>'+msg+'</p>'));
}, },
infoMessages: {
100: 'This room is not anonymous',
102: 'This room now shows unavailable members',
103: 'This room does not show unavailable members',
104: 'Non-privacy-related room configuration has changed',
170: 'Room logging is now enabled',
171: 'Room logging is now disabled',
172: 'This room is now non-anonymous',
173: 'This room is now semi-anonymous',
174: 'This room is now fully-anonymous',
201: 'A new room has been created',
210: 'Your nickname has been changed'
},
actionInfoMessages: {
301: ' has been banned',
307: ' has been kicked out',
321: " has been removed because of an affiliation change",
322: " has been removed for not being a member"
},
disconnectMessages: {
301: 'You have been banned from this room',
307: 'You have been kicked from this room',
321: "You have been removed from this room because of an affiliation change",
322: "You have been removed from this room because the room" +
"has changed to members-only and you're not a member",
332: "You have been removed from this room because the MUC " +
"(Multi-user chat) service is being shut down."
},
showStatusMessages: function ($el, is_self) {
/* Check for status codes and communicate their purpose to the user
* See: http://xmpp.org/registrar/mucstatus.html
*/
var $chat_content = this.$el.find('.chat-content'),
$stats = $el.find('status'),
disconnect_msgs = [],
info_msgs = [],
action_msgs = [],
msgs, i;
for (i=0; i<$stats.length; i++) {
var stat = $stats[i].getAttribute('code');
if (is_self) {
if (_.contains(_.keys(this.disconnectMessages), stat)) {
disconnect_msgs.push(this.disconnectMessages[stat]);
}
} else {
if (_.contains(_.keys(this.infoMessages), stat)) {
info_msgs.push(this.infoMessages[stat]);
} else if (_.contains(_.keys(this.actionInfoMessages), stat)) {
action_msgs.push(
'<strong>'+
Strophe.unescapeNode(Strophe.getResourceFromJid($el.attr('from')))+
'</strong>'+
this.actionInfoMessages[stat]);
}
}
}
if (disconnect_msgs.length > 0) {
for (i=0; i<disconnect_msgs.length; i++) {
this.showDisconnectMessage(disconnect_msgs[i]);
}
return true;
}
if (!this.$el.find('.chat-area').length) { this.renderChatArea(); }
for (i=0; i<info_msgs.length; i++) {
$chat_content.append(this.info_template({message: info_msgs[i]}));
}
for (i=0; i<action_msgs.length; i++) {
$chat_content.append(this.info_template({message: action_msgs[i]}));
}
return false;
},
showErrorMessage: function ($error, room) {
var $chat_content = this.$el.find('.chat-content');
// We didn't enter the room, so we must remove it from the MUC
// add-on
converse.connection.muc.removeRoom(room.name);
if ($error.attr('type') == 'auth') {
if ($error.find('not-authorized').length) {
this.renderPasswordForm();
} else if ($error.find('registration-required').length) {
this.showDisconnectMessage('You are not on the member list of this room');
} else if ($error.find('forbidden').length) {
this.showDisconnectMessage('You have been banned from this room');
}
} else if ($error.attr('type') == 'modify') {
if ($error.find('jid-malformed').length) {
this.showDisconnectMessage('No nickname was specified');
}
} else if ($error.attr('type') == 'cancel') {
if ($error.find('not-allowed').length) {
this.showDisconnectMessage('You are not allowed to create new rooms');
} 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.showDisconnectMessage("Your nickname is already taken");
} else if ($error.find('item-not-found').length) {
this.showDisconnectMessage("This room does not (yet) exist");
} else if ($error.find('service-unavailable').length) {
this.showDisconnectMessage("This room has reached it's maximum number of occupants");
}
}
},
submitPassword: function (ev) { submitPassword: function (ev) {
ev.preventDefault(); ev.preventDefault();
var password = this.$el.find('.chatroom-form').find('input[type=password]').val(); var password = this.$el.find('.chatroom-form').find('input[type=password]').val();
...@@ -1313,18 +1427,23 @@ ...@@ -1313,18 +1427,23 @@
onChatRoomPresence: function (presence, room) { onChatRoomPresence: function (presence, room) {
var nick = room.nick, var nick = room.nick,
$presence = $(presence), $presence = $(presence),
from = $presence.attr('from'), $item; from = $presence.attr('from'),
if ($presence.attr('type') !== 'error') { is_self = ($presence.find("status[code='110']").length) || (from == room.name+'/'+Strophe.escapeNode(nick)),
if (!this.$el.find('.chat-area').length) { this.renderChatArea(); } $item;
if ($presence.attr('type') === 'error') {
this.showErrorMessage($presence.find('error'), room);
} else {
if (this.showStatusMessages($presence, is_self)) {
return true;
}
if ($presence.find("status[code='201']").length) { if ($presence.find("status[code='201']").length) {
// This is a new chatroom. We create an instant // This is a new chatroom. We create an instant
// chatroom, and let the user manually set any // chatroom, and let the user manually set any
// configuration setting. // configuration setting.
converse.connection.muc.createInstantRoom(room.name); converse.connection.muc.createInstantRoom(room.name);
} }
if (($presence.find("status[code='110']").length) || (from == room.name+'/'+Strophe.escapeNode(nick))) { if (is_self) {
// Check to see if it's our own presence
// code 110 indicates it but ejabberd doesn't seem to comply
$item = $presence.find('item'); $item = $presence.find('item');
if ($item.length) { if ($item.length) {
if ($item.attr('affiliation') == 'owner') { if ($item.attr('affiliation') == 'owner') {
...@@ -1336,66 +1455,10 @@ ...@@ -1336,66 +1455,10 @@
this.model.set({'nick': Strophe.getResourceFromJid(from)}); this.model.set({'nick': Strophe.getResourceFromJid(from)});
} }
} }
} else {
var $error = $presence.find('error'),
$chat_content = this.$el.find('.chat-content');
// We didn't enter the room, so we must remove it from the MUC
// add-on
converse.connection.muc.removeRoom(room.name);
if ($error.attr('type') == 'auth') {
if ($error.find('not-authorized').length) {
this.renderPasswordForm();
} else if ($error.find('registration-required').length) {
this.renderErrorMessage('You are not on the member list of this room');
} else if ($error.find('forbidden').length) {
this.renderErrorMessage('You have been banned from this room');
}
} else if ($error.attr('type') == 'modify') {
if ($error.find('jid-malformed').length) {
this.renderErrorMessage('No nickname was specified');
}
} else if ($error.attr('type') == 'cancel') {
if ($error.find('not-allowed').length) {
this.renderErrorMessage('You are not allowed to create new rooms');
} else if ($error.find('not-acceptable').length) {
this.renderErrorMessage("Your nickname doesn't conform to this room's policies");
} else if ($error.find('conflict').length) {
this.renderErrorMessage("Your nickname is already taken");
} else if ($error.find('item-not-found').length) {
this.renderErrorMessage("This room does not (yet) exist");
} else if ($error.find('service-unavailable').length) {
this.renderErrorMessage("This room has reached it's maximum number of occupants");
}
}
} }
return true; return true;
}, },
communicateStatusCodes: function ($message, $chat_content) {
/* Parse the message for status codes and communicate their purpose
* to the user.
* See: http://xmpp.org/registrar/mucstatus.html
*/
var status_messages = {
100: 'This room is not anonymous',
102: 'This room now shows unavailable members',
103: 'This room does not show unavailable members',
104: 'Non-privacy-related room configuration has changed',
170: 'Room logging is now enabled',
171: 'Room logging is now disabled',
172: 'This room is now non-anonymous',
173: 'This room is now semi-anonymous',
174: 'This room is now fully-anonymous'
};
$message.find('x').find('status').each($.proxy(function (idx, item) {
var code = $(item).attr('code');
var message = code && status_messages[code] || null;
if (message) {
$chat_content.append(this.info_template({message: message}));
}
}, this));
},
onChatRoomMessage: function (message) { onChatRoomMessage: function (message) {
var $message = $(message), var $message = $(message),
body = $message.children('body').text(), body = $message.children('body').text(),
...@@ -1425,7 +1488,7 @@ ...@@ -1425,7 +1488,7 @@
datestring: message_date.toString().substring(0,15) datestring: message_date.toString().substring(0,15)
})); }));
} }
this.communicateStatusCodes($message, $chat_content); this.showStatusMessages($message);
if (subject) { if (subject) {
this.$el.find('.chatroom-topic').text(subject).attr('title', subject); this.$el.find('.chatroom-topic').text(subject).attr('title', subject);
$chat_content.append(this.info_template({'message': 'Topic set by '+sender+' to: '+subject })); $chat_content.append(this.info_template({'message': 'Topic set by '+sender+' to: '+subject }));
...@@ -2337,9 +2400,10 @@ ...@@ -2337,9 +2400,10 @@
'<label>BOSH Service URL:</label>' + '<label>BOSH Service URL:</label>' +
'<input type="text" id="bosh_service_url">'), '<input type="text" id="bosh_service_url">'),
connect: function ($form, jid, password) {
connect: function (jid, password) { var $button = $form.find('input[type=submit]'),
var connection = new Strophe.Connection(converse.bosh_service_url); connection = new Strophe.Connection(converse.bosh_service_url);
$button.hide().after('<img class="spinner login-submit" src="images/spinner.gif"/>');
connection.connect(jid, password, $.proxy(function (status, message) { connection.connect(jid, password, $.proxy(function (status, message) {
if (status === Strophe.Status.CONNECTED) { if (status === Strophe.Status.CONNECTED) {
console.log('Connected'); console.log('Connected');
...@@ -2395,10 +2459,7 @@ ...@@ -2395,10 +2459,7 @@
$pw_input.addClass('error'); $pw_input.addClass('error');
} }
if (errors) { return; } if (errors) { return; }
this.connect($form, jid, password);
var $button = $form.find('input[type=submit]');
$button.hide().after('<img class="spinner login-submit" src="images/spinner.gif"/>');
this.connect(jid, password);
}, },
remove: function () { remove: function () {
......
...@@ -162,7 +162,7 @@ ...@@ -162,7 +162,7 @@
.c('registration-required').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree; .c('registration-required').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
var view = this.chatboxesview.views['problematic@muc.localhost']; var view = this.chatboxesview.views['problematic@muc.localhost'];
spyOn(converse.connection.muc, 'removeRoom'); spyOn(converse.connection.muc, 'removeRoom');
spyOn(view, 'renderErrorMessage').andCallThrough(); spyOn(view, 'showErrorMessage').andCallThrough();
view.onChatRoomPresence(presence, {'nick': 'dummy'}); view.onChatRoomPresence(presence, {'nick': 'dummy'});
expect(converse.connection.muc.removeRoom).toHaveBeenCalled(); expect(converse.connection.muc.removeRoom).toHaveBeenCalled();
expect(view.$el.find('.chat-body p').text()).toBe('You are not on the member list of this room'); expect(view.$el.find('.chat-body p').text()).toBe('You are not on the member list of this room');
...@@ -179,7 +179,7 @@ ...@@ -179,7 +179,7 @@
.c('forbidden').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree; .c('forbidden').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
var view = this.chatboxesview.views['problematic@muc.localhost']; var view = this.chatboxesview.views['problematic@muc.localhost'];
spyOn(converse.connection.muc, 'removeRoom'); spyOn(converse.connection.muc, 'removeRoom');
spyOn(view, 'renderErrorMessage').andCallThrough(); spyOn(view, 'showErrorMessage').andCallThrough();
view.onChatRoomPresence(presence, {'nick': 'dummy'}); view.onChatRoomPresence(presence, {'nick': 'dummy'});
expect(converse.connection.muc.removeRoom).toHaveBeenCalled(); expect(converse.connection.muc.removeRoom).toHaveBeenCalled();
expect(view.$el.find('.chat-body p').text()).toBe('You have been banned from this room'); expect(view.$el.find('.chat-body p').text()).toBe('You have been banned from this room');
...@@ -196,7 +196,7 @@ ...@@ -196,7 +196,7 @@
.c('jid-malformed').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree; .c('jid-malformed').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
var view = this.chatboxesview.views['problematic@muc.localhost']; var view = this.chatboxesview.views['problematic@muc.localhost'];
spyOn(converse.connection.muc, 'removeRoom'); spyOn(converse.connection.muc, 'removeRoom');
spyOn(view, 'renderErrorMessage').andCallThrough(); spyOn(view, 'showErrorMessage').andCallThrough();
view.onChatRoomPresence(presence, {'nick': 'dummy'}); view.onChatRoomPresence(presence, {'nick': 'dummy'});
expect(converse.connection.muc.removeRoom).toHaveBeenCalled(); expect(converse.connection.muc.removeRoom).toHaveBeenCalled();
expect(view.$el.find('.chat-body p').text()).toBe('No nickname was specified'); expect(view.$el.find('.chat-body p').text()).toBe('No nickname was specified');
...@@ -213,7 +213,7 @@ ...@@ -213,7 +213,7 @@
.c('not-allowed').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.chatboxesview.views['problematic@muc.localhost']; var view = this.chatboxesview.views['problematic@muc.localhost'];
spyOn(converse.connection.muc, 'removeRoom'); spyOn(converse.connection.muc, 'removeRoom');
spyOn(view, 'renderErrorMessage').andCallThrough(); spyOn(view, 'showErrorMessage').andCallThrough();
view.onChatRoomPresence(presence, {'nick': 'dummy'}); view.onChatRoomPresence(presence, {'nick': 'dummy'});
expect(converse.connection.muc.removeRoom).toHaveBeenCalled(); expect(converse.connection.muc.removeRoom).toHaveBeenCalled();
expect(view.$el.find('.chat-body p').text()).toBe('You are not allowed to create new rooms'); expect(view.$el.find('.chat-body p').text()).toBe('You are not allowed to create new rooms');
...@@ -230,7 +230,7 @@ ...@@ -230,7 +230,7 @@
.c('not-acceptable').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree; .c('not-acceptable').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
var view = this.chatboxesview.views['problematic@muc.localhost']; var view = this.chatboxesview.views['problematic@muc.localhost'];
spyOn(converse.connection.muc, 'removeRoom'); spyOn(converse.connection.muc, 'removeRoom');
spyOn(view, 'renderErrorMessage').andCallThrough(); spyOn(view, 'showErrorMessage').andCallThrough();
view.onChatRoomPresence(presence, {'nick': 'dummy'}); view.onChatRoomPresence(presence, {'nick': 'dummy'});
expect(converse.connection.muc.removeRoom).toHaveBeenCalled(); expect(converse.connection.muc.removeRoom).toHaveBeenCalled();
expect(view.$el.find('.chat-body p').text()).toBe("Your nickname doesn't conform to this room's policies"); expect(view.$el.find('.chat-body p').text()).toBe("Your nickname doesn't conform to this room's policies");
...@@ -247,7 +247,7 @@ ...@@ -247,7 +247,7 @@
.c('conflict').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree; .c('conflict').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
var view = this.chatboxesview.views['problematic@muc.localhost']; var view = this.chatboxesview.views['problematic@muc.localhost'];
spyOn(converse.connection.muc, 'removeRoom'); spyOn(converse.connection.muc, 'removeRoom');
spyOn(view, 'renderErrorMessage').andCallThrough(); spyOn(view, 'showErrorMessage').andCallThrough();
view.onChatRoomPresence(presence, {'nick': 'dummy'}); view.onChatRoomPresence(presence, {'nick': 'dummy'});
expect(converse.connection.muc.removeRoom).toHaveBeenCalled(); expect(converse.connection.muc.removeRoom).toHaveBeenCalled();
expect(view.$el.find('.chat-body p').text()).toBe("Your nickname is already taken"); expect(view.$el.find('.chat-body p').text()).toBe("Your nickname is already taken");
...@@ -264,7 +264,7 @@ ...@@ -264,7 +264,7 @@
.c('item-not-found').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree; .c('item-not-found').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
var view = this.chatboxesview.views['problematic@muc.localhost']; var view = this.chatboxesview.views['problematic@muc.localhost'];
spyOn(converse.connection.muc, 'removeRoom'); spyOn(converse.connection.muc, 'removeRoom');
spyOn(view, 'renderErrorMessage').andCallThrough(); spyOn(view, 'showErrorMessage').andCallThrough();
view.onChatRoomPresence(presence, {'nick': 'dummy'}); view.onChatRoomPresence(presence, {'nick': 'dummy'});
expect(converse.connection.muc.removeRoom).toHaveBeenCalled(); expect(converse.connection.muc.removeRoom).toHaveBeenCalled();
expect(view.$el.find('.chat-body p').text()).toBe("This room does not (yet) exist"); expect(view.$el.find('.chat-body p').text()).toBe("This room does not (yet) exist");
...@@ -281,7 +281,7 @@ ...@@ -281,7 +281,7 @@
.c('service-unavailable').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree; .c('service-unavailable').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
var view = this.chatboxesview.views['problematic@muc.localhost']; var view = this.chatboxesview.views['problematic@muc.localhost'];
spyOn(converse.connection.muc, 'removeRoom'); spyOn(converse.connection.muc, 'removeRoom');
spyOn(view, 'renderErrorMessage').andCallThrough(); spyOn(view, 'showErrorMessage').andCallThrough();
view.onChatRoomPresence(presence, {'nick': 'dummy'}); view.onChatRoomPresence(presence, {'nick': 'dummy'});
expect(converse.connection.muc.removeRoom).toHaveBeenCalled(); expect(converse.connection.muc.removeRoom).toHaveBeenCalled();
expect(view.$el.find('.chat-body p').text()).toBe("This room has reached it's maximum number of occupants"); expect(view.$el.find('.chat-body p').text()).toBe("This room has reached it's maximum number of occupants");
......
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