Move all MUC joining logic to the model

This commit is contained in:
JC Brand 2019-05-20 10:06:37 +02:00
parent 39363d495f
commit 7e515dd4b1
3 changed files with 63 additions and 123 deletions

View File

@ -307,7 +307,7 @@
_converse.connection._dataRecv(test_utils.createRequest(features_stanza));
const view = _converse.chatboxviews.get('lounge@localhost');
spyOn(view, 'join').and.callThrough();
spyOn(view.model, 'join').and.callThrough();
/* <iq to="myroom@conference.chat.example.org"
* from="jordie.langen@chat.example.org/converse.js-11659299"
@ -344,7 +344,7 @@
const input = await test_utils.waitUntil(() => view.el.querySelector('input[name="nick"]'));
input.value = 'nicky';
view.el.querySelector('input[type=submit]').click();
expect(view.join).toHaveBeenCalled();
expect(view.model.join).toHaveBeenCalled();
// The user has just entered the room (because join was called)
// and receives their own presence from the server.
@ -359,7 +359,7 @@
* </x>
* </presence>
*/
var presence = $pres({
const presence = $pres({
to:'dummy@localhost/resource',
from:'lounge@localhost/thirdwitch',
id:'5025e055-036c-4bc5-a227-706e7e352053'
@ -1752,7 +1752,7 @@
_converse.connection._dataRecv(test_utils.createRequest(features_stanza));
const view = _converse.chatboxviews.get('lounge@localhost');
spyOn(view, 'join').and.callThrough();
spyOn(view.model, 'join').and.callThrough();
/* <iq from='hag66@shakespeare.lit/pda'
* id='getnick1'
@ -1795,7 +1795,7 @@
.c('identity', {'category': 'conference', 'name': 'thirdwitch', 'type': 'text'});
_converse.connection._dataRecv(test_utils.createRequest(stanza));
expect(view.join).toHaveBeenCalled();
expect(view.model.join).toHaveBeenCalled();
// The user has just entered the groupchat (because join was called)
// and receives their own presence from the server.
@ -3617,11 +3617,11 @@
.toBe('This groupchat requires a password');
// Let's submit the form
spyOn(view, 'join');
spyOn(view.model, 'join');
const input_el = view.el.querySelector('[name="password"]');
input_el.value = 'secret';
view.el.querySelector('input[type=submit]').click();
expect(view.join).toHaveBeenCalledWith('dummy', 'secret');
expect(view.model.join).toHaveBeenCalledWith('dummy', 'secret');
done();
}));
@ -3734,12 +3734,12 @@
const view = _converse.chatboxviews.get(groupchat_jid);
spyOn(view, 'showErrorMessage').and.callThrough();
spyOn(view, 'join').and.callThrough();
spyOn(view.model, 'join').and.callThrough();
// Simulate repeatedly that there's already someone in the groupchat
// with that nickname
_converse.connection._dataRecv(test_utils.createRequest(presence));
expect(view.join).toHaveBeenCalledWith('dummy-2');
expect(view.model.join).toHaveBeenCalledWith('dummy-2');
attrs.from = `${groupchat_jid}/dummy-2`;
attrs.id = u.getUniqueId();
@ -3749,7 +3749,7 @@
.c('conflict').attrs({xmlns:'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
_converse.connection._dataRecv(test_utils.createRequest(presence));
expect(view.join).toHaveBeenCalledWith('dummy-3');
expect(view.model.join).toHaveBeenCalledWith('dummy-3');
attrs.from = `${groupchat_jid}/dummy-3`;
attrs.id = new Date().getTime();
@ -3758,7 +3758,7 @@
.c('error').attrs({'by': groupchat_jid, 'type': 'cancel'})
.c('conflict').attrs({'xmlns':'urn:ietf:params:xml:ns:xmpp-stanzas'}).nodeTree;
_converse.connection._dataRecv(test_utils.createRequest(presence));
expect(view.join).toHaveBeenCalledWith('dummy-4');
expect(view.model.join).toHaveBeenCalledWith('dummy-4');
done();
}));

View File

@ -544,7 +544,7 @@ converse.plugins.add('converse-muc-views', {
this.model.messages.on('reset', () => (this.content.innerHTML = ''));
this.model.on('change:affiliation', this.renderHeading, this);
this.model.on('change:connection_status', this.afterConnected, this);
this.model.on('change:connection_status', this.onConnectionStatusChanged, this);
this.model.on('change:hidden_occupants', this.updateOccupantsToggle, this);
this.model.on('change:jid', this.renderHeading, this);
this.model.on('change:name', this.renderHeading, this);
@ -580,7 +580,7 @@ converse.plugins.add('converse-muc-views', {
// is a hanging chatbox (i.e. not in the collection anymore).
return;
}
this.populateAndJoin();
this.model.join();
}
/**
* Triggered once a groupchat has been opened
@ -747,7 +747,7 @@ converse.plugins.add('converse-muc-views', {
/* Override from converse-chatview, specifically to avoid
* the 'active' chat state from being sent out prematurely.
*
* This is instead done in `afterConnected` below.
* This is instead done in `onConnectionStatusChanged` below.
*/
if (u.isPersistableModel(this.model)) {
this.model.clearUnreadMsgCounter();
@ -768,10 +768,13 @@ converse.plugins.add('converse-muc-views', {
this.afterShown();
},
afterConnected () {
if (this.model.get('connection_status') === converse.ROOMSTATUS.CONNECTING) {
onConnectionStatusChanged () {
const conn_status = this.model.get('connection_status');
if (conn_status === converse.ROOMSTATUS.NICKNAME_REQUIRED) {
this.renderNicknameForm();
} else if (conn_status === converse.ROOMSTATUS.CONNECTING) {
this.showSpinner();
} else if (this.model.get('connection_status') === converse.ROOMSTATUS.ENTERED) {
} else if (conn_status === converse.ROOMSTATUS.ENTERED) {
this.hideSpinner();
this.setChatState(_converse.ACTIVE);
this.scrollDown();
@ -1193,28 +1196,6 @@ converse.plugins.add('converse-muc-views', {
}
},
populateAndJoin () {
this.model.occupants.fetchMembers();
this.join();
},
/**
* Join the groupchat.
* @private
* @method _converse.ChatRoomView#join
* @param { String } nick - The user's nickname
* @param { String } password - Optional password, if required by the groupchat
*/
join (nick, password) {
if (!nick && !this.model.get('nick')) {
this.checkForReservedNick();
return this;
}
this.showSpinner();
this.model.join(nick, password);
return this;
},
/**
* Renders a form given an IQ stanza containing the current
* groupchat configuration.
@ -1273,34 +1254,6 @@ converse.plugins.add('converse-muc-views', {
}
},
checkForReservedNick () {
/* User service-discovery to ask the XMPP server whether
* this user has a reserved nickname for this groupchat.
* If so, we'll use that, otherwise we render the nickname form.
*/
this.showSpinner();
this.model.checkForReservedNick()
.then(this.onReservedNickFound.bind(this))
.catch(this.onReservedNickNotFound.bind(this));
},
onReservedNickFound (iq) {
if (this.model.get('nick')) {
this.join();
} else {
this.onReservedNickNotFound();
}
},
onReservedNickNotFound (message) {
const nick = _converse.getDefaultMUCNickname();
if (nick) {
this.join(nick);
} else {
this.renderNicknameForm(message);
}
},
onNicknameClash (presence) {
/* When the nickname is already taken, we either render a
* form for the user to choose a new nickname, or we
@ -1313,11 +1266,11 @@ converse.plugins.add('converse-muc-views', {
if (_converse.muc_nickname_from_jid) {
const nick = presence.getAttribute('from').split('/')[1];
if (nick === _converse.getDefaultMUCNickname()) {
this.join(nick + '-2');
this.model.join(nick + '-2');
} else {
const del= nick.lastIndexOf("-");
const num = nick.substring(del+1, nick.length);
this.join(nick.substring(0, del+1) + String(Number(num)+1));
this.model.join(nick.substring(0, del+1) + String(Number(num)+1));
}
} else {
this.renderNicknameForm(
@ -1930,7 +1883,7 @@ converse.plugins.add('converse-muc-views', {
submitPassword (ev) {
ev.preventDefault();
const password = this.el.querySelector('input[type=password]').value;
this.chatroomview.join(this.chatroomview.model.get('nick'), password);
this.chatroomview.model.join(this.chatroomview.model.get('nick'), password);
this.model.set('validation_message', null);
}
});
@ -1968,7 +1921,7 @@ converse.plugins.add('converse-muc-views', {
const nick_el = ev.target.nick;
const nick = nick_el.value.trim();
if (nick) {
this.chatroomview.join(nick);
this.chatroomview.model.join(nick);
this.model.set({
'validation_message': null,
'nickname': nick
@ -2243,20 +2196,6 @@ converse.plugins.add('converse-muc-views', {
fetchAndSetMUCDomain(view);
view.model.on('change:connected', _.partial(fetchAndSetMUCDomain, view));
});
function reconnectToChatRooms () {
/* Upon a reconnection event from converse, join again
* all the open groupchats.
*/
_converse.chatboxviews.each(view => {
if (view.model.get('type') === _converse.CHATROOMS_TYPE) {
view.model.save('connection_status', converse.ROOMSTATUS.DISCONNECTED);
view.model.registerHandlers();
view.populateAndJoin();
}
});
}
_converse.api.listen.on('reconnected', reconnectToChatRooms);
/************************ END Event Handlers ************************/

View File

@ -226,6 +226,7 @@ converse.plugins.add('converse-muc', {
!this.get('reserved_nick') &&
await _converse.api.disco.supports(Strophe.NS.MUC_REGISTER, this.get('jid'))) {
this.occupants.fetchMembers();
this.registerNickname()
}
},
@ -320,10 +321,11 @@ converse.plugins.add('converse-muc', {
* @param { String } nick - The user's nickname
* @param { String } password - Optional password, if required by the groupchat.
*/
join (nick, password) {
nick = nick ? nick : this.get('nick');
async join (nick, password) {
nick = nick ? nick : await this.getNickname();
if (!nick) {
throw new TypeError('join: You need to provide a valid nickname');
u.safeSave(this, {'connection_status': converse.ROOMSTATUS.NICKNAME_REQUIRED});
return this;
}
if (this.get('connection_status') === converse.ROOMSTATUS.ENTERED) {
// We have restored a groupchat from session storage,
@ -843,15 +845,29 @@ converse.plugins.add('converse-muc', {
.catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
},
async getNickname () {
let nick = this.get('nick');
if (!nick) {
try {
nick = await this.getReservedNick();
this.save({'reserved_nick': nick, 'nick': nick}, {'silent': true});
} catch (e) {
nick = _converse.getDefaultMUCNickname();
this.save({'nick': nick}, {'silent': true});
}
}
return nick;
},
/**
* Use service-discovery to ask the XMPP server whether
* this user has a reserved nickname for this groupchat.
* If so, we'll use that, otherwise we render the nickname form.
* @private
* @method _converse.ChatRoom#checkForReservedNick
* @returns { promise } A promise which resolves with the response IQ
* @method _converse.ChatRoom#getReservedNick
* @returns { promise } A promise which resolves with the reserved nick or null
*/
async checkForReservedNick () {
async getReservedNick () {
const iq = await _converse.api.sendIQ(
$iq({
'to': this.get('jid'),
@ -862,13 +878,8 @@ converse.plugins.add('converse-muc', {
'node': 'x-roomuser-item'
})
);
const identity_el = iq.querySelector('query[node="x-roomuser-item"] identity'),
nick = identity_el ? identity_el.getAttribute('name') : null;
this.save({
'reserved_nick': nick,
'nick': nick
}, {'silent': true});
return iq;
const identity_el = iq.querySelector('query[node="x-roomuser-item"] identity');
return identity_el ? identity_el.getAttribute('name') : null;
},
async registerNickname () {
@ -1417,16 +1428,10 @@ converse.plugins.add('converse-muc', {
}
if (result === true) {
const chatroom = openChatRoom(room_jid, {'password': x_el.getAttribute('password') });
if (chatroom.get('connection_status') === converse.ROOMSTATUS.DISCONNECTED) {
// XXX: Leaky abstraction from views here
if (_converse.chatboxviews) {
_converse.chatboxviews.get(room_jid).join();
} else {
_converse.chatboxes.get(room_jid).join();
}
}
}
};
if (_converse.allow_muc_invitations) {
@ -1497,24 +1502,6 @@ converse.plugins.add('converse-muc', {
});
}
function fetchRegistrationForm (room_jid, user_jid) {
_converse.api.sendIQ(
$iq({
'from': user_jid,
'to': room_jid,
'type': 'get'
}).c('query', {'xmlns': Strophe.NS.REGISTER})
).then(iq => {
}).catch(iq => {
if (sizzle('item-not-found[xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"]', iq).length) {
this.feedback.set('error', __('Error: the groupchat %1$s does not exist.', this.model.getDisplayName()));
} else if (sizzle('not-allowed[xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"]').length) {
this.feedback.set('error', __("Sorry, you're not allowed to register in this groupchat"));
}
});
}
/************************ BEGIN Event Handlers ************************/
_converse.api.listen.on('addClientFeatures', () => {
@ -1539,6 +1526,20 @@ converse.plugins.add('converse-muc', {
}
});
});
function reconnectToChatRooms () {
/* Upon a reconnection event from converse, join again
* all the open groupchats.
*/
_converse.chatboxes.each(model => {
if (model.get('type') === _converse.CHATROOMS_TYPE) {
model.save('connection_status', converse.ROOMSTATUS.DISCONNECTED);
model.registerHandlers();
model.join();
}
});
}
_converse.api.listen.on('reconnected', reconnectToChatRooms);
/************************ END Event Handlers ************************/