MUC: Use converse-disco to query for room features

By doing so we create a new DiscoEntity for the room, which allows us to
query for features via the disco API.

We also avoid duplication of functionality between converse-muc and
converse-disco
This commit is contained in:
JC Brand 2018-09-12 12:32:50 +02:00
parent 197451db54
commit 6457bc765a
3 changed files with 68 additions and 66 deletions

View File

@ -1141,9 +1141,8 @@
form_el.addEventListener('submit',
(ev) => {
ev.preventDefault();
this.model.saveConfiguration(ev.target).then(
this.model.getRoomFeatures.bind(this.model)
);
this.model.saveConfiguration(ev.target)
.then(() => this.model.refreshRoomFeatures());
this.closeForm();
},
false

View File

@ -403,22 +403,6 @@
};
},
getRoomFeatures () {
/* Fetch the groupchat disco info, parse it and then save it.
*/
// XXX: Currently we store disco info on the room itself.
// A better design would probably be to create a
// DiscoEntity for this room, and then to let
// converse-disco manage all disco-related tasks.
// Then we can also use _converse.api.disco.supports.
return _converse.api.disco.info(this.get('jid'), null)
.then(stanza => this.parseRoomFeatures(stanza))
.catch(err => {
_converse.log("Could not parse the groupchat features", Strophe.LogLevel.WARN);
_converse.log(err, Strophe.LogLevel.WARN);
});
},
getRoomJIDAndNick (nick) {
/* Utility method to construct the JID for the current user
* as occupant of the groupchat.
@ -499,43 +483,34 @@
});
},
parseRoomFeatures (iq) {
/* Parses an IQ stanza containing the groupchat's features.
*
* See http://xmpp.org/extensions/xep-0045.html#disco-roominfo
*
* <identity
* category='conference'
* name='A Dark Cave'
* type='text'/>
* <feature var='http://jabber.org/protocol/muc'/>
* <feature var='muc_passwordprotected'/>
* <feature var='muc_hidden'/>
* <feature var='muc_temporary'/>
* <feature var='muc_open'/>
* <feature var='muc_unmoderated'/>
* <feature var='muc_nonanonymous'/>
* <feature var='urn:xmpp:mam:0'/>
*/
const features = {
'features_fetched': moment().format(),
'name': iq.querySelector('identity').getAttribute('name')
refreshRoomFeatures () {
const entity = _converse.disco_entities.get(this.get('jid'));
if (entity) {
entity.destroy();
}
_.each(iq.querySelectorAll('feature'), function (field) {
const fieldname = field.getAttribute('var');
return this.getRoomFeatures();
},
async getRoomFeatures () {
const features = await _converse.api.disco.getFeatures(this.get('jid')),
fields = await _converse.api.disco.getFields(this.get('jid')),
identity = await _converse.api.disco.getIdentity('conference', 'text', this.get('jid')),
attrs = {
'features_fetched': moment().format(),
'name': identity && identity.get('name')
};
features.each(feature => {
const fieldname = feature.get('var');
if (!fieldname.startsWith('muc_')) {
if (fieldname === Strophe.NS.MAM) {
features.mam_enabled = true;
attrs.mam_enabled = true;
}
return;
}
features[fieldname.replace('muc_', '')] = true;
attrs[fieldname.replace('muc_', '')] = true;
});
const desc_field = iq.querySelector('field[var="muc#roominfo_description"] value');
if (!_.isNull(desc_field)) {
features.description = desc_field.textContent;
}
this.save(features);
attrs.description = _.get(fields.findWhere({'var': "muc#roominfo_description"}), 'attributes.value');
this.save(attrs);
},
requestMemberList (affiliation) {
@ -969,7 +944,7 @@
if (configuration_changed || logging_enabled || logging_disabled ||
room_no_longer_anon || room_now_semi_anon || room_now_fully_anon) {
this.getRoomFeatures();
this.refreshRoomFeatures();
}
},
@ -1053,10 +1028,10 @@
const locked_room = pres.querySelector("status[code='201']");
if (locked_room) {
if (this.get('auto_configure')) {
this.autoConfigureChatRoom().then(this.getRoomFeatures.bind(this));
this.autoConfigureChatRoom().then(() => this.refreshRoomFeatures());
} else if (_converse.muc_instant_rooms) {
// Accept default configuration
this.saveConfiguration().then(this.getRoomFeatures.bind(this));
this.saveConfiguration().then(() => this.getRoomFeatures());
} else {
this.trigger('configurationNeeded');
return; // We haven't yet entered the groupchat, so bail here.
@ -1068,7 +1043,7 @@
// otherwise the features would have been fetched in
// the "initialize" method already.
if (this.get('affiliation') === 'owner' && this.get('auto_configure')) {
this.autoConfigureChatRoom().then(this.getRoomFeatures.bind(this));
this.autoConfigureChatRoom().then(() => this.refreshRoomFeatures());
} else {
this.getRoomFeatures();
}

View File

@ -127,19 +127,44 @@
utils.openAndEnterChatRoom = function (_converse, room, server, nick) {
let last_stanza, view;
const room_jid = `${room}@${server}`.toLowerCase();
return _converse.api.rooms.open(`${room}@${server}`).then(() => {
view = _converse.chatboxviews.get((room+'@'+server).toLowerCase());
// We pretend this is a new room, so no disco info is returned.
last_stanza = _.last(_converse.connection.IQ_stanzas).nodeTree;
const IQ_id = last_stanza.getAttribute('id');
return _converse.api.rooms.open(room_jid).then(() => {
view = _converse.chatboxviews.get(room_jid);
return utils.waitUntil(() => _.get(_.filter(
_converse.connection.IQ_stanzas,
iq => iq.nodeTree.querySelector(
`iq[to="coven@chat.shakespeare.lit"] query[xmlns="http://jabber.org/protocol/disco#info"]`
)
).pop(), 'nodeTree'));
}).then(stanza => {
const features_stanza = $iq({
'from': room+'@'+server,
'id': IQ_id,
'to': nick+'@'+server,
'type': 'error'
}).c('error', {'type': 'cancel'})
.c('item-not-found', {'xmlns': "urn:ietf:params:xml:ns:xmpp-stanzas"});
'from': room_jid,
'id': stanza.getAttribute('id'),
'to': 'dummy@localhost/desktop',
'type': 'result'
})
.c('query', { 'xmlns': 'http://jabber.org/protocol/disco#info'})
.c('identity', {
'category': 'conference',
'name': 'A Dark Cave',
'type': 'text'
}).up()
.c('feature', {'var': 'http://jabber.org/protocol/muc'}).up()
.c('feature', {'var': 'jabber:iq:register'}).up()
.c('feature', {'var': 'muc_passwordprotected'}).up()
.c('feature', {'var': 'muc_hidden'}).up()
.c('feature', {'var': 'muc_temporary'}).up()
.c('feature', {'var': 'muc_open'}).up()
.c('feature', {'var': 'muc_unmoderated'}).up()
.c('feature', {'var': 'muc_nonanonymous'})
.c('x', { 'xmlns':'jabber:x:data', 'type':'result'})
.c('field', {'var':'FORM_TYPE', 'type':'hidden'})
.c('value').t('http://jabber.org/protocol/muc#roominfo').up().up()
.c('field', {'type':'text-single', 'var':'muc#roominfo_description', 'label':'Description'})
.c('value').t('This is the description').up().up()
.c('field', {'type':'text-single', 'var':'muc#roominfo_occupants', 'label':'Number of occupants'})
.c('value').t(0);
_converse.connection._dataRecv(utils.createRequest(features_stanza));
return utils.waitUntil(() => {
return _.filter(
@ -179,8 +204,11 @@
}).up()
.c('status').attrs({code:'110'});
_converse.connection._dataRecv(utils.createRequest(presence));
return utils.waitUntil(() => view.model.get('connection_status') === converse.ROOMSTATUS.ENTERED);
}).catch(_.partial(console.error, _));
return utils.waitUntil(() => (view.model.get('connection_status') === converse.ROOMSTATUS.ENTERED));
}).catch(e => {
console.error(e);
throw e;
});
};
utils.clearBrowserStorage = function () {