Re-add support for muc_domain and add locked_muc_domain.

updates #1373
This commit is contained in:
JC Brand 2019-02-26 10:34:41 +01:00
parent 2ddd918f6a
commit d3a4555165
7 changed files with 283 additions and 34 deletions

View File

@ -2,6 +2,8 @@
## 4.1.3 (Unreleased) ## 4.1.3 (Unreleased)
- New config setting [locked_muc_domain](https://conversejs.org/docs/html/configuration.html#locked-muc-domain)
- #1373: Re-add support for the [muc_domain](https://conversejs.org/docs/html/configuration.html#muc-domain) setting
- #1437: List of groupchats in modal doesn't scroll - #1437: List of groupchats in modal doesn't scroll
## 4.1.2 (2019-02-22) ## 4.1.2 (2019-02-22)
@ -23,7 +25,7 @@
- Bugfix: MUC invite form not appearing - Bugfix: MUC invite form not appearing
- #1369 Don't wrongly interpret message with `subject` as a topic change. - #1369 Don't wrongly interpret message with `subject` as a topic change.
- #1405 Status of contacts list are not displayed properly - #1405 Status of contacts list are not displayed properly
- #1408 New config option `roomconfig_whitelist` - #1408 New config option [roomconfig_whitelist](https://conversejs.org/docs/html/configuration.html#roomconfig-whitelist)
- #1410 HTTP upload not working if conversations push proxy is used - #1410 HTTP upload not working if conversations push proxy is used
- #1412 MUC moderator commands can be disabled selectively by config - #1412 MUC moderator commands can be disabled selectively by config
- #1413 Fix moderator commands that change affiliation - #1413 Fix moderator commands that change affiliation

67
dist/converse.js vendored
View File

@ -53303,6 +53303,8 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_3__["default"].plugins
_converse.api.settings.update({ _converse.api.settings.update({
'auto_list_rooms': false, 'auto_list_rooms': false,
'muc_disable_moderator_commands': false, 'muc_disable_moderator_commands': false,
'muc_domain': undefined,
'locked_muc_domain': undefined,
'muc_show_join_leave': true, 'muc_show_join_leave': true,
'roomconfig_whitelist': [], 'roomconfig_whitelist': [],
'visible_toolbar_buttons': { 'visible_toolbar_buttons': {
@ -53310,6 +53312,10 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_3__["default"].plugins
} }
}); });
if (_converse.locked_muc_domain && !_.isString(_converse.muc_domain)) {
throw new Error("Config Error: it makes no sense to set locked_muc_domain " + "to true when muc_domain is not set");
}
function ___(str) { function ___(str) {
/* This is part of a hack to get gettext to scan strings to be /* This is part of a hack to get gettext to scan strings to be
* translated. Strings we cannot send to the function above because * translated. Strings we cannot send to the function above because
@ -53459,22 +53465,31 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_3__["default"].plugins
initialize() { initialize() {
_converse.BootstrapModal.prototype.initialize.apply(this, arguments); _converse.BootstrapModal.prototype.initialize.apply(this, arguments);
if (_converse.muc_domain && !this.model.get('muc_domain')) {
this.model.save('muc_domain', _converse.muc_domain);
}
this.model.on('change:muc_domain', this.onDomainChange, this); this.model.on('change:muc_domain', this.onDomainChange, this);
}, },
toHTML() { toHTML() {
const muc_domain = this.model.get('muc_domain') || _converse.muc_domain;
return templates_list_chatrooms_modal_html__WEBPACK_IMPORTED_MODULE_19___default()(_.extend(this.model.toJSON(), { return templates_list_chatrooms_modal_html__WEBPACK_IMPORTED_MODULE_19___default()(_.extend(this.model.toJSON(), {
'heading_list_chatrooms': __('Query for Groupchats'), 'heading_list_chatrooms': __('Query for Groupchats'),
'label_server_address': __('Server address'), 'label_server_address': __('Server address'),
'label_query': __('Show groupchats'), 'label_query': __('Show groupchats'),
'server_placeholder': __('conference.example.org') 'show_form': !_converse.locked_muc_domain,
'server_placeholder': muc_domain ? muc_domain : __('conference.example.org')
})); }));
}, },
afterRender() { afterRender() {
this.el.addEventListener('shown.bs.modal', () => { if (_converse.locked_muc_domain) {
this.el.querySelector('input[name="server"]').focus(); this.updateRoomsList();
}, false); } else {
this.el.addEventListener('shown.bs.modal', () => this.el.querySelector('input[name="server"]').focus(), false);
}
}, },
openRoom(ev) { openRoom(ev) {
@ -53588,12 +53603,26 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_3__["default"].plugins
'submit form.add-chatroom': 'openChatRoom' 'submit form.add-chatroom': 'openChatRoom'
}, },
initialize() {
_converse.BootstrapModal.prototype.initialize.apply(this, arguments);
this.model.on('change:muc_domain', this.render, this);
},
toHTML() { toHTML() {
let placeholder = '';
if (!_converse.locked_muc_domain) {
const muc_domain = this.model.get('muc_domain') || _converse.muc_domain;
placeholder = muc_domain ? `name@${muc_domain}` : __('name@conference.example.org');
}
return templates_add_chatroom_modal_html__WEBPACK_IMPORTED_MODULE_5___default()(_.extend(this.model.toJSON(), { return templates_add_chatroom_modal_html__WEBPACK_IMPORTED_MODULE_5___default()(_.extend(this.model.toJSON(), {
'heading_new_chatroom': __('Enter a new Groupchat'), 'heading_new_chatroom': __('Enter a new Groupchat'),
'label_room_address': __('Groupchat address'), 'label_room_address': _converse.muc_domain ? __('Groupchat name') : __('Groupchat address'),
'label_nickname': __('Optional nickname'), 'label_nickname': __('Optional nickname'),
'chatroom_placeholder': __('name@conference.example.org'), 'chatroom_placeholder': placeholder,
'label_join': __('Join') 'label_join': __('Join')
})); }));
}, },
@ -53623,7 +53652,17 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_3__["default"].plugins
data.nick = undefined; data.nick = undefined;
} }
_converse.api.rooms.open(data.jid, data); let jid;
if (_converse.locked_muc_domain || _converse.muc_domain && !u.isValidJID(data.jid)) {
jid = `${Strophe.escapeNode(data.jid)}@${_converse.muc_domain}`;
} else {
jid = data.jid;
}
_converse.api.rooms.open(jid, _.extend(data, {
jid
}));
this.modal.hide(); this.modal.hide();
ev.target.reset(); ev.target.reset();
@ -66093,7 +66132,6 @@ _converse_core__WEBPACK_IMPORTED_MODULE_6__["default"].plugins.add('converse-muc
auto_join_on_invite: false, auto_join_on_invite: false,
auto_join_rooms: [], auto_join_rooms: [],
auto_register_muc_nickname: false, auto_register_muc_nickname: false,
muc_domain: undefined,
muc_history_max_stanzas: undefined, muc_history_max_stanzas: undefined,
muc_instant_rooms: true, muc_instant_rooms: true,
muc_nickname_from_jid: false muc_nickname_from_jid: false
@ -93667,18 +93705,23 @@ return __p
var _ = {escape:__webpack_require__(/*! ./node_modules/lodash/escape.js */ "./node_modules/lodash/escape.js")}; var _ = {escape:__webpack_require__(/*! ./node_modules/lodash/escape.js */ "./node_modules/lodash/escape.js")};
module.exports = function(o) { module.exports = function(o) {
var __t, __p = '', __e = _.escape; var __t, __p = '', __e = _.escape, __j = Array.prototype.join;
function print() { __p += __j.call(arguments, '') }
__p += '<!-- src/templates/list_chatrooms_modal.html -->\n<div class="modal fade" id="list-chatrooms-modal" tabindex="-1" role="dialog" aria-labelledby="list-chatrooms-modal-label" aria-hidden="true">\n <div class="modal-dialog" role="document">\n <div class="modal-content">\n <div class="modal-header">\n <h5 class="modal-title"\n id="list-chatrooms-modal-label">' + __p += '<!-- src/templates/list_chatrooms_modal.html -->\n<div class="modal fade" id="list-chatrooms-modal" tabindex="-1" role="dialog" aria-labelledby="list-chatrooms-modal-label" aria-hidden="true">\n <div class="modal-dialog" role="document">\n <div class="modal-content">\n <div class="modal-header">\n <h5 class="modal-title"\n id="list-chatrooms-modal-label">' +
__e(o.heading_list_chatrooms) + __e(o.heading_list_chatrooms) +
'</h5>\n <button type="button" class="close" data-dismiss="modal" aria-label="Close">\n <span aria-hidden="true">×</span>\n </button>\n </div>\n <div class="modal-body d-flex flex-column">\n <form class="converse-form list-chatrooms">\n <div class="form-group">\n <label for="chatroom">' + '</h5>\n <button type="button" class="close" data-dismiss="modal" aria-label="Close">\n <span aria-hidden="true">×</span>\n </button>\n </div>\n <div class="modal-body d-flex flex-column">\n ';
if (o.show_form) { ;
__p += '\n <form class="converse-form list-chatrooms">\n <div class="form-group">\n <label for="chatroom">' +
__e(o.label_server_address) + __e(o.label_server_address) +
':</label>\n <input type="text" value="' + ':</label>\n <input type="text" value="' +
__e(o.muc_domain) + __e(o.muc_domain) +
'" required="required" name="server" class="form-control" placeholder="' + '" required="required" name="server" class="form-control" placeholder="' +
__e(o.server_placeholder) + __e(o.server_placeholder) +
'"/>\n </div>\n <input type="submit" class="btn btn-primary" name="join" value="' + '"/>\n </div>\n <input type="submit" class="btn btn-primary" name="list" value="' +
__e(o.label_query) + __e(o.label_query) +
'"/>\n </form>\n <ul class="available-chatrooms list-group"></ul>\n </div>\n </div>\n </div>\n</div>\n'; '"/>\n </form>\n ';
} ;
__p += '\n <ul class="available-chatrooms list-group"></ul>\n </div>\n </div>\n </div>\n</div>\n';
return __p return __p
}; };

View File

@ -256,7 +256,8 @@ auto_list_rooms
* Default: ``false`` * Default: ``false``
If true, and the XMPP server on which the current user is logged in supports If true, and the XMPP server on which the current user is logged in supports
multi-user chat, then a list of rooms on that server will be fetched. multi-user chat, then a list of rooms on that server will be fetched in the
"Query for Groupchats" modal.
Not recommended for servers with lots of chatrooms. Not recommended for servers with lots of chatrooms.
@ -264,6 +265,10 @@ For each room on the server a query is made to fetch further details (e.g.
features, number of occupants etc.), so on servers with many rooms this features, number of occupants etc.), so on servers with many rooms this
option will create lots of extra connection traffic. option will create lots of extra connection traffic.
If the `muc_domain`_ is locked with the `locked_muc_domain`_ setting, then
rooms will automatically be fetched in the "Query for Groupchats" modal,
regardless of the value of this setting.
.. _`auto_login`: .. _`auto_login`:
auto_login auto_login
@ -869,6 +874,15 @@ For example, if ``locked_domain`` is set to ``example.org``, then the user
Additionally, only users registered on the ``example.org`` host can log in, no Additionally, only users registered on the ``example.org`` host can log in, no
other users are allowed to log in. other users are allowed to log in.
locked_muc_domain
-----------------
* Default: ``false``
This setting allows you to restrict the multi-user chat (MUC) domain to only the value
specified in `muc_domain`_.
message_archiving message_archiving
----------------- -----------------
@ -941,11 +955,16 @@ muc_domain
* Default: ``undefined`` * Default: ``undefined``
The MUC (multi-user chat) domain that should be used. By default Converse The default MUC (multi-user chat) domain that should be used.
will attempt to get the MUC domain from the XMPP host of the currently logged in
user.
This setting will override that. When setting this value, users can only enter the name when opening a new MUC,
and don't have to add the whole address (i.e. including the domain part).
Users can however still enter the domain and they can still open MUCs with
other domains.
If you want to restrict MUCs to only this domain, then set `locked_domain`_ to
``true``.
muc_history_max_stanzas muc_history_max_stanzas
----------------------- -----------------------

View File

@ -3958,13 +3958,19 @@
async function (done, _converse) { async function (done, _converse) {
test_utils.openControlBox(); test_utils.openControlBox();
_converse.emit('rosterContactsFetched'); await test_utils.waitForRoster(_converse, 'current', 0);
const roomspanel = _converse.chatboxviews.get('controlbox').roomspanel; const roomspanel = _converse.chatboxviews.get('controlbox').roomspanel;
roomspanel.el.querySelector('.show-add-muc-modal').click(); roomspanel.el.querySelector('.show-add-muc-modal').click();
test_utils.closeControlBox(_converse); test_utils.closeControlBox(_converse);
const modal = roomspanel.add_room_modal; const modal = roomspanel.add_room_modal;
await test_utils.waitUntil(() => u.isVisible(modal.el), 1000) await test_utils.waitUntil(() => u.isVisible(modal.el), 1000)
let label_name = modal.el.querySelector('label[for="chatroom"]');
expect(label_name.textContent).toBe('Groupchat address:');
let name_input = modal.el.querySelector('input[name="chatroom"]');
expect(name_input.placeholder).toBe('name@conference.example.org');
expect(modal.el.querySelector('.modal-title').textContent).toBe('Enter a new Groupchat'); expect(modal.el.querySelector('.modal-title').textContent).toBe('Enter a new Groupchat');
spyOn(_converse.ChatRoom.prototype, 'getRoomFeatures').and.callFake(() => Promise.resolve()); spyOn(_converse.ChatRoom.prototype, 'getRoomFeatures').and.callFake(() => Promise.resolve());
roomspanel.delegateEvents(); // We need to rebind all events otherwise our spy won't be called roomspanel.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
@ -3972,6 +3978,83 @@
modal.el.querySelector('form input[type="submit"]').click(); modal.el.querySelector('form input[type="submit"]').click();
await test_utils.waitUntil(() => _converse.chatboxes.length); await test_utils.waitUntil(() => _converse.chatboxes.length);
await test_utils.waitUntil(() => sizzle('.chatroom', _converse.el).filter(u.isVisible).length === 1); await test_utils.waitUntil(() => sizzle('.chatroom', _converse.el).filter(u.isVisible).length === 1);
roomspanel.model.set('muc_domain', 'muc.example.org');
roomspanel.el.querySelector('.show-add-muc-modal').click();
label_name = modal.el.querySelector('label[for="chatroom"]');
expect(label_name.textContent).toBe('Groupchat address:');
name_input = modal.el.querySelector('input[name="chatroom"]');
expect(name_input.placeholder).toBe('name@muc.example.org');
done();
}));
it("doesn't require the domain when muc_domain is set",
mock.initConverse(
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {'muc_domain': 'muc.example.org'},
async function (done, _converse) {
test_utils.openControlBox();
const roomspanel = _converse.chatboxviews.get('controlbox').roomspanel;
roomspanel.el.querySelector('.show-add-muc-modal').click();
const modal = roomspanel.add_room_modal;
await test_utils.waitUntil(() => u.isVisible(modal.el), 1000)
expect(modal.el.querySelector('.modal-title').textContent).toBe('Enter a new Groupchat');
spyOn(_converse.ChatRoom.prototype, 'getRoomFeatures').and.callFake(() => Promise.resolve());
roomspanel.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
const label_name = modal.el.querySelector('label[for="chatroom"]');
expect(label_name.textContent).toBe('Groupchat name:');
let name_input = modal.el.querySelector('input[name="chatroom"]');
expect(name_input.placeholder).toBe('name@muc.example.org');
name_input.value = 'lounge';
modal.el.querySelector('form input[type="submit"]').click();
await test_utils.waitUntil(() => _converse.chatboxes.length);
await test_utils.waitUntil(() => sizzle('.chatroom', _converse.el).filter(u.isVisible).length === 1);
expect(_.includes(_converse.chatboxes.models.map(m => m.get('id')), 'lounge@muc.example.org')).toBe(true);
// However, you can still open MUCs with different domains
roomspanel.el.querySelector('.show-add-muc-modal').click();
await test_utils.waitUntil(() => u.isVisible(modal.el), 1000);
name_input = modal.el.querySelector('input[name="chatroom"]');
name_input.value = 'lounge@conference.example.org';
modal.el.querySelector('form input[type="submit"]').click();
await test_utils.waitUntil(() => _converse.chatboxes.models.filter(c => c.get('type') === 'chatroom').length === 2);
await test_utils.waitUntil(() => sizzle('.chatroom', _converse.el).filter(u.isVisible).length === 2);
expect(_.includes(_converse.chatboxes.models.map(m => m.get('id')), 'lounge@conference.example.org')).toBe(true);
done();
}));
it("only uses the muc_domain is locked_muc_domain is true",
mock.initConverse(
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {'muc_domain': 'muc.example.org', 'locked_muc_domain': true},
async function (done, _converse) {
test_utils.openControlBox();
const roomspanel = _converse.chatboxviews.get('controlbox').roomspanel;
roomspanel.el.querySelector('.show-add-muc-modal').click();
const modal = roomspanel.add_room_modal;
await test_utils.waitUntil(() => u.isVisible(modal.el), 1000)
expect(modal.el.querySelector('.modal-title').textContent).toBe('Enter a new Groupchat');
spyOn(_converse.ChatRoom.prototype, 'getRoomFeatures').and.callFake(() => Promise.resolve());
roomspanel.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
const label_name = modal.el.querySelector('label[for="chatroom"]');
expect(label_name.textContent).toBe('Groupchat name:');
let name_input = modal.el.querySelector('input[name="chatroom"]');
expect(name_input.placeholder).toBe('');
name_input.value = 'lounge';
modal.el.querySelector('form input[type="submit"]').click();
await test_utils.waitUntil(() => _converse.chatboxes.length);
await test_utils.waitUntil(() => sizzle('.chatroom', _converse.el).filter(u.isVisible).length === 1);
expect(_.includes(_converse.chatboxes.models.map(m => m.get('id')), 'lounge@muc.example.org')).toBe(true);
// However, you can still open MUCs with different domains
roomspanel.el.querySelector('.show-add-muc-modal').click();
await test_utils.waitUntil(() => u.isVisible(modal.el), 1000);
name_input = modal.el.querySelector('input[name="chatroom"]');
name_input.value = 'lounge@conference';
modal.el.querySelector('form input[type="submit"]').click();
await test_utils.waitUntil(() => _converse.chatboxes.models.filter(c => c.get('type') === 'chatroom').length === 2);
await test_utils.waitUntil(() => sizzle('.chatroom', _converse.el).filter(u.isVisible).length === 2);
expect(_.includes(_converse.chatboxes.models.map(m => m.get('id')), 'lounge\\40conference@muc.example.org')).toBe(true);
done(); done();
})); }));
}); });
@ -4002,7 +4085,9 @@
// See: http://xmpp.org/extensions/xep-0045.html#disco-rooms // See: http://xmpp.org/extensions/xep-0045.html#disco-rooms
expect(modal.el.querySelectorAll('.available-chatrooms li').length).toBe(0); expect(modal.el.querySelectorAll('.available-chatrooms li').length).toBe(0);
const input = modal.el.querySelector('input[name="server"]').value = 'chat.shakespear.lit'; const server_input = modal.el.querySelector('input[name="server"]');
expect(server_input.placeholder).toBe('conference.example.org');
const input = server_input.value = 'chat.shakespear.lit';
modal.el.querySelector('input[type="submit"]').click(); modal.el.querySelector('input[type="submit"]').click();
await test_utils.waitUntil(() => _converse.chatboxes.length); await test_utils.waitUntil(() => _converse.chatboxes.length);
expect(sent_stanza.toLocaleString()).toBe( expect(sent_stanza.toLocaleString()).toBe(
@ -4010,7 +4095,6 @@
`<query xmlns="http://jabber.org/protocol/disco#items"/>`+ `<query xmlns="http://jabber.org/protocol/disco#items"/>`+
`</iq>` `</iq>`
); );
const iq = $iq({ const iq = $iq({
from:'muc.localhost', from:'muc.localhost',
to:'dummy@localhost/pda', to:'dummy@localhost/pda',
@ -4029,13 +4113,19 @@
.c('item', { jid:'street@chat.shakespeare.lit', name:'A street'}).nodeTree; .c('item', { jid:'street@chat.shakespeare.lit', name:'A street'}).nodeTree;
_converse.connection._dataRecv(test_utils.createRequest(iq)); _converse.connection._dataRecv(test_utils.createRequest(iq));
await test_utils.waitUntil(() => modal.el.querySelectorAll('.available-chatrooms li').length === 5); await test_utils.waitUntil(() => modal.el.querySelectorAll('.available-chatrooms li').length === 11);
const rooms = modal.el.querySelectorAll('.available-chatrooms li'); const rooms = modal.el.querySelectorAll('.available-chatrooms li');
expect(rooms[0].textContent.trim()).toBe("Groupchats found:"); expect(rooms[0].textContent.trim()).toBe("Groupchats found:");
expect(rooms[1].textContent.trim()).toBe("A Lonely Heath"); expect(rooms[1].textContent.trim()).toBe("A Lonely Heath");
expect(rooms[2].textContent.trim()).toBe("A Dark Cave"); expect(rooms[2].textContent.trim()).toBe("A Dark Cave");
expect(rooms[3].textContent.trim()).toBe("The Palace"); expect(rooms[3].textContent.trim()).toBe("The Palace");
expect(rooms[4].textContent.trim()).toBe("Macbeth's Castle"); expect(rooms[4].textContent.trim()).toBe("Macbeth's Castle");
expect(rooms[5].textContent.trim()).toBe('Capulet\'s Orchard');
expect(rooms[6].textContent.trim()).toBe('Friar Laurence\'s cell');
expect(rooms[7].textContent.trim()).toBe('Hall in Capulet\'s house');
expect(rooms[8].textContent.trim()).toBe('Juliet\'s chamber');
expect(rooms[9].textContent.trim()).toBe('A public place');
expect(rooms[10].textContent.trim()).toBe('A street');
rooms[4].querySelector('.open-room').click(); rooms[4].querySelector('.open-room').click();
await test_utils.waitUntil(() => _converse.chatboxes.length > 1); await test_utils.waitUntil(() => _converse.chatboxes.length > 1);
@ -4044,6 +4134,71 @@
expect(view.el.querySelector('.chat-head-chatroom').textContent.trim()).toBe("Macbeth's Castle"); expect(view.el.querySelector('.chat-head-chatroom').textContent.trim()).toBe("Macbeth's Castle");
done(); done();
})); }));
it("is pre-filled with the muc_domain",
mock.initConverse(
null, ['rosterGroupsFetched', 'chatBoxesFetched'],
{'muc_domain': 'muc.example.org'},
async function (done, _converse) {
test_utils.openControlBox();
const roomspanel = _converse.chatboxviews.get('controlbox').roomspanel;
roomspanel.el.querySelector('.show-list-muc-modal').click();
test_utils.closeControlBox(_converse);
const modal = roomspanel.list_rooms_modal;
await test_utils.waitUntil(() => u.isVisible(modal.el), 1000);
const server_input = modal.el.querySelector('input[name="server"]');
expect(server_input.value).toBe('muc.example.org');
done();
}));
it("doesn't let you set the MUC domain if it's locked",
mock.initConverse(
null, ['rosterGroupsFetched', 'chatBoxesFetched'],
{'muc_domain': 'chat.shakespeare.lit', 'locked_muc_domain': true},
async function (done, _converse) {
test_utils.openControlBox();
const roomspanel = _converse.chatboxviews.get('controlbox').roomspanel;
roomspanel.el.querySelector('.show-list-muc-modal').click();
test_utils.closeControlBox(_converse);
const modal = roomspanel.list_rooms_modal;
await test_utils.waitUntil(() => u.isVisible(modal.el), 1000);
spyOn(_converse.ChatRoom.prototype, 'getRoomFeatures').and.callFake(() => Promise.resolve());
roomspanel.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
expect(modal.el.querySelector('input[name="server"]')).toBe(null);
expect(modal.el.querySelector('input[type="submit"]')).toBe(null);
await test_utils.waitUntil(() => _converse.chatboxes.length);
const sent_stanza = await test_utils.waitUntil(() =>
_converse.connection.sent_stanzas.filter(
s => sizzle(`query[xmlns="http://jabber.org/protocol/disco#items"]`, s).length).pop()
);
expect(Strophe.serialize(sent_stanza)).toBe(
`<iq from="dummy@localhost/resource" id="${sent_stanza.getAttribute('id')}" `+
`to="chat.shakespeare.lit" type="get" xmlns="jabber:client">`+
`<query xmlns="http://jabber.org/protocol/disco#items"/>`+
`</iq>`
);
const iq = $iq({
from:'muc.localhost',
to:'dummy@localhost/pda',
id: sent_stanza.getAttribute('id'),
type:'result'
}).c('query')
.c('item', { jid:'heath@chat.shakespeare.lit', name:'A Lonely Heath'}).up()
.c('item', { jid:'coven@chat.shakespeare.lit', name:'A Dark Cave'}).up()
.c('item', { jid:'forres@chat.shakespeare.lit', name:'The Palace'}).up()
_converse.connection._dataRecv(test_utils.createRequest(iq));
await test_utils.waitUntil(() => modal.el.querySelectorAll('.available-chatrooms li').length === 4);
const rooms = modal.el.querySelectorAll('.available-chatrooms li');
expect(rooms[0].textContent.trim()).toBe("Groupchats found:");
expect(rooms[1].textContent.trim()).toBe("A Lonely Heath");
expect(rooms[2].textContent.trim()).toBe("A Dark Cave");
expect(rooms[3].textContent.trim()).toBe("The Palace");
done();
}));
}); });
describe("The \"Groupchats\" section", function () { describe("The \"Groupchats\" section", function () {
@ -4052,9 +4207,6 @@
mock.initConverse( mock.initConverse(
null, ['rosterGroupsFetched'], {'allow_bookmarks': false}, null, ['rosterGroupsFetched'], {'allow_bookmarks': false},
async function (done, _converse) { async function (done, _converse) {
// XXX: we set `allow_bookmarks` to false, so that the groupchats
// list gets rendered. Otherwise we would have to mock
// the bookmark stanza exchange.
test_utils.openControlBox(); test_utils.openControlBox();
const roomspanel = _converse.chatboxviews.get('controlbox').roomspanel; const roomspanel = _converse.chatboxviews.get('controlbox').roomspanel;

View File

@ -103,6 +103,8 @@ converse.plugins.add('converse-muc-views', {
_converse.api.settings.update({ _converse.api.settings.update({
'auto_list_rooms': false, 'auto_list_rooms': false,
'muc_disable_moderator_commands': false, 'muc_disable_moderator_commands': false,
'muc_domain': undefined,
'locked_muc_domain': undefined,
'muc_show_join_leave': true, 'muc_show_join_leave': true,
'roomconfig_whitelist': [], 'roomconfig_whitelist': [],
'visible_toolbar_buttons': { 'visible_toolbar_buttons': {
@ -110,6 +112,10 @@ converse.plugins.add('converse-muc-views', {
} }
}); });
if (_converse.locked_muc_domain && !_.isString(_converse.muc_domain)) {
throw new Error("Config Error: it makes no sense to set locked_muc_domain "+
"to true when muc_domain is not set");
}
function ___ (str) { function ___ (str) {
/* This is part of a hack to get gettext to scan strings to be /* This is part of a hack to get gettext to scan strings to be
@ -266,22 +272,32 @@ converse.plugins.add('converse-muc-views', {
initialize () { initialize () {
_converse.BootstrapModal.prototype.initialize.apply(this, arguments); _converse.BootstrapModal.prototype.initialize.apply(this, arguments);
if (_converse.muc_domain && !this.model.get('muc_domain')) {
this.model.save('muc_domain', _converse.muc_domain);
}
this.model.on('change:muc_domain', this.onDomainChange, this); this.model.on('change:muc_domain', this.onDomainChange, this);
}, },
toHTML () { toHTML () {
const muc_domain = this.model.get('muc_domain') || _converse.muc_domain;
return tpl_list_chatrooms_modal(_.extend(this.model.toJSON(), { return tpl_list_chatrooms_modal(_.extend(this.model.toJSON(), {
'heading_list_chatrooms': __('Query for Groupchats'), 'heading_list_chatrooms': __('Query for Groupchats'),
'label_server_address': __('Server address'), 'label_server_address': __('Server address'),
'label_query': __('Show groupchats'), 'label_query': __('Show groupchats'),
'server_placeholder': __('conference.example.org') 'show_form': !_converse.locked_muc_domain,
'server_placeholder': muc_domain ? muc_domain : __('conference.example.org')
})); }));
}, },
afterRender () { afterRender () {
this.el.addEventListener('shown.bs.modal', () => { if (_converse.locked_muc_domain) {
this.el.querySelector('input[name="server"]').focus(); this.updateRoomsList();
}, false); } else {
this.el.addEventListener('shown.bs.modal',
() => this.el.querySelector('input[name="server"]').focus(),
false
);
}
}, },
openRoom (ev) { openRoom (ev) {
@ -384,12 +400,22 @@ converse.plugins.add('converse-muc-views', {
'submit form.add-chatroom': 'openChatRoom' 'submit form.add-chatroom': 'openChatRoom'
}, },
initialize () {
_converse.BootstrapModal.prototype.initialize.apply(this, arguments);
this.model.on('change:muc_domain', this.render, this);
},
toHTML () { toHTML () {
let placeholder = '';
if (!_converse.locked_muc_domain) {
const muc_domain = this.model.get('muc_domain') || _converse.muc_domain;
placeholder = muc_domain ? `name@${muc_domain}` : __('name@conference.example.org');
}
return tpl_add_chatroom_modal(_.extend(this.model.toJSON(), { return tpl_add_chatroom_modal(_.extend(this.model.toJSON(), {
'heading_new_chatroom': __('Enter a new Groupchat'), 'heading_new_chatroom': __('Enter a new Groupchat'),
'label_room_address': __('Groupchat address'), 'label_room_address': _converse.muc_domain ? __('Groupchat name') : __('Groupchat address'),
'label_nickname': __('Optional nickname'), 'label_nickname': __('Optional nickname'),
'chatroom_placeholder': __('name@conference.example.org'), 'chatroom_placeholder': placeholder,
'label_join': __('Join'), 'label_join': __('Join'),
})); }));
}, },
@ -417,7 +443,13 @@ converse.plugins.add('converse-muc-views', {
// Make sure defaults apply if no nick is provided. // Make sure defaults apply if no nick is provided.
data.nick = undefined; data.nick = undefined;
} }
_converse.api.rooms.open(data.jid, data); let jid;
if (_converse.locked_muc_domain || (_converse.muc_domain && !u.isValidJID(data.jid))) {
jid = `${Strophe.escapeNode(data.jid)}@${_converse.muc_domain}`;
} else {
jid = data.jid
}
_converse.api.rooms.open(jid, _.extend(data, {jid}));
this.modal.hide(); this.modal.hide();
ev.target.reset(); ev.target.reset();
} }

View File

@ -118,7 +118,6 @@ converse.plugins.add('converse-muc', {
auto_join_on_invite: false, auto_join_on_invite: false,
auto_join_rooms: [], auto_join_rooms: [],
auto_register_muc_nickname: false, auto_register_muc_nickname: false,
muc_domain: undefined,
muc_history_max_stanzas: undefined, muc_history_max_stanzas: undefined,
muc_instant_rooms: true, muc_instant_rooms: true,
muc_nickname_from_jid: false muc_nickname_from_jid: false

View File

@ -9,13 +9,15 @@
</button> </button>
</div> </div>
<div class="modal-body d-flex flex-column"> <div class="modal-body d-flex flex-column">
{[ if (o.show_form) { ]}
<form class="converse-form list-chatrooms"> <form class="converse-form list-chatrooms">
<div class="form-group"> <div class="form-group">
<label for="chatroom">{{{o.label_server_address}}}:</label> <label for="chatroom">{{{o.label_server_address}}}:</label>
<input type="text" value="{{{o.muc_domain}}}" required="required" name="server" class="form-control" placeholder="{{{o.server_placeholder}}}"/> <input type="text" value="{{{o.muc_domain}}}" required="required" name="server" class="form-control" placeholder="{{{o.server_placeholder}}}"/>
</div> </div>
<input type="submit" class="btn btn-primary" name="join" value="{{{o.label_query}}}"/> <input type="submit" class="btn btn-primary" name="list" value="{{{o.label_query}}}"/>
</form> </form>
{[ } ]}
<ul class="available-chatrooms list-group"></ul> <ul class="available-chatrooms list-group"></ul>
</div> </div>
</div> </div>