Merge branch 'master' into async-await
This commit is contained in:
commit
55fce912df
|
@ -1,10 +1,11 @@
|
|||
# Changelog
|
||||
|
||||
## 4.1.0 (Unreleased)
|
||||
## 4.0.4 (Unreleased)
|
||||
|
||||
- Use [Lerna](https://lernajs.io/) to create the @converse/headless package
|
||||
- Use ES2015 modules instead of UMD.
|
||||
- #1257: Prefer 'probably' over 'maybe' when evaluating audio play support.
|
||||
- #1257 Prefer 'probably' over 'maybe' when evaluating audio play support.
|
||||
- #1261 File upload not working
|
||||
|
||||
## 4.0.3 (2018-10-22)
|
||||
|
||||
|
|
416
dist/converse.js
vendored
416
dist/converse.js
vendored
|
@ -617,7 +617,7 @@ module.exports = Awesomplete;
|
|||
|
||||
/**
|
||||
* Backbone localStorage and sessionStorage Adapter
|
||||
* Version 0.0.3
|
||||
* Version 0.0.4
|
||||
*
|
||||
* https://github.com/jcbrand/Backbone.browserStorage
|
||||
*/
|
||||
|
@ -664,11 +664,11 @@ function _browserStorage (name, serializer, type) {
|
|||
this.name = name;
|
||||
this.serializer = serializer || {
|
||||
serialize: function(item) {
|
||||
return _.isObject(item) ? JSON.stringify(item) : item;
|
||||
return _.isObject(item) ? JSON.stringify(item) : item;
|
||||
},
|
||||
// fix for "illegal access" error on Android when JSON.parse is passed null
|
||||
deserialize: function (data) {
|
||||
return data && JSON.parse(data);
|
||||
return data && JSON.parse(data);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -704,10 +704,10 @@ var _extension = {
|
|||
|
||||
// Add a model, giving it a (hopefully)-unique GUID, if it doesn't already
|
||||
// have an id of it's own.
|
||||
create: function(model) {
|
||||
create: function(model, options) {
|
||||
if (!model.id) {
|
||||
model.id = guid();
|
||||
model.set(model.idAttribute, model.id);
|
||||
model.set(model.idAttribute, model.id, options);
|
||||
}
|
||||
this.store.setItem(this._itemName(model.id), this.serializer.serialize(model));
|
||||
this.records.push(model.id.toString());
|
||||
|
@ -815,13 +815,13 @@ Backbone.BrowserStorage.sync = Backbone.localSync = function(method, model, opti
|
|||
resp = model.id !== undefined ? store.find(model) : store.findAll();
|
||||
break;
|
||||
case "create":
|
||||
resp = store.create(model);
|
||||
resp = store.create(model, options);
|
||||
break;
|
||||
case "update":
|
||||
resp = store.update(model);
|
||||
resp = store.update(model, options);
|
||||
break;
|
||||
case "delete":
|
||||
resp = store.destroy(model);
|
||||
resp = store.destroy(model, options);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -834,7 +834,7 @@ Backbone.BrowserStorage.sync = Backbone.localSync = function(method, model, opti
|
|||
|
||||
if (resp) {
|
||||
if (options && options.success) {
|
||||
options.success(resp);
|
||||
options.success(resp, options);
|
||||
}
|
||||
if (syncDfd) {
|
||||
syncDfd.resolve(resp);
|
||||
|
@ -59267,6 +59267,10 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins
|
|||
prev_msg_date = _.isNull(prev_msg_el) ? null : prev_msg_el.getAttribute('data-isodate'),
|
||||
next_msg_date = next_msg_el.getAttribute('data-isodate');
|
||||
|
||||
if (_.isNull(prev_msg_date) && _.isNull(next_msg_date)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_.isNull(prev_msg_date) || moment(next_msg_date).isAfter(prev_msg_date, 'day')) {
|
||||
const day_date = moment(next_msg_date).startOf('day');
|
||||
next_msg_el.insertAdjacentHTML('beforeBegin', templates_new_day_html__WEBPACK_IMPORTED_MODULE_13___default()({
|
||||
|
@ -59462,6 +59466,13 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins
|
|||
});
|
||||
await view.render();
|
||||
this.clearChatStateNotification(message);
|
||||
|
||||
if (!view.el.innerHTML) {
|
||||
// An "inactive" CSN message (for example) will have an
|
||||
// empty body. No need to then continue.
|
||||
return _converse.log("Not inserting a message with empty element", Strophe.LogLevel.INFO);
|
||||
}
|
||||
|
||||
this.insertMessage(view);
|
||||
this.insertDayIndicator(view.el);
|
||||
this.setScrollPosition(view.el);
|
||||
|
@ -61611,6 +61622,12 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
|
|||
if (this.model.isOnlyChatStateNotification()) {
|
||||
this.renderChatStateNotification();
|
||||
} else if (this.model.get('file') && !this.model.get('oob_url')) {
|
||||
if (!this.model.file) {
|
||||
_converse.log("Attempted to render a file upload message with no file data");
|
||||
|
||||
return this.el;
|
||||
}
|
||||
|
||||
this.renderFileUploadProgresBar();
|
||||
} else if (this.model.get('type') === 'error') {
|
||||
this.renderErrorMessage();
|
||||
|
@ -61751,7 +61768,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
|
|||
|
||||
renderFileUploadProgresBar() {
|
||||
const msg = utils_emoji__WEBPACK_IMPORTED_MODULE_8__["default"].stringToElement(templates_file_progress_html__WEBPACK_IMPORTED_MODULE_4___default()(_.extend(this.model.toJSON(), {
|
||||
'filesize': filesize__WEBPACK_IMPORTED_MODULE_1___default()(this.model.get('file').size)
|
||||
'filesize': filesize__WEBPACK_IMPORTED_MODULE_1___default()(this.model.file.size)
|
||||
})));
|
||||
this.replaceElement(msg);
|
||||
this.renderAvatar();
|
||||
|
@ -63011,13 +63028,15 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_3__["default"].plugins
|
|||
updateRoomsList() {
|
||||
/* Send an IQ stanza to the server asking for all groupchats
|
||||
*/
|
||||
_converse.connection.sendIQ($iq({
|
||||
const iq = $iq({
|
||||
'to': this.model.get('muc_domain'),
|
||||
'from': _converse.connection.jid,
|
||||
'type': "get"
|
||||
}).c("query", {
|
||||
xmlns: Strophe.NS.DISCO_ITEMS
|
||||
}), this.onRoomsFound.bind(this), this.informNoRoomsFound.bind(this), 5000);
|
||||
});
|
||||
|
||||
_converse.api.sendIQ(iq).then(iq => this.onRoomsFound(iq)).catch(iq => this.informNoRoomsFound());
|
||||
},
|
||||
|
||||
showRooms(ev) {
|
||||
|
@ -63495,7 +63514,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_3__["default"].plugins
|
|||
iq.c("reason", reason);
|
||||
}
|
||||
|
||||
return _converse.connection.sendIQ(iq, onSuccess, onError);
|
||||
return _converse.api.sendIQ(iq).then(onSuccess).catch(onError);
|
||||
},
|
||||
|
||||
verifyRoles(roles) {
|
||||
|
@ -63644,7 +63663,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_3__["default"].plugins
|
|||
break;
|
||||
}
|
||||
|
||||
_converse.connection.send($pres({
|
||||
_converse.api.send($pres({
|
||||
from: _converse.connection.jid,
|
||||
to: this.model.getRoomJIDAndNick(match[2]),
|
||||
id: _converse.connection.getUniqueId()
|
||||
|
@ -63696,7 +63715,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_3__["default"].plugins
|
|||
case 'topic':
|
||||
case 'subject':
|
||||
// TODO: should be done via API call to _converse.api.rooms
|
||||
_converse.connection.send($msg({
|
||||
_converse.api.send($msg({
|
||||
to: this.model.get('jid'),
|
||||
from: _converse.connection.jid,
|
||||
type: "groupchat"
|
||||
|
@ -70508,10 +70527,6 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha
|
|||
|
||||
if (this.get('file')) {
|
||||
this.on('change:put', this.uploadFile, this);
|
||||
|
||||
if (!_.includes([_converse.SUCCESS, _converse.FAILURE], this.get('upload'))) {
|
||||
this.getRequestSlotURL();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isOnlyChatStateNotification()) {
|
||||
|
@ -70594,21 +70609,21 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha
|
|||
*
|
||||
* https://xmpp.org/extensions/xep-0363.html#request
|
||||
*/
|
||||
const file = this.get('file');
|
||||
return new Promise((resolve, reject) => {
|
||||
const iq = _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].env.$iq({
|
||||
'from': _converse.jid,
|
||||
'to': this.get('slot_request_url'),
|
||||
'type': 'get'
|
||||
}).c('request', {
|
||||
'xmlns': Strophe.NS.HTTPUPLOAD,
|
||||
'filename': file.name,
|
||||
'size': file.size,
|
||||
'content-type': file.type
|
||||
});
|
||||
if (_.isNil(this.file)) {
|
||||
return Promise.reject(new Error("file is undefined"));
|
||||
}
|
||||
|
||||
_converse.connection.sendIQ(iq, resolve, reject);
|
||||
const iq = _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].env.$iq({
|
||||
'from': _converse.jid,
|
||||
'to': this.get('slot_request_url'),
|
||||
'type': 'get'
|
||||
}).c('request', {
|
||||
'xmlns': Strophe.NS.HTTPUPLOAD,
|
||||
'filename': this.file.name,
|
||||
'size': this.file.size,
|
||||
'content-type': this.file.type
|
||||
});
|
||||
return _converse.api.sendIQ(iq);
|
||||
},
|
||||
|
||||
getRequestSlotURL() {
|
||||
|
@ -70832,11 +70847,11 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha
|
|||
},
|
||||
|
||||
sendMessageStanza(stanza) {
|
||||
_converse.connection.send(stanza);
|
||||
_converse.api.send(stanza);
|
||||
|
||||
if (_converse.forward_messages) {
|
||||
// Forward the message, so that other connected resources are also aware of it.
|
||||
_converse.connection.send($msg({
|
||||
_converse.api.send($msg({
|
||||
'to': _converse.bare_jid,
|
||||
'type': this.get('message_type')
|
||||
}).c('forwarded', {
|
||||
|
@ -70894,7 +70909,7 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha
|
|||
* See XEP-0085 Chat State Notifications.
|
||||
*/
|
||||
if (_converse.send_chat_state_notifications) {
|
||||
_converse.connection.send($msg({
|
||||
_converse.api.send($msg({
|
||||
'to': this.get('jid'),
|
||||
'type': 'chat'
|
||||
}).c(this.get('chat_state'), {
|
||||
|
@ -70907,41 +70922,45 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-cha
|
|||
}
|
||||
},
|
||||
|
||||
sendFiles(files) {
|
||||
_converse.api.disco.supports(Strophe.NS.HTTPUPLOAD, _converse.domain).then(result => {
|
||||
const item = result.pop(),
|
||||
data = item.dataforms.where({
|
||||
'FORM_TYPE': {
|
||||
'value': Strophe.NS.HTTPUPLOAD,
|
||||
'type': "hidden"
|
||||
}
|
||||
}).pop(),
|
||||
max_file_size = window.parseInt(_.get(data, 'attributes.max-file-size.value')),
|
||||
slot_request_url = _.get(item, 'id');
|
||||
async sendFiles(files) {
|
||||
const result = await _converse.api.disco.supports(Strophe.NS.HTTPUPLOAD, _converse.domain),
|
||||
item = result.pop(),
|
||||
data = item.dataforms.where({
|
||||
'FORM_TYPE': {
|
||||
'value': Strophe.NS.HTTPUPLOAD,
|
||||
'type': "hidden"
|
||||
}
|
||||
}).pop(),
|
||||
max_file_size = window.parseInt(_.get(data, 'attributes.max-file-size.value')),
|
||||
slot_request_url = _.get(item, 'id');
|
||||
|
||||
if (!slot_request_url) {
|
||||
this.messages.create({
|
||||
'message': __("Sorry, looks like file upload is not supported by your server."),
|
||||
if (!slot_request_url) {
|
||||
this.messages.create({
|
||||
'message': __("Sorry, looks like file upload is not supported by your server."),
|
||||
'type': 'error'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
_.each(files, file => {
|
||||
if (!window.isNaN(max_file_size) && window.parseInt(file.size) > max_file_size) {
|
||||
return this.messages.create({
|
||||
'message': __('The size of your file, %1$s, exceeds the maximum allowed by your server, which is %2$s.', file.name, filesize__WEBPACK_IMPORTED_MODULE_3___default()(max_file_size)),
|
||||
'type': 'error'
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
const message = this.messages.create(_.extend(this.getOutgoingMessageAttributes(), {
|
||||
'file': file,
|
||||
'progress': 0,
|
||||
'slot_request_url': slot_request_url
|
||||
}), {
|
||||
'silent': true
|
||||
});
|
||||
message.file = file;
|
||||
this.messages.trigger('add', message);
|
||||
message.getRequestSlotURL();
|
||||
}
|
||||
|
||||
_.each(files, file => {
|
||||
if (!window.isNaN(max_file_size) && window.parseInt(file.size) > max_file_size) {
|
||||
return this.messages.create({
|
||||
'message': __('The size of your file, %1$s, exceeds the maximum allowed by your server, which is %2$s.', file.name, filesize__WEBPACK_IMPORTED_MODULE_3___default()(max_file_size)),
|
||||
'type': 'error'
|
||||
});
|
||||
} else {
|
||||
this.messages.create(_.extend(this.getOutgoingMessageAttributes(), {
|
||||
'file': file,
|
||||
'progress': 0,
|
||||
'slot_request_url': slot_request_url
|
||||
}));
|
||||
}
|
||||
});
|
||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
||||
});
|
||||
},
|
||||
|
||||
getReferencesFromStanza(stanza) {
|
||||
|
@ -71911,7 +71930,7 @@ _converse.initialize = function (settings, callback) {
|
|||
|
||||
/* Send out a Chat Status Notification (XEP-0352) */
|
||||
// XXX if (converse.features[Strophe.NS.CSI] || true) {
|
||||
_converse.connection.send(Object(strophe_js__WEBPACK_IMPORTED_MODULE_0__["$build"])(stat, {
|
||||
_converse.api.send(Object(strophe_js__WEBPACK_IMPORTED_MODULE_0__["$build"])(stat, {
|
||||
xmlns: strophe_js__WEBPACK_IMPORTED_MODULE_0__["Strophe"].NS.CSI
|
||||
}));
|
||||
|
||||
|
@ -72019,7 +72038,7 @@ _converse.initialize = function (settings, callback) {
|
|||
pres.c("status").t(message);
|
||||
}
|
||||
|
||||
_converse.connection.send(pres);
|
||||
_converse.api.send(pres);
|
||||
};
|
||||
|
||||
this.reconnect = _lodash_noconflict__WEBPACK_IMPORTED_MODULE_3___default.a.debounce(function () {
|
||||
|
@ -72480,7 +72499,7 @@ _converse.initialize = function (settings, callback) {
|
|||
},
|
||||
|
||||
sendPresence(type, status_message) {
|
||||
_converse.connection.send(this.constructPresence(type, status_message));
|
||||
_converse.api.send(this.constructPresence(type, status_message));
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -73234,6 +73253,8 @@ _converse.api = {
|
|||
*/
|
||||
'send'(stanza) {
|
||||
_converse.connection.send(stanza);
|
||||
|
||||
_converse.emit('send', stanza);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -73243,9 +73264,11 @@ _converse.api = {
|
|||
* @returns {Promise} A promise which resolves when we receive a `result` stanza
|
||||
* or is rejected when we receive an `error` stanza.
|
||||
*/
|
||||
'sendIQ'(stanza) {
|
||||
'sendIQ'(stanza, timeout) {
|
||||
return new es6_promise_dist_es6_promise_auto__WEBPACK_IMPORTED_MODULE_2___default.a((resolve, reject) => {
|
||||
_converse.connection.sendIQ(stanza, resolve, reject, _converse.IQ_TIMEOUT);
|
||||
_converse.connection.sendIQ(stanza, resolve, reject, timeout || _converse.IQ_TIMEOUT);
|
||||
|
||||
_converse.emit('send', stanza);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -73759,7 +73782,7 @@ _converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins.add('converse-dis
|
|||
}).up();
|
||||
});
|
||||
|
||||
_converse.connection.send(iqresult.tree());
|
||||
_converse.api.send(iqresult.tree());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -74274,7 +74297,7 @@ function queryForArchivedMessages(_converse, options, callback, errback) {
|
|||
return true;
|
||||
}, Strophe.NS.MAM);
|
||||
|
||||
_converse.connection.sendIQ(stanza, function (iq) {
|
||||
_converse.api.sendIQ(stanza, _converse.message_archiving_timeout).then(iq => {
|
||||
_converse.connection.deleteHandler(message_handler);
|
||||
|
||||
if (_.isFunction(callback)) {
|
||||
|
@ -74291,13 +74314,15 @@ function queryForArchivedMessages(_converse, options, callback, errback) {
|
|||
|
||||
callback(messages, rsm);
|
||||
}
|
||||
}, function () {
|
||||
}).catch(e => {
|
||||
_converse.connection.deleteHandler(message_handler);
|
||||
|
||||
if (_.isFunction(errback)) {
|
||||
errback.apply(this, arguments);
|
||||
}
|
||||
}, _converse.message_archiving_timeout);
|
||||
|
||||
return;
|
||||
});
|
||||
}
|
||||
|
||||
_converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-mam', {
|
||||
|
@ -74535,7 +74560,7 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-mam
|
|||
|
||||
});
|
||||
|
||||
_converse.onMAMError = function (model, iq) {
|
||||
_converse.onMAMError = function (iq) {
|
||||
if (iq.querySelectorAll('feature-not-implemented').length) {
|
||||
_converse.log("Message Archive Management (XEP-0313) not supported by this server", Strophe.LogLevel.WARN);
|
||||
} else {
|
||||
|
@ -74567,20 +74592,16 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-mam
|
|||
'default': _converse.message_archiving
|
||||
});
|
||||
|
||||
_.each(preference.children, function (child) {
|
||||
stanza.cnode(child).up();
|
||||
});
|
||||
_.each(preference.children, child => stanza.cnode(child).up()); // XXX: Strictly speaking, the server should respond with the updated prefs
|
||||
// (see example 18: https://xmpp.org/extensions/xep-0313.html#config)
|
||||
// but Prosody doesn't do this, so we don't rely on it.
|
||||
|
||||
_converse.connection.sendIQ(stanza, _.partial(function (feature, iq) {
|
||||
// XXX: Strictly speaking, the server should respond with the updated prefs
|
||||
// (see example 18: https://xmpp.org/extensions/xep-0313.html#config)
|
||||
// but Prosody doesn't do this, so we don't rely on it.
|
||||
feature.save({
|
||||
'preferences': {
|
||||
'default': _converse.message_archiving
|
||||
}
|
||||
});
|
||||
}, feature), _converse.onMAMError);
|
||||
|
||||
_converse.api.sendIQ(stanza).then(() => feature.save({
|
||||
'preferences': {
|
||||
'default': _converse.message_archiving
|
||||
}
|
||||
})).catch(_converse.onMAMError);
|
||||
} else {
|
||||
feature.save({
|
||||
'preferences': {
|
||||
|
@ -74598,11 +74619,11 @@ _converse_core__WEBPACK_IMPORTED_MODULE_2__["default"].plugins.add('converse-mam
|
|||
if (feature.get('var') === Strophe.NS.MAM && prefs['default'] !== _converse.message_archiving && // eslint-disable-line dot-notation
|
||||
!_.isUndefined(_converse.message_archiving)) {
|
||||
// Ask the server for archiving preferences
|
||||
_converse.connection.sendIQ($iq({
|
||||
_converse.api.sendIQ($iq({
|
||||
'type': 'get'
|
||||
}).c('prefs', {
|
||||
'xmlns': Strophe.NS.MAM
|
||||
}), _.partial(_converse.onMAMPreferences, feature), _.partial(_converse.onMAMError, feature));
|
||||
})).then(_.partial(_converse.onMAMPreferences, feature)).catch(_converse.onMAMError);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -75124,7 +75145,7 @@ _converse_core__WEBPACK_IMPORTED_MODULE_6__["default"].plugins.add('converse-muc
|
|||
|
||||
this.save('connection_status', _converse_core__WEBPACK_IMPORTED_MODULE_6__["default"].ROOMSTATUS.CONNECTING);
|
||||
|
||||
_converse.connection.send(stanza);
|
||||
_converse.api.send(stanza);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
@ -75306,7 +75327,7 @@ _converse_core__WEBPACK_IMPORTED_MODULE_6__["default"].plugins.add('converse-muc
|
|||
return;
|
||||
}
|
||||
|
||||
_converse.connection.send($msg({
|
||||
_converse.api.send($msg({
|
||||
'to': this.get('jid'),
|
||||
'type': 'groupchat'
|
||||
}).c(chat_state, {
|
||||
|
@ -75356,14 +75377,14 @@ _converse_core__WEBPACK_IMPORTED_MODULE_6__["default"].plugins.add('converse-muc
|
|||
}
|
||||
|
||||
const invitation = $msg({
|
||||
from: _converse.connection.jid,
|
||||
to: recipient,
|
||||
id: _converse.connection.getUniqueId()
|
||||
'from': _converse.connection.jid,
|
||||
'to': recipient,
|
||||
'id': _converse.connection.getUniqueId()
|
||||
}).c('x', attrs);
|
||||
|
||||
_converse.connection.send(invitation);
|
||||
_converse.api.send(invitation);
|
||||
|
||||
_converse.emit('roomInviteSent', {
|
||||
_converse.api.emit('roomInviteSent', {
|
||||
'room': this,
|
||||
'recipient': recipient,
|
||||
'reason': reason
|
||||
|
@ -75531,14 +75552,12 @@ _converse_core__WEBPACK_IMPORTED_MODULE_6__["default"].plugins.add('converse-muc
|
|||
* Returns a promise which resolves once the response IQ
|
||||
* has been received.
|
||||
*/
|
||||
return new Promise((resolve, reject) => {
|
||||
_converse.connection.sendIQ($iq({
|
||||
'to': this.get('jid'),
|
||||
'type': "get"
|
||||
}).c("query", {
|
||||
xmlns: Strophe.NS.MUC_OWNER
|
||||
}), resolve, reject);
|
||||
});
|
||||
return _converse.api.sendIQ($iq({
|
||||
'to': this.get('jid'),
|
||||
'type': "get"
|
||||
}).c("query", {
|
||||
xmlns: Strophe.NS.MUC_OWNER
|
||||
}));
|
||||
},
|
||||
|
||||
sendConfiguration(config, callback, errback) {
|
||||
|
@ -75571,7 +75590,7 @@ _converse_core__WEBPACK_IMPORTED_MODULE_6__["default"].plugins.add('converse-muc
|
|||
|
||||
callback = _.isUndefined(callback) ? _.noop : _.partial(callback, iq.nodeTree);
|
||||
errback = _.isUndefined(errback) ? _.noop : _.partial(errback, iq.nodeTree);
|
||||
return _converse.connection.sendIQ(iq, callback, errback);
|
||||
return _converse.api.sendIQ(iq).then(callback).catch(errback);
|
||||
},
|
||||
|
||||
saveAffiliationAndRole(pres) {
|
||||
|
@ -75611,24 +75630,22 @@ _converse_core__WEBPACK_IMPORTED_MODULE_6__["default"].plugins.add('converse-muc
|
|||
* (Object) member: Map containing the member's jid and
|
||||
* optionally a reason and affiliation.
|
||||
*/
|
||||
return new Promise((resolve, reject) => {
|
||||
const iq = $iq({
|
||||
to: this.get('jid'),
|
||||
type: "set"
|
||||
}).c("query", {
|
||||
xmlns: Strophe.NS.MUC_ADMIN
|
||||
}).c("item", {
|
||||
'affiliation': member.affiliation || affiliation,
|
||||
'nick': member.nick,
|
||||
'jid': member.jid
|
||||
});
|
||||
|
||||
if (!_.isUndefined(member.reason)) {
|
||||
iq.c("reason", member.reason);
|
||||
}
|
||||
|
||||
_converse.connection.sendIQ(iq, resolve, reject);
|
||||
const iq = $iq({
|
||||
to: this.get('jid'),
|
||||
type: "set"
|
||||
}).c("query", {
|
||||
xmlns: Strophe.NS.MUC_ADMIN
|
||||
}).c("item", {
|
||||
'affiliation': member.affiliation || affiliation,
|
||||
'nick': member.nick,
|
||||
'jid': member.jid
|
||||
});
|
||||
|
||||
if (!_.isUndefined(member.reason)) {
|
||||
iq.c("reason", member.reason);
|
||||
}
|
||||
|
||||
return _converse.api.sendIQ(iq);
|
||||
},
|
||||
|
||||
setAffiliations(members) {
|
||||
|
@ -76972,7 +76989,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
|
|||
}).t(nick).up();
|
||||
}
|
||||
|
||||
_converse.connection.send(pres);
|
||||
_converse.api.send(pres);
|
||||
|
||||
this.save('ask', "subscribe"); // ask === 'subscribe' Means we have asked to subscribe to them.
|
||||
|
||||
|
@ -76985,7 +77002,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
|
|||
* state notification by sending a presence stanza of type
|
||||
* "subscribe" to the contact
|
||||
*/
|
||||
_converse.connection.send($pres({
|
||||
_converse.api.send($pres({
|
||||
'type': 'subscribe',
|
||||
'to': this.get('jid')
|
||||
}));
|
||||
|
@ -77000,7 +77017,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
|
|||
* Parameters:
|
||||
* (String) jid - The Jabber ID of the user who is unsubscribing
|
||||
*/
|
||||
_converse.connection.send($pres({
|
||||
_converse.api.send($pres({
|
||||
'type': 'unsubscribe',
|
||||
'to': this.get('jid')
|
||||
}));
|
||||
|
@ -77033,7 +77050,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
|
|||
pres.c("status").t(message);
|
||||
}
|
||||
|
||||
_converse.connection.send(pres);
|
||||
_converse.api.send(pres);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
@ -77052,7 +77069,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
|
|||
subscription: "remove"
|
||||
});
|
||||
|
||||
_converse.connection.sendIQ(iq, callback, errback);
|
||||
_converse.api.sendIQ(iq).then(callback).catch(errback);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -77176,7 +77193,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
|
|||
this.addContactToRoster(jid, name, groups, attributes).then(handler, handler);
|
||||
},
|
||||
|
||||
sendContactAddIQ(jid, name, groups, callback, errback) {
|
||||
sendContactAddIQ(jid, name, groups) {
|
||||
/* Send an IQ stanza to the XMPP server to add a new roster contact.
|
||||
*
|
||||
* Parameters:
|
||||
|
@ -77188,22 +77205,20 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
|
|||
*/
|
||||
name = _.isEmpty(name) ? jid : name;
|
||||
const iq = $iq({
|
||||
type: 'set'
|
||||
'type': 'set'
|
||||
}).c('query', {
|
||||
xmlns: Strophe.NS.ROSTER
|
||||
'xmlns': Strophe.NS.ROSTER
|
||||
}).c('item', {
|
||||
jid,
|
||||
name
|
||||
});
|
||||
|
||||
_.each(groups, function (group) {
|
||||
iq.c('group').t(group).up();
|
||||
});
|
||||
_.each(groups, group => iq.c('group').t(group).up());
|
||||
|
||||
_converse.connection.sendIQ(iq, callback, errback);
|
||||
_converse.api.sendIQ(iq);
|
||||
},
|
||||
|
||||
addContactToRoster(jid, name, groups, attributes) {
|
||||
async addContactToRoster(jid, name, groups, attributes) {
|
||||
/* Adds a RosterContact instance to _converse.roster and
|
||||
* registers the contact on the XMPP server.
|
||||
* Returns a promise which is resolved once the XMPP server has
|
||||
|
@ -77215,27 +77230,26 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
|
|||
* (Array of Strings) groups - Any roster groups the user might belong to
|
||||
* (Object) attributes - Any additional attributes to be stored on the user's model.
|
||||
*/
|
||||
return new Promise((resolve, reject) => {
|
||||
groups = groups || [];
|
||||
this.sendContactAddIQ(jid, name, groups, () => {
|
||||
const contact = this.create(_.assignIn({
|
||||
'ask': undefined,
|
||||
'nickname': name,
|
||||
groups,
|
||||
jid,
|
||||
'requesting': false,
|
||||
'subscription': 'none'
|
||||
}, attributes), {
|
||||
sort: false
|
||||
});
|
||||
resolve(contact);
|
||||
}, function (err) {
|
||||
alert(__('Sorry, there was an error while trying to add %1$s as a contact.', name));
|
||||
groups = groups || [];
|
||||
|
||||
_converse.log(err, Strophe.LogLevel.ERROR);
|
||||
try {
|
||||
await this.sendContactAddIQ(jid, name, groups);
|
||||
} catch (e) {
|
||||
_converse.log(e, Strophe.LogLevel.ERROR);
|
||||
|
||||
resolve(err);
|
||||
});
|
||||
alert(__('Sorry, there was an error while trying to add %1$s as a contact.', name));
|
||||
return e;
|
||||
}
|
||||
|
||||
return this.create(_.assignIn({
|
||||
'ask': undefined,
|
||||
'nickname': name,
|
||||
groups,
|
||||
jid,
|
||||
'requesting': false,
|
||||
'subscription': 'none'
|
||||
}, attributes), {
|
||||
'sort': false
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -77290,7 +77304,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
|
|||
return;
|
||||
}
|
||||
|
||||
_converse.connection.send($iq({
|
||||
_converse.api.send($iq({
|
||||
type: 'result',
|
||||
id,
|
||||
from: _converse.connection.jid
|
||||
|
@ -77325,34 +77339,32 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
|
|||
return _converse.api.disco.stream.getFeature('ver', 'urn:xmpp:features:rosterver') && this.data.get('version');
|
||||
},
|
||||
|
||||
fetchFromServer() {
|
||||
async fetchFromServer() {
|
||||
/* Fetch the roster from the XMPP server */
|
||||
return new Promise((resolve, reject) => {
|
||||
const iq = $iq({
|
||||
'type': 'get',
|
||||
'id': _converse.connection.getUniqueId('roster')
|
||||
}).c('query', {
|
||||
xmlns: Strophe.NS.ROSTER
|
||||
});
|
||||
|
||||
if (this.rosterVersioningSupported()) {
|
||||
iq.attrs({
|
||||
'ver': this.data.get('version')
|
||||
});
|
||||
}
|
||||
|
||||
const callback = _.flow(this.onReceivedFromServer.bind(this), resolve);
|
||||
|
||||
const errback = function errback(iq) {
|
||||
const errmsg = "Error while trying to fetch roster from the server";
|
||||
|
||||
_converse.log(errmsg, Strophe.LogLevel.ERROR);
|
||||
|
||||
reject(new Error(errmsg));
|
||||
};
|
||||
|
||||
return _converse.connection.sendIQ(iq, callback, errback);
|
||||
const stanza = $iq({
|
||||
'type': 'get',
|
||||
'id': _converse.connection.getUniqueId('roster')
|
||||
}).c('query', {
|
||||
xmlns: Strophe.NS.ROSTER
|
||||
});
|
||||
|
||||
if (this.rosterVersioningSupported()) {
|
||||
stanza.attrs({
|
||||
'ver': this.data.get('version')
|
||||
});
|
||||
}
|
||||
|
||||
let iq;
|
||||
|
||||
try {
|
||||
iq = await _converse.api.sendIQ(stanza);
|
||||
} catch (e) {
|
||||
_converse.log(e, Strophe.LogLevel.ERROR);
|
||||
|
||||
return _converse.log("Error while trying to fetch roster from the server", Strophe.LogLevel.ERROR);
|
||||
}
|
||||
|
||||
return this.onReceivedFromServer(iq);
|
||||
},
|
||||
|
||||
onReceivedFromServer(iq) {
|
||||
|
@ -77813,7 +77825,7 @@ _converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins.add('converse-vca
|
|||
|
||||
});
|
||||
|
||||
function onVCardData(jid, iq, callback) {
|
||||
async function onVCardData(jid, iq) {
|
||||
const vcard = iq.querySelector('vCard');
|
||||
let result = {};
|
||||
|
||||
|
@ -77834,23 +77846,11 @@ _converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins.add('converse-vca
|
|||
|
||||
if (result.image) {
|
||||
const buffer = u.base64ToArrayBuffer(result['image']);
|
||||
crypto.subtle.digest('SHA-1', buffer).then(ab => {
|
||||
result['image_hash'] = u.arrayBufferToHex(ab);
|
||||
if (callback) callback(result);
|
||||
});
|
||||
} else {
|
||||
if (callback) callback(result);
|
||||
const ab = await crypto.subtle.digest('SHA-1', buffer);
|
||||
result['image_hash'] = u.arrayBufferToHex(ab);
|
||||
}
|
||||
}
|
||||
|
||||
function onVCardError(jid, iq, errback) {
|
||||
if (errback) {
|
||||
errback({
|
||||
'stanza': iq,
|
||||
'jid': jid,
|
||||
'vcard_error': moment().format()
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function createStanza(type, jid, vcard_el) {
|
||||
|
@ -77881,7 +77881,7 @@ _converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins.add('converse-vca
|
|||
return _converse.api.sendIQ(createStanza("set", jid, vcard_el));
|
||||
}
|
||||
|
||||
function getVCard(_converse, jid) {
|
||||
async function getVCard(_converse, jid) {
|
||||
/* Request the VCard of another user. Returns a promise.
|
||||
*
|
||||
* Parameters:
|
||||
|
@ -77889,9 +77889,19 @@ _converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins.add('converse-vca
|
|||
* is being requested.
|
||||
*/
|
||||
const to = Strophe.getBareJidFromJid(jid) === _converse.bare_jid ? null : jid;
|
||||
return new Promise((resolve, reject) => {
|
||||
_converse.connection.sendIQ(createStanza("get", to), _.partial(onVCardData, jid, _, resolve), _.partial(onVCardError, jid, _, resolve), _converse.IQ_TIMEOUT);
|
||||
});
|
||||
let iq;
|
||||
|
||||
try {
|
||||
iq = await _converse.api.sendIQ(createStanza("get", to));
|
||||
} catch (iq) {
|
||||
return {
|
||||
'stanza': iq,
|
||||
'jid': jid,
|
||||
'vcard_error': moment().format()
|
||||
};
|
||||
}
|
||||
|
||||
return onVCardData(jid, iq);
|
||||
}
|
||||
/* Event handlers */
|
||||
|
||||
|
|
10
package-lock.json
generated
10
package-lock.json
generated
|
@ -3178,16 +3178,13 @@
|
|||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/backbone/-/backbone-1.3.3.tgz",
|
||||
"integrity": "sha1-TMgOp8sWMaxHSInOQPL4vGg7KZk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"underscore": ">=1.8.3"
|
||||
}
|
||||
},
|
||||
"backbone.browserStorage": {
|
||||
"version": "0.0.4",
|
||||
"resolved": "https://registry.npmjs.org/backbone.browserStorage/-/backbone.browserStorage-0.0.4.tgz",
|
||||
"integrity": "sha512-4LvDP2IkOu9Nt6kj6ft4moKmqKqm3c0WY3c/aie0Cf374wjFuO7vCh/afcKdu1YSuVsryM8yH90/J7yqWbaPHw==",
|
||||
"dev": true,
|
||||
"version": "github:jcbrand/Backbone.browserStorage#03bfa13f68b71f97be361840adc5a5064f57b47e",
|
||||
"from": "github:jcbrand/Backbone.browserStorage#03bfa13f68b71f97be361840adc5a5064f57b47e",
|
||||
"requires": {
|
||||
"backbone": "~1.x.x",
|
||||
"underscore": ">=1.4.0"
|
||||
|
@ -15220,8 +15217,7 @@
|
|||
"underscore": {
|
||||
"version": "1.8.3",
|
||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
|
||||
"integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=",
|
||||
"dev": true
|
||||
"integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI="
|
||||
},
|
||||
"underscore-contrib": {
|
||||
"version": "0.3.0",
|
||||
|
|
|
@ -39,8 +39,6 @@
|
|||
"@fortawesome/fontawesome-free": "5.3.1",
|
||||
"awesomplete-avoid-xss": "^1.1.2",
|
||||
"babel-loader": "^8.0.0",
|
||||
"backbone": "1.3.3",
|
||||
"backbone.browserStorage": "0.0.4",
|
||||
"backbone.nativeview": "^0.3.3",
|
||||
"backbone.overview": "^1.0.2",
|
||||
"backbone.vdomview": "^1.0.1",
|
||||
|
|
|
@ -1020,47 +1020,41 @@
|
|||
it("will clear any other chat status notifications",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
async function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'current');
|
||||
_converse.emit('rosterContactsFetched');
|
||||
test_utils.openControlBox();
|
||||
const sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
let view;
|
||||
|
||||
// See XEP-0085 http://xmpp.org/extensions/xep-0085.html#definitions
|
||||
spyOn(_converse, 'emit');
|
||||
test_utils.openChatBoxFor(_converse, sender_jid)
|
||||
.then(() => {
|
||||
view = _converse.chatboxviews.get(sender_jid);
|
||||
expect(view.el.querySelectorAll('.chat-event').length).toBe(0);
|
||||
// Insert <composing> message, to also check that
|
||||
// text messages are inserted correctly with
|
||||
// temporary chat events in the chat contents.
|
||||
const msg = $msg({
|
||||
'to': _converse.bare_jid,
|
||||
'xmlns': 'jabber:client',
|
||||
'from': sender_jid,
|
||||
'type': 'chat'})
|
||||
.c('composing', {'xmlns': Strophe.NS.CHATSTATES}).up()
|
||||
.tree();
|
||||
_converse.chatboxes.onMessage(msg);
|
||||
return test_utils.waitUntil(() => view.model.messages.length);
|
||||
}).then(() => {
|
||||
expect(view.el.querySelectorAll('.chat-state-notification').length).toBe(1);
|
||||
const msg = $msg({
|
||||
from: sender_jid,
|
||||
to: _converse.connection.jid,
|
||||
type: 'chat',
|
||||
id: (new Date()).getTime()
|
||||
}).c('body').c('inactive', {'xmlns': Strophe.NS.CHATSTATES}).tree();
|
||||
_converse.chatboxes.onMessage(msg);
|
||||
return test_utils.waitUntil(() => (view.model.messages.length > 1));
|
||||
}).then(() => {
|
||||
expect(_converse.emit).toHaveBeenCalledWith('message', jasmine.any(Object));
|
||||
expect($(view.el).find('.chat-state-notification').length).toBe(0);
|
||||
done();
|
||||
});
|
||||
await test_utils.openChatBoxFor(_converse, sender_jid);
|
||||
const view = _converse.chatboxviews.get(sender_jid);
|
||||
expect(view.el.querySelectorAll('.chat-event').length).toBe(0);
|
||||
// Insert <composing> message, to also check that
|
||||
// text messages are inserted correctly with
|
||||
// temporary chat events in the chat contents.
|
||||
let msg = $msg({
|
||||
'to': _converse.bare_jid,
|
||||
'xmlns': 'jabber:client',
|
||||
'from': sender_jid,
|
||||
'type': 'chat'})
|
||||
.c('composing', {'xmlns': Strophe.NS.CHATSTATES}).up()
|
||||
.tree();
|
||||
_converse.chatboxes.onMessage(msg);
|
||||
await test_utils.waitUntil(() => view.model.messages.length);
|
||||
expect(view.el.querySelectorAll('.chat-state-notification').length).toBe(1);
|
||||
msg = $msg({
|
||||
from: sender_jid,
|
||||
to: _converse.connection.jid,
|
||||
type: 'chat',
|
||||
id: (new Date()).getTime()
|
||||
}).c('body').c('inactive', {'xmlns': Strophe.NS.CHATSTATES}).tree();
|
||||
_converse.chatboxes.onMessage(msg);
|
||||
await test_utils.waitUntil(() => (view.model.messages.length > 1));
|
||||
expect(_converse.emit).toHaveBeenCalledWith('message', jasmine.any(Object));
|
||||
expect(view.el.querySelectorAll('.chat-state-notification').length).toBe(0);
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
||||
|
|
|
@ -3737,9 +3737,9 @@
|
|||
}));
|
||||
|
||||
it("contains a link to a modal which can list groupchats publically available on the server",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
function (done, _converse) {
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
|
||||
async function (done, _converse) {
|
||||
|
||||
var sendIQ = _converse.connection.sendIQ;
|
||||
var sent_stanza, IQ_id;
|
||||
|
@ -3753,53 +3753,49 @@
|
|||
roomspanel.el.querySelector('.show-list-muc-modal').click();
|
||||
test_utils.closeControlBox(_converse);
|
||||
const modal = roomspanel.list_rooms_modal;
|
||||
test_utils.waitUntil(() => u.isVisible(modal.el), 1000)
|
||||
.then(() => {
|
||||
spyOn(_converse.ChatRoom.prototype, 'getRoomFeatures').and.callFake(() => Promise.resolve());
|
||||
roomspanel.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
|
||||
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
|
||||
|
||||
// See: http://xmpp.org/extensions/xep-0045.html#disco-rooms
|
||||
expect(modal.el.querySelectorAll('.available-chatrooms li').length).toBe(0);
|
||||
// See: http://xmpp.org/extensions/xep-0045.html#disco-rooms
|
||||
expect(modal.el.querySelectorAll('.available-chatrooms li').length).toBe(0);
|
||||
|
||||
const input = modal.el.querySelector('input[name="server"]').value = 'chat.shakespear.lit';
|
||||
modal.el.querySelector('input[type="submit"]').click();
|
||||
return test_utils.waitUntil(() => _converse.chatboxes.length);
|
||||
}).then(() => {
|
||||
expect(sent_stanza.toLocaleString()).toBe(
|
||||
`<iq from="dummy@localhost/resource" id="${IQ_id}" to="chat.shakespear.lit" type="get" xmlns="jabber:client">`+
|
||||
`<query xmlns="http://jabber.org/protocol/disco#items"/>`+
|
||||
`</iq>`
|
||||
);
|
||||
const input = modal.el.querySelector('input[name="server"]').value = 'chat.shakespear.lit';
|
||||
modal.el.querySelector('input[type="submit"]').click();
|
||||
await test_utils.waitUntil(() => _converse.chatboxes.length);
|
||||
expect(sent_stanza.toLocaleString()).toBe(
|
||||
`<iq from="dummy@localhost/resource" id="${IQ_id}" to="chat.shakespear.lit" type="get" xmlns="jabber:client">`+
|
||||
`<query xmlns="http://jabber.org/protocol/disco#items"/>`+
|
||||
`</iq>`
|
||||
);
|
||||
|
||||
var iq = $iq({
|
||||
from:'muc.localhost',
|
||||
to:'dummy@localhost/pda',
|
||||
id: IQ_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()
|
||||
.c('item', { jid:'inverness@chat.shakespeare.lit', name:'Macbeth's Castle'}).nodeTree;
|
||||
_converse.connection._dataRecv(test_utils.createRequest(iq));
|
||||
const iq = $iq({
|
||||
from:'muc.localhost',
|
||||
to:'dummy@localhost/pda',
|
||||
id: IQ_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()
|
||||
.c('item', { jid:'inverness@chat.shakespeare.lit', name:'Macbeth's Castle'}).nodeTree;
|
||||
_converse.connection._dataRecv(test_utils.createRequest(iq));
|
||||
|
||||
expect(modal.el.querySelectorAll('.available-chatrooms li').length).toBe(5);
|
||||
await test_utils.waitUntil(() => modal.el.querySelectorAll('.available-chatrooms li').length === 5);
|
||||
|
||||
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");
|
||||
expect(rooms[4].textContent.trim()).toBe("Macbeth's Castle");
|
||||
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");
|
||||
expect(rooms[4].textContent.trim()).toBe("Macbeth's Castle");
|
||||
|
||||
rooms[4].querySelector('.open-room').click();
|
||||
return test_utils.waitUntil(() => _converse.chatboxes.length > 1);
|
||||
}).then(() => {
|
||||
expect(sizzle('.chatroom', _converse.el).filter(u.isVisible).length).toBe(1); // There should now be an open chatroom
|
||||
var view = _converse.chatboxviews.get('inverness@chat.shakespeare.lit');
|
||||
expect(view.el.querySelector('.chat-head-chatroom').textContent.trim()).toBe("Macbeth's Castle");
|
||||
done();
|
||||
}).catch(_.partial(console.error, _));
|
||||
rooms[4].querySelector('.open-room').click();
|
||||
await test_utils.waitUntil(() => _converse.chatboxes.length > 1);
|
||||
expect(sizzle('.chatroom', _converse.el).filter(u.isVisible).length).toBe(1); // There should now be an open chatroom
|
||||
var view = _converse.chatboxviews.get('inverness@chat.shakespeare.lit');
|
||||
expect(view.el.querySelector('.chat-head-chatroom').textContent.trim()).toBe("Macbeth's Castle");
|
||||
done();
|
||||
}));
|
||||
|
||||
it("shows the number of unread mentions received",
|
||||
|
|
484
spec/mam.js
484
spec/mam.js
|
@ -157,79 +157,79 @@
|
|||
it("checks whether returned MAM messages from a MUC room are from the right JID",
|
||||
mock.initConverseWithPromises(
|
||||
null, [], {},
|
||||
function (done, _converse) {
|
||||
async function (done, _converse) {
|
||||
|
||||
_converse.api.disco.entities.get(_converse.domain).then(function (entity) {
|
||||
if (!entity.features.findWhere({'var': Strophe.NS.MAM})) {
|
||||
_converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
|
||||
}
|
||||
var sent_stanza, IQ_id;
|
||||
var sendIQ = _converse.connection.sendIQ;
|
||||
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
|
||||
sent_stanza = iq;
|
||||
IQ_id = sendIQ.bind(this)(iq, callback, errback);
|
||||
});
|
||||
var callback = jasmine.createSpy('callback');
|
||||
|
||||
_converse.api.archive.query({'with': 'coven@chat.shakespear.lit', 'groupchat': true, 'max':'10'}, callback);
|
||||
var queryid = sent_stanza.nodeTree.querySelector('query').getAttribute('queryid');
|
||||
|
||||
/* <message id='iasd207' from='coven@chat.shakespeare.lit' to='hag66@shakespeare.lit/pda'>
|
||||
* <result xmlns='urn:xmpp:mam:2' queryid='g27' id='34482-21985-73620'>
|
||||
* <forwarded xmlns='urn:xmpp:forward:0'>
|
||||
* <delay xmlns='urn:xmpp:delay' stamp='2002-10-13T23:58:37Z'/>
|
||||
* <message xmlns="jabber:client"
|
||||
* from='coven@chat.shakespeare.lit/firstwitch'
|
||||
* id='162BEBB1-F6DB-4D9A-9BD8-CFDCC801A0B2'
|
||||
* type='groupchat'>
|
||||
* <body>Thrice the brinded cat hath mew'd.</body>
|
||||
* <x xmlns='http://jabber.org/protocol/muc#user'>
|
||||
* <item affiliation='none'
|
||||
* jid='witch1@shakespeare.lit'
|
||||
* role='participant' />
|
||||
* </x>
|
||||
* </message>
|
||||
* </forwarded>
|
||||
* </result>
|
||||
* </message>
|
||||
*/
|
||||
var msg1 = $msg({'id':'iasd207', 'from': 'other@chat.shakespear.lit', 'to': 'dummy@localhost'})
|
||||
.c('result', {'xmlns': 'urn:xmpp:mam:2', 'queryid':queryid, 'id':'34482-21985-73620'})
|
||||
.c('forwarded', {'xmlns':'urn:xmpp:forward:0'})
|
||||
.c('delay', {'xmlns':'urn:xmpp:delay', 'stamp':'2010-07-10T23:08:25Z'}).up()
|
||||
.c('message', {
|
||||
'xmlns':'jabber:client',
|
||||
'to':'dummy@localhost',
|
||||
'id':'162BEBB1-F6DB-4D9A-9BD8-CFDCC801A0B2',
|
||||
'from':'coven@chat.shakespeare.lit/firstwitch',
|
||||
'type':'groupchat' })
|
||||
.c('body').t("Thrice the brinded cat hath mew'd.");
|
||||
_converse.connection._dataRecv(test_utils.createRequest(msg1));
|
||||
|
||||
/* Send an <iq> stanza to indicate the end of the result set.
|
||||
*
|
||||
* <iq type='result' id='juliet1'>
|
||||
* <fin xmlns='urn:xmpp:mam:2'>
|
||||
* <set xmlns='http://jabber.org/protocol/rsm'>
|
||||
* <first index='0'>28482-98726-73623</first>
|
||||
* <last>09af3-cc343-b409f</last>
|
||||
* <count>20</count>
|
||||
* </set>
|
||||
* </iq>
|
||||
*/
|
||||
var stanza = $iq({'type': 'result', 'id': IQ_id})
|
||||
.c('fin', {'xmlns': 'urn:xmpp:mam:2'})
|
||||
.c('set', {'xmlns': 'http://jabber.org/protocol/rsm'})
|
||||
.c('first', {'index': '0'}).t('23452-4534-1').up()
|
||||
.c('last').t('09af3-cc343-b409f').up()
|
||||
.c('count').t('16');
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
expect(callback).toHaveBeenCalled();
|
||||
var args = callback.calls.argsFor(0);
|
||||
expect(args[0].length).toBe(0);
|
||||
done();
|
||||
const entity = await _converse.api.disco.entities.get(_converse.domain);
|
||||
if (!entity.features.findWhere({'var': Strophe.NS.MAM})) {
|
||||
_converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
|
||||
}
|
||||
var sent_stanza, IQ_id;
|
||||
const sendIQ = _converse.connection.sendIQ;
|
||||
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
|
||||
sent_stanza = iq;
|
||||
IQ_id = sendIQ.bind(this)(iq, callback, errback);
|
||||
});
|
||||
var callback = jasmine.createSpy('callback');
|
||||
|
||||
_converse.api.archive.query({'with': 'coven@chat.shakespear.lit', 'groupchat': true, 'max':'10'}, callback);
|
||||
var queryid = sent_stanza.nodeTree.querySelector('query').getAttribute('queryid');
|
||||
|
||||
/* <message id='iasd207' from='coven@chat.shakespeare.lit' to='hag66@shakespeare.lit/pda'>
|
||||
* <result xmlns='urn:xmpp:mam:2' queryid='g27' id='34482-21985-73620'>
|
||||
* <forwarded xmlns='urn:xmpp:forward:0'>
|
||||
* <delay xmlns='urn:xmpp:delay' stamp='2002-10-13T23:58:37Z'/>
|
||||
* <message xmlns="jabber:client"
|
||||
* from='coven@chat.shakespeare.lit/firstwitch'
|
||||
* id='162BEBB1-F6DB-4D9A-9BD8-CFDCC801A0B2'
|
||||
* type='groupchat'>
|
||||
* <body>Thrice the brinded cat hath mew'd.</body>
|
||||
* <x xmlns='http://jabber.org/protocol/muc#user'>
|
||||
* <item affiliation='none'
|
||||
* jid='witch1@shakespeare.lit'
|
||||
* role='participant' />
|
||||
* </x>
|
||||
* </message>
|
||||
* </forwarded>
|
||||
* </result>
|
||||
* </message>
|
||||
*/
|
||||
var msg1 = $msg({'id':'iasd207', 'from': 'other@chat.shakespear.lit', 'to': 'dummy@localhost'})
|
||||
.c('result', {'xmlns': 'urn:xmpp:mam:2', 'queryid':queryid, 'id':'34482-21985-73620'})
|
||||
.c('forwarded', {'xmlns':'urn:xmpp:forward:0'})
|
||||
.c('delay', {'xmlns':'urn:xmpp:delay', 'stamp':'2010-07-10T23:08:25Z'}).up()
|
||||
.c('message', {
|
||||
'xmlns':'jabber:client',
|
||||
'to':'dummy@localhost',
|
||||
'id':'162BEBB1-F6DB-4D9A-9BD8-CFDCC801A0B2',
|
||||
'from':'coven@chat.shakespeare.lit/firstwitch',
|
||||
'type':'groupchat' })
|
||||
.c('body').t("Thrice the brinded cat hath mew'd.");
|
||||
_converse.connection._dataRecv(test_utils.createRequest(msg1));
|
||||
|
||||
/* Send an <iq> stanza to indicate the end of the result set.
|
||||
*
|
||||
* <iq type='result' id='juliet1'>
|
||||
* <fin xmlns='urn:xmpp:mam:2'>
|
||||
* <set xmlns='http://jabber.org/protocol/rsm'>
|
||||
* <first index='0'>28482-98726-73623</first>
|
||||
* <last>09af3-cc343-b409f</last>
|
||||
* <count>20</count>
|
||||
* </set>
|
||||
* </iq>
|
||||
*/
|
||||
const stanza = $iq({'type': 'result', 'id': IQ_id})
|
||||
.c('fin', {'xmlns': 'urn:xmpp:mam:2'})
|
||||
.c('set', {'xmlns': 'http://jabber.org/protocol/rsm'})
|
||||
.c('first', {'index': '0'}).t('23452-4534-1').up()
|
||||
.c('last').t('09af3-cc343-b409f').up()
|
||||
.c('count').t('16');
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
await test_utils.waitUntil(() => callback.calls.count());
|
||||
expect(callback).toHaveBeenCalled();
|
||||
var args = callback.calls.argsFor(0);
|
||||
expect(args[0].length).toBe(0);
|
||||
done();
|
||||
}));
|
||||
|
||||
it("can be used to query for all messages in a certain timespan",
|
||||
|
@ -277,19 +277,18 @@
|
|||
}));
|
||||
|
||||
it("throws a TypeError if an invalid date is provided",
|
||||
mock.initConverseWithPromises(
|
||||
null, [], {},
|
||||
function (done, _converse) {
|
||||
mock.initConverseWithPromises(
|
||||
null, [], {},
|
||||
async function (done, _converse) {
|
||||
|
||||
_converse.api.disco.entities.get(_converse.domain).then(function (entity) {
|
||||
if (!entity.features.findWhere({'var': Strophe.NS.MAM})) {
|
||||
_converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
|
||||
}
|
||||
expect(_.partial(_converse.api.archive.query, {'start': 'not a real date'})).toThrow(
|
||||
new TypeError('archive.query: invalid date provided for: start')
|
||||
);
|
||||
done();
|
||||
});
|
||||
const entity = await _converse.api.disco.entities.get(_converse.domain);
|
||||
if (!entity.features.findWhere({'var': Strophe.NS.MAM})) {
|
||||
_converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
|
||||
}
|
||||
expect(_.partial(_converse.api.archive.query, {'start': 'not a real date'})).toThrow(
|
||||
new TypeError('archive.query: invalid date provided for: start')
|
||||
);
|
||||
done();
|
||||
}));
|
||||
|
||||
it("can be used to query for all messages after a certain time",
|
||||
|
@ -498,175 +497,176 @@
|
|||
}));
|
||||
|
||||
it("accepts a callback function, which it passes the messages and a Strophe.RSM object",
|
||||
mock.initConverseWithPromises(
|
||||
null, [], {},
|
||||
function (done, _converse) {
|
||||
mock.initConverseWithPromises(
|
||||
null, [], {},
|
||||
async function (done, _converse) {
|
||||
|
||||
_converse.api.disco.entities.get(_converse.domain).then(function (entity) {
|
||||
if (!entity.features.findWhere({'var': Strophe.NS.MAM})) {
|
||||
_converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
|
||||
}
|
||||
var sent_stanza, IQ_id;
|
||||
var sendIQ = _converse.connection.sendIQ;
|
||||
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
|
||||
sent_stanza = iq;
|
||||
IQ_id = sendIQ.bind(this)(iq, callback, errback);
|
||||
});
|
||||
var callback = jasmine.createSpy('callback');
|
||||
|
||||
_converse.api.archive.query({'with': 'romeo@capulet.lit', 'max':'10'}, callback);
|
||||
var queryid = sent_stanza.nodeTree.querySelector('query').getAttribute('queryid');
|
||||
|
||||
/* <message id='aeb213' to='juliet@capulet.lit/chamber'>
|
||||
* <result xmlns='urn:xmpp:mam:2' queryid='f27' id='28482-98726-73623'>
|
||||
* <forwarded xmlns='urn:xmpp:forward:0'>
|
||||
* <delay xmlns='urn:xmpp:delay' stamp='2010-07-10T23:08:25Z'/>
|
||||
* <message xmlns='jabber:client'
|
||||
* to='juliet@capulet.lit/balcony'
|
||||
* from='romeo@montague.lit/orchard'
|
||||
* type='chat'>
|
||||
* <body>Call me but love, and I'll be new baptized; Henceforth I never will be Romeo.</body>
|
||||
* </message>
|
||||
* </forwarded>
|
||||
* </result>
|
||||
* </message>
|
||||
*/
|
||||
var msg1 = $msg({'id':'aeb213', 'to':'juliet@capulet.lit/chamber'})
|
||||
.c('result', {'xmlns': 'urn:xmpp:mam:2', 'queryid':queryid, 'id':'28482-98726-73623'})
|
||||
.c('forwarded', {'xmlns':'urn:xmpp:forward:0'})
|
||||
.c('delay', {'xmlns':'urn:xmpp:delay', 'stamp':'2010-07-10T23:08:25Z'}).up()
|
||||
.c('message', {
|
||||
'xmlns':'jabber:client',
|
||||
'to':'juliet@capulet.lit/balcony',
|
||||
'from':'romeo@montague.lit/orchard',
|
||||
'type':'chat' })
|
||||
.c('body').t("Call me but love, and I'll be new baptized;");
|
||||
_converse.connection._dataRecv(test_utils.createRequest(msg1));
|
||||
|
||||
var msg2 = $msg({'id':'aeb213', 'to':'juliet@capulet.lit/chamber'})
|
||||
.c('result', {'xmlns': 'urn:xmpp:mam:2', 'queryid':queryid, 'id':'28482-98726-73624'})
|
||||
.c('forwarded', {'xmlns':'urn:xmpp:forward:0'})
|
||||
.c('delay', {'xmlns':'urn:xmpp:delay', 'stamp':'2010-07-10T23:08:25Z'}).up()
|
||||
.c('message', {
|
||||
'xmlns':'jabber:client',
|
||||
'to':'juliet@capulet.lit/balcony',
|
||||
'from':'romeo@montague.lit/orchard',
|
||||
'type':'chat' })
|
||||
.c('body').t("Henceforth I never will be Romeo.");
|
||||
_converse.connection._dataRecv(test_utils.createRequest(msg2));
|
||||
|
||||
/* Send an <iq> stanza to indicate the end of the result set.
|
||||
*
|
||||
* <iq type='result' id='juliet1'>
|
||||
* <fin xmlns='urn:xmpp:mam:2'>
|
||||
* <set xmlns='http://jabber.org/protocol/rsm'>
|
||||
* <first index='0'>28482-98726-73623</first>
|
||||
* <last>09af3-cc343-b409f</last>
|
||||
* <count>20</count>
|
||||
* </set>
|
||||
* </iq>
|
||||
*/
|
||||
var stanza = $iq({'type': 'result', 'id': IQ_id})
|
||||
.c('fin', {'xmlns': 'urn:xmpp:mam:2'})
|
||||
.c('set', {'xmlns': 'http://jabber.org/protocol/rsm'})
|
||||
.c('first', {'index': '0'}).t('23452-4534-1').up()
|
||||
.c('last').t('09af3-cc343-b409f').up()
|
||||
.c('count').t('16');
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
expect(callback).toHaveBeenCalled();
|
||||
var args = callback.calls.argsFor(0);
|
||||
expect(args[0].length).toBe(2);
|
||||
expect(args[0][0].outerHTML).toBe(msg1.nodeTree.outerHTML);
|
||||
expect(args[0][1].outerHTML).toBe(msg2.nodeTree.outerHTML);
|
||||
expect(args[1]['with']).toBe('romeo@capulet.lit'); // eslint-disable-line dot-notation
|
||||
expect(args[1].max).toBe('10');
|
||||
expect(args[1].count).toBe('16');
|
||||
expect(args[1].first).toBe('23452-4534-1');
|
||||
expect(args[1].last).toBe('09af3-cc343-b409f');
|
||||
done()
|
||||
const entity = await _converse.api.disco.entities.get(_converse.domain);
|
||||
if (!entity.features.findWhere({'var': Strophe.NS.MAM})) {
|
||||
_converse.disco_entities.get(_converse.domain).features.create({'var': Strophe.NS.MAM});
|
||||
}
|
||||
let sent_stanza, IQ_id;
|
||||
const sendIQ = _converse.connection.sendIQ;
|
||||
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
|
||||
sent_stanza = iq;
|
||||
IQ_id = sendIQ.bind(this)(iq, callback, errback);
|
||||
});
|
||||
const callback = jasmine.createSpy('callback');
|
||||
|
||||
_converse.api.archive.query({'with': 'romeo@capulet.lit', 'max':'10'}, callback);
|
||||
const queryid = sent_stanza.nodeTree.querySelector('query').getAttribute('queryid');
|
||||
|
||||
/* <message id='aeb213' to='juliet@capulet.lit/chamber'>
|
||||
* <result xmlns='urn:xmpp:mam:2' queryid='f27' id='28482-98726-73623'>
|
||||
* <forwarded xmlns='urn:xmpp:forward:0'>
|
||||
* <delay xmlns='urn:xmpp:delay' stamp='2010-07-10T23:08:25Z'/>
|
||||
* <message xmlns='jabber:client'
|
||||
* to='juliet@capulet.lit/balcony'
|
||||
* from='romeo@montague.lit/orchard'
|
||||
* type='chat'>
|
||||
* <body>Call me but love, and I'll be new baptized; Henceforth I never will be Romeo.</body>
|
||||
* </message>
|
||||
* </forwarded>
|
||||
* </result>
|
||||
* </message>
|
||||
*/
|
||||
var msg1 = $msg({'id':'aeb213', 'to':'juliet@capulet.lit/chamber'})
|
||||
.c('result', {'xmlns': 'urn:xmpp:mam:2', 'queryid':queryid, 'id':'28482-98726-73623'})
|
||||
.c('forwarded', {'xmlns':'urn:xmpp:forward:0'})
|
||||
.c('delay', {'xmlns':'urn:xmpp:delay', 'stamp':'2010-07-10T23:08:25Z'}).up()
|
||||
.c('message', {
|
||||
'xmlns':'jabber:client',
|
||||
'to':'juliet@capulet.lit/balcony',
|
||||
'from':'romeo@montague.lit/orchard',
|
||||
'type':'chat' })
|
||||
.c('body').t("Call me but love, and I'll be new baptized;");
|
||||
_converse.connection._dataRecv(test_utils.createRequest(msg1));
|
||||
|
||||
var msg2 = $msg({'id':'aeb213', 'to':'juliet@capulet.lit/chamber'})
|
||||
.c('result', {'xmlns': 'urn:xmpp:mam:2', 'queryid':queryid, 'id':'28482-98726-73624'})
|
||||
.c('forwarded', {'xmlns':'urn:xmpp:forward:0'})
|
||||
.c('delay', {'xmlns':'urn:xmpp:delay', 'stamp':'2010-07-10T23:08:25Z'}).up()
|
||||
.c('message', {
|
||||
'xmlns':'jabber:client',
|
||||
'to':'juliet@capulet.lit/balcony',
|
||||
'from':'romeo@montague.lit/orchard',
|
||||
'type':'chat' })
|
||||
.c('body').t("Henceforth I never will be Romeo.");
|
||||
_converse.connection._dataRecv(test_utils.createRequest(msg2));
|
||||
|
||||
/* Send an <iq> stanza to indicate the end of the result set.
|
||||
*
|
||||
* <iq type='result' id='juliet1'>
|
||||
* <fin xmlns='urn:xmpp:mam:2'>
|
||||
* <set xmlns='http://jabber.org/protocol/rsm'>
|
||||
* <first index='0'>28482-98726-73623</first>
|
||||
* <last>09af3-cc343-b409f</last>
|
||||
* <count>20</count>
|
||||
* </set>
|
||||
* </iq>
|
||||
*/
|
||||
const stanza = $iq({'type': 'result', 'id': IQ_id})
|
||||
.c('fin', {'xmlns': 'urn:xmpp:mam:2'})
|
||||
.c('set', {'xmlns': 'http://jabber.org/protocol/rsm'})
|
||||
.c('first', {'index': '0'}).t('23452-4534-1').up()
|
||||
.c('last').t('09af3-cc343-b409f').up()
|
||||
.c('count').t('16');
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
await test_utils.waitUntil(() => callback.calls.count());
|
||||
expect(callback).toHaveBeenCalled();
|
||||
var args = callback.calls.argsFor(0);
|
||||
expect(args[0].length).toBe(2);
|
||||
expect(args[0][0].outerHTML).toBe(msg1.nodeTree.outerHTML);
|
||||
expect(args[0][1].outerHTML).toBe(msg2.nodeTree.outerHTML);
|
||||
expect(args[1]['with']).toBe('romeo@capulet.lit'); // eslint-disable-line dot-notation
|
||||
expect(args[1].max).toBe('10');
|
||||
expect(args[1].count).toBe('16');
|
||||
expect(args[1].first).toBe('23452-4534-1');
|
||||
expect(args[1].last).toBe('09af3-cc343-b409f');
|
||||
done()
|
||||
}));
|
||||
});
|
||||
|
||||
describe("The default preference", function () {
|
||||
|
||||
it("is set once server support for MAM has been confirmed",
|
||||
mock.initConverseWithPromises(
|
||||
null, [], {},
|
||||
function (done, _converse) {
|
||||
mock.initConverseWithPromises(
|
||||
null, [], {},
|
||||
async function (done, _converse) {
|
||||
|
||||
_converse.api.disco.entities.get(_converse.domain).then(function (entity) {
|
||||
var sent_stanza, IQ_id;
|
||||
var sendIQ = _converse.connection.sendIQ;
|
||||
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
|
||||
sent_stanza = iq;
|
||||
IQ_id = sendIQ.bind(this)(iq, callback, errback);
|
||||
});
|
||||
spyOn(_converse, 'onMAMPreferences').and.callThrough();
|
||||
_converse.message_archiving = 'never';
|
||||
|
||||
var feature = new Backbone.Model({
|
||||
'var': Strophe.NS.MAM
|
||||
});
|
||||
spyOn(feature, 'save').and.callFake(feature.set); // Save will complain about a url not being set
|
||||
|
||||
entity.onFeatureAdded(feature);
|
||||
|
||||
expect(_converse.connection.sendIQ).toHaveBeenCalled();
|
||||
expect(sent_stanza.toLocaleString()).toBe(
|
||||
`<iq id="${IQ_id}" type="get" xmlns="jabber:client">`+
|
||||
`<prefs xmlns="urn:xmpp:mam:2"/>`+
|
||||
`</iq>`);
|
||||
|
||||
/* Example 20. Server responds with current preferences
|
||||
*
|
||||
* <iq type='result' id='juliet2'>
|
||||
* <prefs xmlns='urn:xmpp:mam:0' default='roster'>
|
||||
* <always/>
|
||||
* <never/>
|
||||
* </prefs>
|
||||
* </iq>
|
||||
*/
|
||||
var stanza = $iq({'type': 'result', 'id': IQ_id})
|
||||
.c('prefs', {'xmlns': Strophe.NS.MAM, 'default':'roster'})
|
||||
.c('always').c('jid').t('romeo@montague.lit').up().up()
|
||||
.c('never').c('jid').t('montague@montague.lit');
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
expect(_converse.onMAMPreferences).toHaveBeenCalled();
|
||||
expect(_converse.connection.sendIQ.calls.count()).toBe(2);
|
||||
|
||||
expect(sent_stanza.toString()).toBe(
|
||||
`<iq id="${IQ_id}" type="set" xmlns="jabber:client">`+
|
||||
`<prefs default="never" xmlns="urn:xmpp:mam:2">`+
|
||||
`<always><jid>romeo@montague.lit</jid></always>`+
|
||||
`<never><jid>montague@montague.lit</jid></never>`+
|
||||
`</prefs>`+
|
||||
`</iq>`
|
||||
);
|
||||
|
||||
expect(feature.get('preference')).toBe(undefined);
|
||||
/* <iq type='result' id='juliet3'>
|
||||
* <prefs xmlns='urn:xmpp:mam:0' default='always'>
|
||||
* <always>
|
||||
* <jid>romeo@montague.lit</jid>
|
||||
* </always>
|
||||
* <never>
|
||||
* <jid>montague@montague.lit</jid>
|
||||
* </never>
|
||||
* </prefs>
|
||||
* </iq>
|
||||
*/
|
||||
stanza = $iq({'type': 'result', 'id': IQ_id})
|
||||
.c('prefs', {'xmlns': Strophe.NS.MAM, 'default':'always'})
|
||||
.c('always').up()
|
||||
.c('never').up();
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
expect(feature.save).toHaveBeenCalled();
|
||||
expect(feature.get('preferences')['default']).toBe('never'); // eslint-disable-line dot-notation
|
||||
done();
|
||||
const entity = await _converse.api.disco.entities.get(_converse.domain);
|
||||
let sent_stanza, IQ_id;
|
||||
const sendIQ = _converse.connection.sendIQ;
|
||||
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
|
||||
sent_stanza = iq;
|
||||
IQ_id = sendIQ.bind(this)(iq, callback, errback);
|
||||
});
|
||||
spyOn(_converse, 'onMAMPreferences').and.callThrough();
|
||||
_converse.message_archiving = 'never';
|
||||
|
||||
var feature = new Backbone.Model({
|
||||
'var': Strophe.NS.MAM
|
||||
});
|
||||
spyOn(feature, 'save').and.callFake(feature.set); // Save will complain about a url not being set
|
||||
|
||||
entity.onFeatureAdded(feature);
|
||||
|
||||
expect(_converse.connection.sendIQ).toHaveBeenCalled();
|
||||
expect(sent_stanza.toLocaleString()).toBe(
|
||||
`<iq id="${IQ_id}" type="get" xmlns="jabber:client">`+
|
||||
`<prefs xmlns="urn:xmpp:mam:2"/>`+
|
||||
`</iq>`);
|
||||
|
||||
/* Example 20. Server responds with current preferences
|
||||
*
|
||||
* <iq type='result' id='juliet2'>
|
||||
* <prefs xmlns='urn:xmpp:mam:0' default='roster'>
|
||||
* <always/>
|
||||
* <never/>
|
||||
* </prefs>
|
||||
* </iq>
|
||||
*/
|
||||
let stanza = $iq({'type': 'result', 'id': IQ_id})
|
||||
.c('prefs', {'xmlns': Strophe.NS.MAM, 'default':'roster'})
|
||||
.c('always').c('jid').t('romeo@montague.lit').up().up()
|
||||
.c('never').c('jid').t('montague@montague.lit');
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
await test_utils.waitUntil(() => _converse.onMAMPreferences.calls.count());
|
||||
expect(_converse.onMAMPreferences).toHaveBeenCalled();
|
||||
expect(_converse.connection.sendIQ.calls.count()).toBe(2);
|
||||
|
||||
expect(sent_stanza.toString()).toBe(
|
||||
`<iq id="${IQ_id}" type="set" xmlns="jabber:client">`+
|
||||
`<prefs default="never" xmlns="urn:xmpp:mam:2">`+
|
||||
`<always><jid>romeo@montague.lit</jid></always>`+
|
||||
`<never><jid>montague@montague.lit</jid></never>`+
|
||||
`</prefs>`+
|
||||
`</iq>`
|
||||
);
|
||||
|
||||
expect(feature.get('preference')).toBe(undefined);
|
||||
/* <iq type='result' id='juliet3'>
|
||||
* <prefs xmlns='urn:xmpp:mam:0' default='always'>
|
||||
* <always>
|
||||
* <jid>romeo@montague.lit</jid>
|
||||
* </always>
|
||||
* <never>
|
||||
* <jid>montague@montague.lit</jid>
|
||||
* </never>
|
||||
* </prefs>
|
||||
* </iq>
|
||||
*/
|
||||
stanza = $iq({'type': 'result', 'id': IQ_id})
|
||||
.c('prefs', {'xmlns': Strophe.NS.MAM, 'default':'always'})
|
||||
.c('always').up()
|
||||
.c('never');
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
await test_utils.waitUntil(() => feature.save.calls.count());
|
||||
expect(feature.save).toHaveBeenCalled();
|
||||
expect(feature.get('preferences')['default']).toBe('never'); // eslint-disable-line dot-notation
|
||||
done();
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
|
705
spec/protocol.js
705
spec/protocol.js
|
@ -52,327 +52,317 @@
|
|||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'],
|
||||
{ roster_groups: false },
|
||||
function (done, _converse) {
|
||||
async function (done, _converse) {
|
||||
|
||||
var contact, sent_stanza, IQ_id, stanza, modal;
|
||||
test_utils.waitUntilDiscoConfirmed(_converse, 'localhost', [], ['vcard-temp'])
|
||||
.then(function () {
|
||||
return test_utils.waitUntil(function () {
|
||||
return _converse.xmppstatus.vcard.get('fullname');
|
||||
}, 300);
|
||||
}).then(function () {
|
||||
/* The process by which a user subscribes to a contact, including
|
||||
* the interaction between roster items and subscription states.
|
||||
*/
|
||||
test_utils.openControlBox(_converse);
|
||||
var cbview = _converse.chatboxviews.get('controlbox');
|
||||
await test_utils.waitUntilDiscoConfirmed(_converse, 'localhost', [], ['vcard-temp']);
|
||||
await test_utils.waitUntil(() => _converse.xmppstatus.vcard.get('fullname'), 300);
|
||||
/* The process by which a user subscribes to a contact, including
|
||||
* the interaction between roster items and subscription states.
|
||||
*/
|
||||
test_utils.openControlBox(_converse);
|
||||
const cbview = _converse.chatboxviews.get('controlbox');
|
||||
|
||||
spyOn(_converse.roster, "addAndSubscribe").and.callThrough();
|
||||
spyOn(_converse.roster, "addContactToRoster").and.callThrough();
|
||||
spyOn(_converse.roster, "sendContactAddIQ").and.callThrough();
|
||||
spyOn(_converse.api.vcard, "get").and.callThrough();
|
||||
spyOn(_converse.roster, "addAndSubscribe").and.callThrough();
|
||||
spyOn(_converse.roster, "addContactToRoster").and.callThrough();
|
||||
spyOn(_converse.roster, "sendContactAddIQ").and.callThrough();
|
||||
spyOn(_converse.api.vcard, "get").and.callThrough();
|
||||
|
||||
var sendIQ = _converse.connection.sendIQ;
|
||||
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
|
||||
sent_stanza = iq;
|
||||
IQ_id = sendIQ.bind(this)(iq, callback, errback);
|
||||
});
|
||||
|
||||
cbview.el.querySelector('.add-contact').click()
|
||||
modal = _converse.rosterview.add_contact_modal;
|
||||
return test_utils.waitUntil(function () {
|
||||
return u.isVisible(modal.el);
|
||||
}, 1000);
|
||||
}).then(function () {
|
||||
spyOn(modal, "addContactFromForm").and.callThrough();
|
||||
modal.delegateEvents();
|
||||
|
||||
// Fill in the form and submit
|
||||
var form = modal.el.querySelector('form.add-xmpp-contact');
|
||||
form.querySelector('input').value = 'contact@example.org';
|
||||
form.querySelector('[type="submit"]').click();
|
||||
|
||||
/* In preparation for being able to render the contact in the
|
||||
* user's client interface and for the server to keep track of the
|
||||
* subscription, the user's client SHOULD perform a "roster set"
|
||||
* for the new roster item.
|
||||
*/
|
||||
expect(modal.addContactFromForm).toHaveBeenCalled();
|
||||
expect(_converse.roster.addAndSubscribe).toHaveBeenCalled();
|
||||
expect(_converse.roster.addContactToRoster).toHaveBeenCalled();
|
||||
|
||||
/* _converse request consists of sending an IQ
|
||||
* stanza of type='set' containing a <query/> element qualified by
|
||||
* the 'jabber:iq:roster' namespace, which in turn contains an
|
||||
* <item/> element that defines the new roster item; the <item/>
|
||||
* element MUST possess a 'jid' attribute, MAY possess a 'name'
|
||||
* attribute, MUST NOT possess a 'subscription' attribute, and MAY
|
||||
* contain one or more <group/> child elements:
|
||||
*
|
||||
* <iq type='set' id='set1'>
|
||||
* <query xmlns='jabber:iq:roster'>
|
||||
* <item
|
||||
* jid='contact@example.org'
|
||||
* name='MyContact'>
|
||||
* <group>MyBuddies</group>
|
||||
* </item>
|
||||
* </query>
|
||||
* </iq>
|
||||
*/
|
||||
expect(_converse.roster.sendContactAddIQ).toHaveBeenCalled();
|
||||
expect(sent_stanza.toLocaleString()).toBe(
|
||||
`<iq id="${IQ_id}" type="set" xmlns="jabber:client">`+
|
||||
`<query xmlns="jabber:iq:roster">`+
|
||||
`<item jid="contact@example.org" name="contact@example.org"/>`+
|
||||
`</query>`+
|
||||
`</iq>`
|
||||
);
|
||||
/* As a result, the user's server (1) MUST initiate a roster push
|
||||
* for the new roster item to all available resources associated
|
||||
* with _converse user that have requested the roster, setting the
|
||||
* 'subscription' attribute to a value of "none"; and (2) MUST
|
||||
* reply to the sending resource with an IQ result indicating the
|
||||
* success of the roster set:
|
||||
*
|
||||
* <iq type='set'>
|
||||
* <query xmlns='jabber:iq:roster'>
|
||||
* <item
|
||||
* jid='contact@example.org'
|
||||
* subscription='none'
|
||||
* name='MyContact'>
|
||||
* <group>MyBuddies</group>
|
||||
* </item>
|
||||
* </query>
|
||||
* </iq>
|
||||
*/
|
||||
var create = _converse.roster.create;
|
||||
var sent_stanzas = [];
|
||||
spyOn(_converse.connection, 'send').and.callFake(function (stanza) {
|
||||
sent_stanza = stanza;
|
||||
sent_stanzas.push(stanza.toLocaleString());
|
||||
});
|
||||
spyOn(_converse.roster, 'create').and.callFake(function () {
|
||||
contact = create.apply(_converse.roster, arguments);
|
||||
spyOn(contact, 'subscribe').and.callThrough();
|
||||
return contact;
|
||||
});
|
||||
stanza = $iq({'type': 'set'}).c('query', {'xmlns': 'jabber:iq:roster'})
|
||||
.c('item', {
|
||||
'jid': 'contact@example.org',
|
||||
'subscription': 'none',
|
||||
'name': 'contact@example.org'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
/*
|
||||
* <iq type='result' id='set1'/>
|
||||
*/
|
||||
stanza = $iq({'type': 'result', 'id':IQ_id});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
// A contact should now have been created
|
||||
expect(_converse.roster.get('contact@example.org') instanceof _converse.RosterContact).toBeTruthy();
|
||||
expect(contact.get('jid')).toBe('contact@example.org');
|
||||
expect(_converse.api.vcard.get).toHaveBeenCalled();
|
||||
|
||||
/* To subscribe to the contact's presence information,
|
||||
* the user's client MUST send a presence stanza of
|
||||
* type='subscribe' to the contact:
|
||||
*
|
||||
* <presence to='contact@example.org' type='subscribe'/>
|
||||
*/
|
||||
return test_utils.waitUntil(function () {
|
||||
return sent_stanzas.length == 1;
|
||||
}, 300);
|
||||
}).then(function () {
|
||||
expect(contact.subscribe).toHaveBeenCalled();
|
||||
expect(sent_stanza.toLocaleString()).toBe( // Strophe adds the xmlns attr (although not in spec)
|
||||
`<presence to="contact@example.org" type="subscribe" xmlns="jabber:client">`+
|
||||
`<nick xmlns="http://jabber.org/protocol/nick">Max Mustermann</nick>`+
|
||||
`</presence>`
|
||||
);
|
||||
/* As a result, the user's server MUST initiate a second roster
|
||||
* push to all of the user's available resources that have
|
||||
* requested the roster, setting the contact to the pending
|
||||
* sub-state of the 'none' subscription state; _converse pending
|
||||
* sub-state is denoted by the inclusion of the ask='subscribe'
|
||||
* attribute in the roster item:
|
||||
*
|
||||
* <iq type='set'>
|
||||
* <query xmlns='jabber:iq:roster'>
|
||||
* <item
|
||||
* jid='contact@example.org'
|
||||
* subscription='none'
|
||||
* ask='subscribe'
|
||||
* name='MyContact'>
|
||||
* <group>MyBuddies</group>
|
||||
* </item>
|
||||
* </query>
|
||||
* </iq>
|
||||
*/
|
||||
spyOn(_converse.roster, "updateContact").and.callThrough();
|
||||
stanza = $iq({'type': 'set', 'from': _converse.bare_jid})
|
||||
.c('query', {'xmlns': 'jabber:iq:roster'})
|
||||
.c('item', {
|
||||
'jid': 'contact@example.org',
|
||||
'subscription': 'none',
|
||||
'ask': 'subscribe',
|
||||
'name': 'contact@example.org'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
expect(_converse.roster.updateContact).toHaveBeenCalled();
|
||||
// Check that the user is now properly shown as a pending
|
||||
// contact in the roster.
|
||||
return test_utils.waitUntil(function () {
|
||||
var $header = $('a:contains("Pending contacts")');
|
||||
var $contacts = $header.parent().find('li:visible');
|
||||
return $contacts.length;
|
||||
}, 600);
|
||||
}).then(function () {
|
||||
var $header = $('a:contains("Pending contacts")');
|
||||
var $contacts = $header.parent().find('li');
|
||||
expect($contacts.length).toBe(1);
|
||||
expect($contacts.is(':visible')).toBeTruthy();
|
||||
|
||||
spyOn(contact, "ackSubscribe").and.callThrough();
|
||||
/* Here we assume the "happy path" that the contact
|
||||
* approves the subscription request
|
||||
*
|
||||
* <presence
|
||||
* to='user@example.com'
|
||||
* from='contact@example.org'
|
||||
* type='subscribed'/>
|
||||
*/
|
||||
stanza = $pres({
|
||||
'to': _converse.bare_jid,
|
||||
'from': 'contact@example.org',
|
||||
'type': 'subscribed'
|
||||
});
|
||||
sent_stanza = ""; // Reset
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
/* Upon receiving the presence stanza of type "subscribed",
|
||||
* the user SHOULD acknowledge receipt of that
|
||||
* subscription state notification by sending a presence
|
||||
* stanza of type "subscribe".
|
||||
*/
|
||||
expect(contact.ackSubscribe).toHaveBeenCalled();
|
||||
expect(sent_stanza.toLocaleString()).toBe( // Strophe adds the xmlns attr (although not in spec)
|
||||
`<presence to="contact@example.org" type="subscribe" xmlns="jabber:client"/>`
|
||||
);
|
||||
|
||||
/* The user's server MUST initiate a roster push to all of the user's
|
||||
* available resources that have requested the roster,
|
||||
* containing an updated roster item for the contact with
|
||||
* the 'subscription' attribute set to a value of "to";
|
||||
*
|
||||
* <iq type='set'>
|
||||
* <query xmlns='jabber:iq:roster'>
|
||||
* <item
|
||||
* jid='contact@example.org'
|
||||
* subscription='to'
|
||||
* name='MyContact'>
|
||||
* <group>MyBuddies</group>
|
||||
* </item>
|
||||
* </query>
|
||||
* </iq>
|
||||
*/
|
||||
IQ_id = _converse.connection.getUniqueId('roster');
|
||||
stanza = $iq({'type': 'set', 'id': IQ_id})
|
||||
.c('query', {'xmlns': 'jabber:iq:roster'})
|
||||
.c('item', {
|
||||
'jid': 'contact@example.org',
|
||||
'subscription': 'to',
|
||||
'name': 'contact@example.org'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
// Check that the IQ set was acknowledged.
|
||||
expect(sent_stanza.toLocaleString()).toBe( // Strophe adds the xmlns attr (although not in spec)
|
||||
`<iq from="dummy@localhost/resource" id="${IQ_id}" type="result" xmlns="jabber:client"/>`
|
||||
);
|
||||
expect(_converse.roster.updateContact).toHaveBeenCalled();
|
||||
|
||||
// The contact should now be visible as an existing
|
||||
// contact (but still offline).
|
||||
return test_utils.waitUntil(function () {
|
||||
var $header = $('a:contains("My contacts")');
|
||||
var $contacts = $header.parent().find('li:visible');
|
||||
return $contacts.length;
|
||||
}, 600);
|
||||
}).then(function () {
|
||||
var $header = $('a:contains("My contacts")');
|
||||
expect($header.length).toBe(1);
|
||||
expect($header.is(":visible")).toBeTruthy();
|
||||
var $contacts = $header.parent().find('li');
|
||||
expect($contacts.length).toBe(1);
|
||||
// Check that it has the right classes and text
|
||||
expect($contacts.hasClass('to')).toBeTruthy();
|
||||
expect($contacts.hasClass('both')).toBeFalsy();
|
||||
expect($contacts.hasClass('current-xmpp-contact')).toBeTruthy();
|
||||
expect($contacts.text().trim()).toBe('Contact');
|
||||
expect(contact.presence.get('show')).toBe('offline');
|
||||
|
||||
/* <presence
|
||||
* from='contact@example.org/resource'
|
||||
* to='user@example.com/resource'/>
|
||||
*/
|
||||
stanza = $pres({'to': _converse.bare_jid, 'from': 'contact@example.org/resource'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
// Now the contact should also be online.
|
||||
expect(contact.presence.get('show')).toBe('online');
|
||||
|
||||
/* Section 8.3. Creating a Mutual Subscription
|
||||
*
|
||||
* If the contact wants to create a mutual subscription,
|
||||
* the contact MUST send a subscription request to the
|
||||
* user.
|
||||
*
|
||||
* <presence from='contact@example.org' to='user@example.com' type='subscribe'/>
|
||||
*/
|
||||
spyOn(contact, 'authorize').and.callThrough();
|
||||
spyOn(_converse.roster, 'handleIncomingSubscription').and.callThrough();
|
||||
stanza = $pres({
|
||||
'to': _converse.bare_jid,
|
||||
'from': 'contact@example.org/resource',
|
||||
'type': 'subscribe'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
expect(_converse.roster.handleIncomingSubscription).toHaveBeenCalled();
|
||||
|
||||
/* The user's client MUST send a presence stanza of type
|
||||
* "subscribed" to the contact in order to approve the
|
||||
* subscription request.
|
||||
*
|
||||
* <presence to='contact@example.org' type='subscribed'/>
|
||||
*/
|
||||
expect(contact.authorize).toHaveBeenCalled();
|
||||
expect(sent_stanza.toLocaleString()).toBe(
|
||||
`<presence to="contact@example.org" type="subscribed" xmlns="jabber:client"/>`
|
||||
);
|
||||
|
||||
/* As a result, the user's server MUST initiate a
|
||||
* roster push containing a roster item for the
|
||||
* contact with the 'subscription' attribute set to
|
||||
* a value of "both".
|
||||
*
|
||||
* <iq type='set'>
|
||||
* <query xmlns='jabber:iq:roster'>
|
||||
* <item
|
||||
* jid='contact@example.org'
|
||||
* subscription='both'
|
||||
* name='MyContact'>
|
||||
* <group>MyBuddies</group>
|
||||
* </item>
|
||||
* </query>
|
||||
* </iq>
|
||||
*/
|
||||
stanza = $iq({'type': 'set'}).c('query', {'xmlns': 'jabber:iq:roster'})
|
||||
.c('item', {
|
||||
'jid': 'contact@example.org',
|
||||
'subscription': 'both',
|
||||
'name': 'contact@example.org'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
expect(_converse.roster.updateContact).toHaveBeenCalled();
|
||||
|
||||
// The class on the contact will now have switched.
|
||||
expect($contacts.hasClass('to')).toBeFalsy();
|
||||
expect($contacts.hasClass('both')).toBeTruthy();
|
||||
done();
|
||||
const sendIQ = _converse.connection.sendIQ;
|
||||
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
|
||||
sent_stanza = iq;
|
||||
IQ_id = sendIQ.bind(this)(iq, callback, errback);
|
||||
});
|
||||
|
||||
cbview.el.querySelector('.add-contact').click()
|
||||
modal = _converse.rosterview.add_contact_modal;
|
||||
await test_utils.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||
spyOn(modal, "addContactFromForm").and.callThrough();
|
||||
modal.delegateEvents();
|
||||
|
||||
// Fill in the form and submit
|
||||
const form = modal.el.querySelector('form.add-xmpp-contact');
|
||||
form.querySelector('input').value = 'contact@example.org';
|
||||
form.querySelector('[type="submit"]').click();
|
||||
|
||||
/* In preparation for being able to render the contact in the
|
||||
* user's client interface and for the server to keep track of the
|
||||
* subscription, the user's client SHOULD perform a "roster set"
|
||||
* for the new roster item.
|
||||
*/
|
||||
expect(modal.addContactFromForm).toHaveBeenCalled();
|
||||
expect(_converse.roster.addAndSubscribe).toHaveBeenCalled();
|
||||
expect(_converse.roster.addContactToRoster).toHaveBeenCalled();
|
||||
|
||||
/* _converse request consists of sending an IQ
|
||||
* stanza of type='set' containing a <query/> element qualified by
|
||||
* the 'jabber:iq:roster' namespace, which in turn contains an
|
||||
* <item/> element that defines the new roster item; the <item/>
|
||||
* element MUST possess a 'jid' attribute, MAY possess a 'name'
|
||||
* attribute, MUST NOT possess a 'subscription' attribute, and MAY
|
||||
* contain one or more <group/> child elements:
|
||||
*
|
||||
* <iq type='set' id='set1'>
|
||||
* <query xmlns='jabber:iq:roster'>
|
||||
* <item
|
||||
* jid='contact@example.org'
|
||||
* name='MyContact'>
|
||||
* <group>MyBuddies</group>
|
||||
* </item>
|
||||
* </query>
|
||||
* </iq>
|
||||
*/
|
||||
expect(_converse.roster.sendContactAddIQ).toHaveBeenCalled();
|
||||
expect(sent_stanza.toLocaleString()).toBe(
|
||||
`<iq id="${IQ_id}" type="set" xmlns="jabber:client">`+
|
||||
`<query xmlns="jabber:iq:roster">`+
|
||||
`<item jid="contact@example.org" name="contact@example.org"/>`+
|
||||
`</query>`+
|
||||
`</iq>`
|
||||
);
|
||||
/* As a result, the user's server (1) MUST initiate a roster push
|
||||
* for the new roster item to all available resources associated
|
||||
* with _converse user that have requested the roster, setting the
|
||||
* 'subscription' attribute to a value of "none"; and (2) MUST
|
||||
* reply to the sending resource with an IQ result indicating the
|
||||
* success of the roster set:
|
||||
*
|
||||
* <iq type='set'>
|
||||
* <query xmlns='jabber:iq:roster'>
|
||||
* <item
|
||||
* jid='contact@example.org'
|
||||
* subscription='none'
|
||||
* name='MyContact'>
|
||||
* <group>MyBuddies</group>
|
||||
* </item>
|
||||
* </query>
|
||||
* </iq>
|
||||
*/
|
||||
const create = _converse.roster.create;
|
||||
const sent_stanzas = [];
|
||||
spyOn(_converse.connection, 'send').and.callFake(function (stanza) {
|
||||
sent_stanza = stanza;
|
||||
sent_stanzas.push(stanza.toLocaleString());
|
||||
});
|
||||
spyOn(_converse.roster, 'create').and.callFake(function () {
|
||||
contact = create.apply(_converse.roster, arguments);
|
||||
spyOn(contact, 'subscribe').and.callThrough();
|
||||
return contact;
|
||||
});
|
||||
stanza = $iq({'type': 'set'}).c('query', {'xmlns': 'jabber:iq:roster'})
|
||||
.c('item', {
|
||||
'jid': 'contact@example.org',
|
||||
'subscription': 'none',
|
||||
'name': 'contact@example.org'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
/* <iq type='result' id='set1'/>
|
||||
*/
|
||||
stanza = $iq({'type': 'result', 'id':IQ_id});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
await test_utils.waitUntil(() => _converse.roster.create.calls.count());
|
||||
|
||||
// A contact should now have been created
|
||||
expect(_converse.roster.get('contact@example.org') instanceof _converse.RosterContact).toBeTruthy();
|
||||
expect(contact.get('jid')).toBe('contact@example.org');
|
||||
expect(_converse.api.vcard.get).toHaveBeenCalled();
|
||||
|
||||
/* To subscribe to the contact's presence information,
|
||||
* the user's client MUST send a presence stanza of
|
||||
* type='subscribe' to the contact:
|
||||
*
|
||||
* <presence to='contact@example.org' type='subscribe'/>
|
||||
*/
|
||||
await test_utils.waitUntil(() => sent_stanzas.filter(s => s.match('presence')));
|
||||
expect(contact.subscribe).toHaveBeenCalled();
|
||||
expect(sent_stanza.toLocaleString()).toBe( // Strophe adds the xmlns attr (although not in spec)
|
||||
`<presence to="contact@example.org" type="subscribe" xmlns="jabber:client">`+
|
||||
`<nick xmlns="http://jabber.org/protocol/nick">Max Mustermann</nick>`+
|
||||
`</presence>`
|
||||
);
|
||||
/* As a result, the user's server MUST initiate a second roster
|
||||
* push to all of the user's available resources that have
|
||||
* requested the roster, setting the contact to the pending
|
||||
* sub-state of the 'none' subscription state; _converse pending
|
||||
* sub-state is denoted by the inclusion of the ask='subscribe'
|
||||
* attribute in the roster item:
|
||||
*
|
||||
* <iq type='set'>
|
||||
* <query xmlns='jabber:iq:roster'>
|
||||
* <item
|
||||
* jid='contact@example.org'
|
||||
* subscription='none'
|
||||
* ask='subscribe'
|
||||
* name='MyContact'>
|
||||
* <group>MyBuddies</group>
|
||||
* </item>
|
||||
* </query>
|
||||
* </iq>
|
||||
*/
|
||||
spyOn(_converse.roster, "updateContact").and.callThrough();
|
||||
stanza = $iq({'type': 'set', 'from': _converse.bare_jid})
|
||||
.c('query', {'xmlns': 'jabber:iq:roster'})
|
||||
.c('item', {
|
||||
'jid': 'contact@example.org',
|
||||
'subscription': 'none',
|
||||
'ask': 'subscribe',
|
||||
'name': 'contact@example.org'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
expect(_converse.roster.updateContact).toHaveBeenCalled();
|
||||
// Check that the user is now properly shown as a pending
|
||||
// contact in the roster.
|
||||
await test_utils.waitUntil(function () {
|
||||
var $header = $('a:contains("Pending contacts")');
|
||||
var $contacts = $header.parent().find('li:visible');
|
||||
return $contacts.length;
|
||||
}, 600);
|
||||
|
||||
var $header = $('a:contains("Pending contacts")');
|
||||
var $contacts = $header.parent().find('li');
|
||||
expect($contacts.length).toBe(1);
|
||||
expect($contacts.is(':visible')).toBeTruthy();
|
||||
|
||||
spyOn(contact, "ackSubscribe").and.callThrough();
|
||||
/* Here we assume the "happy path" that the contact
|
||||
* approves the subscription request
|
||||
*
|
||||
* <presence
|
||||
* to='user@example.com'
|
||||
* from='contact@example.org'
|
||||
* type='subscribed'/>
|
||||
*/
|
||||
stanza = $pres({
|
||||
'to': _converse.bare_jid,
|
||||
'from': 'contact@example.org',
|
||||
'type': 'subscribed'
|
||||
});
|
||||
sent_stanza = ""; // Reset
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
/* Upon receiving the presence stanza of type "subscribed",
|
||||
* the user SHOULD acknowledge receipt of that
|
||||
* subscription state notification by sending a presence
|
||||
* stanza of type "subscribe".
|
||||
*/
|
||||
expect(contact.ackSubscribe).toHaveBeenCalled();
|
||||
expect(sent_stanza.toLocaleString()).toBe( // Strophe adds the xmlns attr (although not in spec)
|
||||
`<presence to="contact@example.org" type="subscribe" xmlns="jabber:client"/>`
|
||||
);
|
||||
|
||||
/* The user's server MUST initiate a roster push to all of the user's
|
||||
* available resources that have requested the roster,
|
||||
* containing an updated roster item for the contact with
|
||||
* the 'subscription' attribute set to a value of "to";
|
||||
*
|
||||
* <iq type='set'>
|
||||
* <query xmlns='jabber:iq:roster'>
|
||||
* <item
|
||||
* jid='contact@example.org'
|
||||
* subscription='to'
|
||||
* name='MyContact'>
|
||||
* <group>MyBuddies</group>
|
||||
* </item>
|
||||
* </query>
|
||||
* </iq>
|
||||
*/
|
||||
IQ_id = _converse.connection.getUniqueId('roster');
|
||||
stanza = $iq({'type': 'set', 'id': IQ_id})
|
||||
.c('query', {'xmlns': 'jabber:iq:roster'})
|
||||
.c('item', {
|
||||
'jid': 'contact@example.org',
|
||||
'subscription': 'to',
|
||||
'name': 'contact@example.org'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
// Check that the IQ set was acknowledged.
|
||||
expect(sent_stanza.toLocaleString()).toBe( // Strophe adds the xmlns attr (although not in spec)
|
||||
`<iq from="dummy@localhost/resource" id="${IQ_id}" type="result" xmlns="jabber:client"/>`
|
||||
);
|
||||
expect(_converse.roster.updateContact).toHaveBeenCalled();
|
||||
|
||||
// The contact should now be visible as an existing
|
||||
// contact (but still offline).
|
||||
await test_utils.waitUntil(function () {
|
||||
var $header = $('a:contains("My contacts")');
|
||||
var $contacts = $header.parent().find('li:visible');
|
||||
return $contacts.length;
|
||||
}, 600);
|
||||
$header = $('a:contains("My contacts")');
|
||||
expect($header.length).toBe(1);
|
||||
expect($header.is(":visible")).toBeTruthy();
|
||||
$contacts = $header.parent().find('li');
|
||||
expect($contacts.length).toBe(1);
|
||||
// Check that it has the right classes and text
|
||||
expect($contacts.hasClass('to')).toBeTruthy();
|
||||
expect($contacts.hasClass('both')).toBeFalsy();
|
||||
expect($contacts.hasClass('current-xmpp-contact')).toBeTruthy();
|
||||
expect($contacts.text().trim()).toBe('Contact');
|
||||
expect(contact.presence.get('show')).toBe('offline');
|
||||
|
||||
/* <presence
|
||||
* from='contact@example.org/resource'
|
||||
* to='user@example.com/resource'/>
|
||||
*/
|
||||
stanza = $pres({'to': _converse.bare_jid, 'from': 'contact@example.org/resource'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
// Now the contact should also be online.
|
||||
expect(contact.presence.get('show')).toBe('online');
|
||||
|
||||
/* Section 8.3. Creating a Mutual Subscription
|
||||
*
|
||||
* If the contact wants to create a mutual subscription,
|
||||
* the contact MUST send a subscription request to the
|
||||
* user.
|
||||
*
|
||||
* <presence from='contact@example.org' to='user@example.com' type='subscribe'/>
|
||||
*/
|
||||
spyOn(contact, 'authorize').and.callThrough();
|
||||
spyOn(_converse.roster, 'handleIncomingSubscription').and.callThrough();
|
||||
stanza = $pres({
|
||||
'to': _converse.bare_jid,
|
||||
'from': 'contact@example.org/resource',
|
||||
'type': 'subscribe'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
expect(_converse.roster.handleIncomingSubscription).toHaveBeenCalled();
|
||||
|
||||
/* The user's client MUST send a presence stanza of type
|
||||
* "subscribed" to the contact in order to approve the
|
||||
* subscription request.
|
||||
*
|
||||
* <presence to='contact@example.org' type='subscribed'/>
|
||||
*/
|
||||
expect(contact.authorize).toHaveBeenCalled();
|
||||
expect(sent_stanza.toLocaleString()).toBe(
|
||||
`<presence to="contact@example.org" type="subscribed" xmlns="jabber:client"/>`
|
||||
);
|
||||
|
||||
/* As a result, the user's server MUST initiate a
|
||||
* roster push containing a roster item for the
|
||||
* contact with the 'subscription' attribute set to
|
||||
* a value of "both".
|
||||
*
|
||||
* <iq type='set'>
|
||||
* <query xmlns='jabber:iq:roster'>
|
||||
* <item
|
||||
* jid='contact@example.org'
|
||||
* subscription='both'
|
||||
* name='MyContact'>
|
||||
* <group>MyBuddies</group>
|
||||
* </item>
|
||||
* </query>
|
||||
* </iq>
|
||||
*/
|
||||
stanza = $iq({'type': 'set'}).c('query', {'xmlns': 'jabber:iq:roster'})
|
||||
.c('item', {
|
||||
'jid': 'contact@example.org',
|
||||
'subscription': 'both',
|
||||
'name': 'contact@example.org'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
expect(_converse.roster.updateContact).toHaveBeenCalled();
|
||||
|
||||
// The class on the contact will now have switched.
|
||||
expect($contacts.hasClass('to')).toBeFalsy();
|
||||
expect($contacts.hasClass('both')).toBeTruthy();
|
||||
done();
|
||||
|
||||
}));
|
||||
|
||||
it("Alternate Flow: Contact Declines Subscription Request",
|
||||
|
@ -466,7 +456,7 @@
|
|||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'],
|
||||
{ roster_groups: false },
|
||||
function (done, _converse) {
|
||||
async function (done, _converse) {
|
||||
|
||||
var sent_IQ, IQ_id, jid = 'annegreet.gomez@localhost';
|
||||
test_utils.openControlBox(_converse);
|
||||
|
@ -480,51 +470,46 @@
|
|||
sent_IQ = iq;
|
||||
IQ_id = sendIQ.bind(this)(iq, callback, errback);
|
||||
});
|
||||
return test_utils.waitUntil(function () {
|
||||
var $header = $('a:contains("My contacts")');
|
||||
var $contacts = $header.parent().find('li');
|
||||
return $contacts.length;
|
||||
}, 600).then(function () {
|
||||
const $header = $('a:contains("My contacts")');
|
||||
await test_utils.waitUntil(() => $header.parent().find('li').length);
|
||||
|
||||
// remove the first user
|
||||
$header.parent().find('li .remove-xmpp-contact').get(0).click();
|
||||
expect(window.confirm).toHaveBeenCalled();
|
||||
|
||||
var $header = $('a:contains("My contacts")');
|
||||
// remove the first user
|
||||
$header.parent().find('li .remove-xmpp-contact').get(0).click();
|
||||
expect(window.confirm).toHaveBeenCalled();
|
||||
/* Section 8.6 Removing a Roster Item and Cancelling All
|
||||
* Subscriptions
|
||||
*
|
||||
* First the user is removed from the roster
|
||||
* Because there may be many steps involved in completely
|
||||
* removing a roster item and cancelling subscriptions in
|
||||
* both directions, the roster management protocol includes
|
||||
* a "shortcut" method for doing so. The process may be
|
||||
* initiated no matter what the current subscription state
|
||||
* is by sending a roster set containing an item for the
|
||||
* contact with the 'subscription' attribute set to a value
|
||||
* of "remove":
|
||||
*
|
||||
* <iq type='set' id='remove1'>
|
||||
* <query xmlns='jabber:iq:roster'>
|
||||
* <item jid='contact@example.org' subscription='remove'/>
|
||||
* </query>
|
||||
* </iq>
|
||||
*/
|
||||
expect(sent_IQ.toLocaleString()).toBe(
|
||||
`<iq id="${IQ_id}" type="set" xmlns="jabber:client">`+
|
||||
`<query xmlns="jabber:iq:roster">`+
|
||||
`<item jid="annegreet.gomez@localhost" subscription="remove"/>`+
|
||||
`</query>`+
|
||||
`</iq>`);
|
||||
|
||||
/* Section 8.6 Removing a Roster Item and Cancelling All
|
||||
* Subscriptions
|
||||
*
|
||||
* First the user is removed from the roster
|
||||
* Because there may be many steps involved in completely
|
||||
* removing a roster item and cancelling subscriptions in
|
||||
* both directions, the roster management protocol includes
|
||||
* a "shortcut" method for doing so. The process may be
|
||||
* initiated no matter what the current subscription state
|
||||
* is by sending a roster set containing an item for the
|
||||
* contact with the 'subscription' attribute set to a value
|
||||
* of "remove":
|
||||
*
|
||||
* <iq type='set' id='remove1'>
|
||||
* <query xmlns='jabber:iq:roster'>
|
||||
* <item jid='contact@example.org' subscription='remove'/>
|
||||
* </query>
|
||||
* </iq>
|
||||
*/
|
||||
expect(sent_IQ.toLocaleString()).toBe(
|
||||
`<iq id="${IQ_id}" type="set" xmlns="jabber:client">`+
|
||||
`<query xmlns="jabber:iq:roster">`+
|
||||
`<item jid="annegreet.gomez@localhost" subscription="remove"/>`+
|
||||
`</query>`+
|
||||
`</iq>`);
|
||||
|
||||
// Receive confirmation from the contact's server
|
||||
// <iq type='result' id='remove1'/>
|
||||
var stanza = $iq({'type': 'result', 'id':IQ_id});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
// Our contact has now been removed
|
||||
expect(typeof _converse.roster.get(jid) === "undefined").toBeTruthy();
|
||||
done();
|
||||
});
|
||||
// Receive confirmation from the contact's server
|
||||
// <iq type='result' id='remove1'/>
|
||||
const stanza = $iq({'type': 'result', 'id':IQ_id});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
// Our contact has now been removed
|
||||
await test_utils.waitUntil(() => typeof _converse.roster.get(jid) === "undefined");
|
||||
done();
|
||||
}));
|
||||
|
||||
it("Receiving a subscription request", mock.initConverseWithPromises(
|
||||
|
|
225
spec/roster.js
225
spec/roster.js
|
@ -1,14 +1,16 @@
|
|||
(function (root, factory) {
|
||||
define(["jquery", "jasmine", "mock", "test-utils"], factory);
|
||||
} (this, function ($, jasmine, mock, test_utils) {
|
||||
var _ = converse.env._;
|
||||
var Strophe = converse.env.Strophe;
|
||||
var $pres = converse.env.$pres;
|
||||
var $msg = converse.env.$msg;
|
||||
var $iq = converse.env.$iq;
|
||||
var u = converse.env.utils;
|
||||
const $iq = converse.env.$iq;
|
||||
const $msg = converse.env.$msg;
|
||||
const $pres = converse.env.$pres;
|
||||
const Strophe = converse.env.Strophe;
|
||||
const _ = converse.env._;
|
||||
const sizzle = converse.env.sizzle;
|
||||
const u = converse.env.utils;
|
||||
|
||||
var checkHeaderToggling = function (group) {
|
||||
|
||||
const checkHeaderToggling = function (group) {
|
||||
var $group = $(group);
|
||||
var toggle = group.querySelector('a.group-toggle');
|
||||
expect(u.isVisible($group[0])).toBeTruthy();
|
||||
|
@ -38,57 +40,58 @@
|
|||
it("supports roster versioning",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
async function (done, _converse) {
|
||||
|
||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||
test_utils.waitUntil(
|
||||
let node = await test_utils.waitUntil(
|
||||
() => _.filter(IQ_stanzas, iq => iq.nodeTree.querySelector('iq query[xmlns="jabber:iq:roster"]')).pop()
|
||||
).then(node => {
|
||||
let stanza = node.nodeTree;
|
||||
expect(_converse.roster.data.get('version')).toBeUndefined();
|
||||
expect(node.toLocaleString()).toBe(
|
||||
`<iq id="${stanza.getAttribute('id')}" type="get" xmlns="jabber:client">`+
|
||||
`<query xmlns="jabber:iq:roster"/>`+
|
||||
`</iq>`);
|
||||
let result = $iq({
|
||||
'to': _converse.connection.jid,
|
||||
'type': 'result',
|
||||
'id': stanza.getAttribute('id')
|
||||
}).c('query', {
|
||||
'xmlns': 'jabber:iq:roster',
|
||||
'ver': 'ver7'
|
||||
}).c('item', {'jid': 'nurse@example.com'}).up()
|
||||
.c('item', {'jid': 'romeo@example.com'})
|
||||
_converse.connection._dataRecv(test_utils.createRequest(result));
|
||||
expect(_converse.roster.data.get('version')).toBe('ver7');
|
||||
expect(_converse.roster.models.length).toBe(2);
|
||||
);
|
||||
let stanza = node.nodeTree;
|
||||
expect(_converse.roster.data.get('version')).toBeUndefined();
|
||||
expect(node.toLocaleString()).toBe(
|
||||
`<iq id="${stanza.getAttribute('id')}" type="get" xmlns="jabber:client">`+
|
||||
`<query xmlns="jabber:iq:roster"/>`+
|
||||
`</iq>`);
|
||||
let result = $iq({
|
||||
'to': _converse.connection.jid,
|
||||
'type': 'result',
|
||||
'id': stanza.getAttribute('id')
|
||||
}).c('query', {
|
||||
'xmlns': 'jabber:iq:roster',
|
||||
'ver': 'ver7'
|
||||
}).c('item', {'jid': 'nurse@example.com'}).up()
|
||||
.c('item', {'jid': 'romeo@example.com'})
|
||||
_converse.connection._dataRecv(test_utils.createRequest(result));
|
||||
|
||||
_converse.roster.fetchFromServer();
|
||||
node = _converse.connection.IQ_stanzas.pop();
|
||||
stanza = node.nodeTree;
|
||||
expect(node.toLocaleString()).toBe(
|
||||
`<iq id="${stanza.getAttribute('id')}" type="get" xmlns="jabber:client">`+
|
||||
`<query ver="ver7" xmlns="jabber:iq:roster"/>`+
|
||||
`</iq>`);
|
||||
await test_utils.waitUntil(() => _converse.roster.models.length > 1);
|
||||
expect(_converse.roster.data.get('version')).toBe('ver7');
|
||||
expect(_converse.roster.models.length).toBe(2);
|
||||
|
||||
result = $iq({
|
||||
'to': _converse.connection.jid,
|
||||
'type': 'result',
|
||||
'id': stanza.getAttribute('id')
|
||||
});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(result));
|
||||
_converse.roster.fetchFromServer();
|
||||
node = _converse.connection.IQ_stanzas.pop();
|
||||
stanza = node.nodeTree;
|
||||
expect(node.toLocaleString()).toBe(
|
||||
`<iq id="${stanza.getAttribute('id')}" type="get" xmlns="jabber:client">`+
|
||||
`<query ver="ver7" xmlns="jabber:iq:roster"/>`+
|
||||
`</iq>`);
|
||||
|
||||
const roster_push = $iq({
|
||||
'to': _converse.connection.jid,
|
||||
'type': 'set',
|
||||
}).c('query', {'xmlns': 'jabber:iq:roster', 'ver': 'ver34'})
|
||||
.c('item', {'jid': 'romeo@example.com', 'subscription': 'remove'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(roster_push));
|
||||
expect(_converse.roster.data.get('version')).toBe('ver34');
|
||||
expect(_converse.roster.models.length).toBe(1);
|
||||
expect(_converse.roster.at(0).get('jid')).toBe('nurse@example.com');
|
||||
done();
|
||||
result = $iq({
|
||||
'to': _converse.connection.jid,
|
||||
'type': 'result',
|
||||
'id': stanza.getAttribute('id')
|
||||
});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(result));
|
||||
|
||||
const roster_push = $iq({
|
||||
'to': _converse.connection.jid,
|
||||
'type': 'set',
|
||||
}).c('query', {'xmlns': 'jabber:iq:roster', 'ver': 'ver34'})
|
||||
.c('item', {'jid': 'romeo@example.com', 'subscription': 'remove'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(roster_push));
|
||||
expect(_converse.roster.data.get('version')).toBe('ver34');
|
||||
expect(_converse.roster.models.length).toBe(1);
|
||||
expect(_converse.roster.at(0).get('jid')).toBe('nurse@example.com');
|
||||
done();
|
||||
}));
|
||||
|
||||
describe("The live filter", function () {
|
||||
|
@ -549,17 +552,15 @@
|
|||
it("can be collapsed under their own header",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
async function (done, _converse) {
|
||||
|
||||
_addContacts(_converse);
|
||||
test_utils.waitUntil(function () {
|
||||
return $(_converse.rosterview.el).find('.roster-group:visible li').length;
|
||||
}, 500).then(function () {
|
||||
checkHeaderToggling.apply(
|
||||
_converse,
|
||||
[_converse.rosterview.get('Pending contacts').el]
|
||||
).then(done);
|
||||
});
|
||||
await test_utils.waitUntil(() => $(_converse.rosterview.el).find('.roster-group:visible li').length, 1000);
|
||||
await checkHeaderToggling.apply(
|
||||
_converse,
|
||||
[_converse.rosterview.get('Pending contacts').el]
|
||||
);
|
||||
done();
|
||||
}));
|
||||
|
||||
it("can be added to the roster",
|
||||
|
@ -662,10 +663,10 @@
|
|||
it("do not have a header if there aren't any",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
async function (done, _converse) {
|
||||
|
||||
test_utils.openControlBox();
|
||||
var name = mock.pend_names[0];
|
||||
const name = mock.pend_names[0];
|
||||
_converse.roster.create({
|
||||
jid: name.replace(/ /g,'.').toLowerCase() + '@localhost',
|
||||
subscription: 'none',
|
||||
|
@ -676,17 +677,18 @@
|
|||
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback) {
|
||||
if (typeof callback === "function") { return callback(); }
|
||||
});
|
||||
test_utils.waitUntil(function () {
|
||||
await test_utils.waitUntil(function () {
|
||||
var $pending_contacts = $(_converse.rosterview.get('Pending contacts').el);
|
||||
return $pending_contacts.is(':visible') && $pending_contacts.find('li:visible').length;
|
||||
}, 700).then(function () {
|
||||
$(_converse.rosterview.el).find(".pending-contact-name:contains('"+name+"')")
|
||||
.parent().siblings('.remove-xmpp-contact')[0].click();
|
||||
expect(window.confirm).toHaveBeenCalled();
|
||||
expect(_converse.connection.sendIQ).toHaveBeenCalled();
|
||||
expect(u.isVisible(_converse.rosterview.get('Pending contacts').el)).toEqual(false);
|
||||
done();
|
||||
});
|
||||
}, 700)
|
||||
|
||||
$(_converse.rosterview.el).find(".pending-contact-name:contains('"+name+"')")
|
||||
.parent().siblings('.remove-xmpp-contact')[0].click();
|
||||
expect(window.confirm).toHaveBeenCalled();
|
||||
expect(_converse.connection.sendIQ).toHaveBeenCalled();
|
||||
|
||||
await test_utils.waitUntil(() => !u.isVisible(_converse.rosterview.get('Pending contacts').el));
|
||||
done();
|
||||
}));
|
||||
|
||||
it("is shown when a new private message is received",
|
||||
|
@ -822,42 +824,39 @@
|
|||
it("can be removed by the user",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
async function (done, _converse) {
|
||||
|
||||
var sent_IQ;
|
||||
_addContacts(_converse);
|
||||
test_utils.waitUntil(function () {
|
||||
return $(_converse.rosterview.el).find('li').length;
|
||||
}, 500).then(function () {
|
||||
var name = mock.cur_names[0];
|
||||
var jid = name.replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
var contact = _converse.roster.get(jid);
|
||||
spyOn(window, 'confirm').and.returnValue(true);
|
||||
spyOn(contact, 'removeFromRoster').and.callThrough();
|
||||
await test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('li').length);
|
||||
const name = mock.cur_names[0];
|
||||
const jid = name.replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
const contact = _converse.roster.get(jid);
|
||||
spyOn(window, 'confirm').and.returnValue(true);
|
||||
spyOn(contact, 'removeFromRoster').and.callThrough();
|
||||
|
||||
var sendIQ = _converse.connection.sendIQ;
|
||||
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
|
||||
sent_IQ = iq;
|
||||
callback();
|
||||
});
|
||||
$(_converse.rosterview.el).find(".open-chat:contains('"+name+"')")
|
||||
.parent().find('.remove-xmpp-contact')[0].click();
|
||||
|
||||
expect(window.confirm).toHaveBeenCalled();
|
||||
expect(sent_IQ.toLocaleString()).toBe(
|
||||
`<iq type="set" xmlns="jabber:client">`+
|
||||
`<query xmlns="jabber:iq:roster"><item jid="max.frankfurter@localhost" subscription="remove"/></query>`+
|
||||
`</iq>`);
|
||||
expect(contact.removeFromRoster).toHaveBeenCalled();
|
||||
expect($(_converse.rosterview.el).find(".open-chat:contains('"+name+"')").length).toEqual(0);
|
||||
done();
|
||||
const sendIQ = _converse.connection.sendIQ;
|
||||
let sent_IQ;
|
||||
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
|
||||
sent_IQ = iq;
|
||||
callback();
|
||||
});
|
||||
$(_converse.rosterview.el).find(".open-chat:contains('"+name+"')")
|
||||
.parent().find('.remove-xmpp-contact')[0].click();
|
||||
|
||||
expect(window.confirm).toHaveBeenCalled();
|
||||
expect(sent_IQ.toLocaleString()).toBe(
|
||||
`<iq type="set" xmlns="jabber:client">`+
|
||||
`<query xmlns="jabber:iq:roster"><item jid="max.frankfurter@localhost" subscription="remove"/></query>`+
|
||||
`</iq>`);
|
||||
expect(contact.removeFromRoster).toHaveBeenCalled();
|
||||
await test_utils.waitUntil(() => $(_converse.rosterview.el).find(".open-chat:contains('"+name+"')").length === 0);
|
||||
done();
|
||||
}));
|
||||
|
||||
it("do not have a header if there aren't any",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
async function (done, _converse) {
|
||||
|
||||
test_utils.openControlBox();
|
||||
var name = mock.cur_names[0];
|
||||
|
@ -868,24 +867,20 @@
|
|||
ask: null,
|
||||
fullname: name
|
||||
});
|
||||
test_utils.waitUntil(function () {
|
||||
return $(_converse.rosterview.el).find('.roster-group:visible li').length;
|
||||
}, 700).then(function () {
|
||||
spyOn(window, 'confirm').and.returnValue(true);
|
||||
spyOn(contact, 'removeFromRoster').and.callThrough();
|
||||
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback) {
|
||||
if (typeof callback === "function") { return callback(); }
|
||||
});
|
||||
|
||||
expect($(_converse.rosterview.el).find('.roster-group').css('display')).toEqual('block');
|
||||
$(_converse.rosterview.el).find(".open-chat:contains('"+name+"')")
|
||||
.parent().find('.remove-xmpp-contact')[0].click();
|
||||
expect(window.confirm).toHaveBeenCalled();
|
||||
expect(_converse.connection.sendIQ).toHaveBeenCalled();
|
||||
expect(contact.removeFromRoster).toHaveBeenCalled();
|
||||
expect($(_converse.rosterview.el).find('.roster-group').length).toEqual(0);
|
||||
done();
|
||||
await test_utils.waitUntil(() => $(_converse.rosterview.el).find('.roster-group:visible li').length, 1000);
|
||||
spyOn(window, 'confirm').and.returnValue(true);
|
||||
spyOn(contact, 'removeFromRoster').and.callThrough();
|
||||
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback) {
|
||||
if (typeof callback === "function") { return callback(); }
|
||||
});
|
||||
expect($(_converse.rosterview.el).find('.roster-group').css('display')).toEqual('block');
|
||||
$(_converse.rosterview.el).find(".open-chat:contains('"+name+"')")
|
||||
.parent().find('.remove-xmpp-contact')[0].click();
|
||||
expect(window.confirm).toHaveBeenCalled();
|
||||
expect(_converse.connection.sendIQ).toHaveBeenCalled();
|
||||
expect(contact.removeFromRoster).toHaveBeenCalled();
|
||||
await test_utils.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length === 0);
|
||||
done();
|
||||
}));
|
||||
|
||||
it("can change their status to online and be sorted alphabetically",
|
||||
|
|
|
@ -533,6 +533,9 @@ converse.plugins.add('converse-chatview', {
|
|||
prev_msg_date = _.isNull(prev_msg_el) ? null : prev_msg_el.getAttribute('data-isodate'),
|
||||
next_msg_date = next_msg_el.getAttribute('data-isodate');
|
||||
|
||||
if (_.isNull(prev_msg_date) && _.isNull(next_msg_date)) {
|
||||
return;
|
||||
}
|
||||
if (_.isNull(prev_msg_date) || moment(next_msg_date).isAfter(prev_msg_date, 'day')) {
|
||||
const day_date = moment(next_msg_date).startOf('day');
|
||||
next_msg_el.insertAdjacentHTML('beforeBegin',
|
||||
|
@ -722,8 +725,15 @@ converse.plugins.add('converse-chatview', {
|
|||
*/
|
||||
const view = new _converse.MessageView({'model': message});
|
||||
await view.render();
|
||||
|
||||
this.clearChatStateNotification(message);
|
||||
if (!view.el.innerHTML) {
|
||||
// An "inactive" CSN message (for example) will have an
|
||||
// empty body. No need to then continue.
|
||||
return _converse.log(
|
||||
"Not inserting a message with empty element",
|
||||
Strophe.LogLevel.INFO
|
||||
);
|
||||
}
|
||||
this.insertMessage(view);
|
||||
this.insertDayIndicator(view.el);
|
||||
this.setScrollPosition(view.el);
|
||||
|
|
|
@ -60,6 +60,10 @@ converse.plugins.add('converse-message-view', {
|
|||
if (this.model.isOnlyChatStateNotification()) {
|
||||
this.renderChatStateNotification()
|
||||
} else if (this.model.get('file') && !this.model.get('oob_url')) {
|
||||
if (!this.model.file) {
|
||||
_converse.log("Attempted to render a file upload message with no file data");
|
||||
return this.el;
|
||||
}
|
||||
this.renderFileUploadProgresBar();
|
||||
} else if (this.model.get('type') === 'error') {
|
||||
this.renderErrorMessage();
|
||||
|
@ -204,7 +208,7 @@ converse.plugins.add('converse-message-view', {
|
|||
renderFileUploadProgresBar () {
|
||||
const msg = u.stringToElement(tpl_file_progress(
|
||||
_.extend(this.model.toJSON(), {
|
||||
'filesize': filesize(this.model.get('file').size),
|
||||
'filesize': filesize(this.model.file.size),
|
||||
})));
|
||||
this.replaceElement(msg);
|
||||
this.renderAvatar();
|
||||
|
|
|
@ -367,16 +367,14 @@ converse.plugins.add('converse-muc-views', {
|
|||
updateRoomsList () {
|
||||
/* Send an IQ stanza to the server asking for all groupchats
|
||||
*/
|
||||
_converse.connection.sendIQ(
|
||||
$iq({
|
||||
'to': this.model.get('muc_domain'),
|
||||
'from': _converse.connection.jid,
|
||||
'type': "get"
|
||||
}).c("query", {xmlns: Strophe.NS.DISCO_ITEMS}),
|
||||
this.onRoomsFound.bind(this),
|
||||
this.informNoRoomsFound.bind(this),
|
||||
5000
|
||||
);
|
||||
const iq = $iq({
|
||||
'to': this.model.get('muc_domain'),
|
||||
'from': _converse.connection.jid,
|
||||
'type': "get"
|
||||
}).c("query", {xmlns: Strophe.NS.DISCO_ITEMS});
|
||||
_converse.api.sendIQ(iq)
|
||||
.then(iq => this.onRoomsFound(iq))
|
||||
.catch(iq => this.informNoRoomsFound())
|
||||
},
|
||||
|
||||
showRooms (ev) {
|
||||
|
@ -805,7 +803,7 @@ converse.plugins.add('converse-muc-views', {
|
|||
const item = $build("item", {nick, role});
|
||||
const iq = $iq({to: groupchat, type: "set"}).c("query", {xmlns: Strophe.NS.MUC_ADMIN}).cnode(item.node);
|
||||
if (reason !== null) { iq.c("reason", reason); }
|
||||
return _converse.connection.sendIQ(iq, onSuccess, onError);
|
||||
return _converse.api.sendIQ(iq).then(onSuccess).catch(onError);
|
||||
},
|
||||
|
||||
verifyRoles (roles) {
|
||||
|
|
|
@ -68,10 +68,6 @@ converse.plugins.add('converse-chatboxes', {
|
|||
this.setVCard();
|
||||
if (this.get('file')) {
|
||||
this.on('change:put', this.uploadFile, this);
|
||||
|
||||
if (!_.includes([_converse.SUCCESS, _converse.FAILURE], this.get('upload'))) {
|
||||
this.getRequestSlotURL();
|
||||
}
|
||||
}
|
||||
if (this.isOnlyChatStateNotification()) {
|
||||
window.setTimeout(this.destroy.bind(this), 20000);
|
||||
|
@ -132,20 +128,20 @@ converse.plugins.add('converse-chatboxes', {
|
|||
*
|
||||
* https://xmpp.org/extensions/xep-0363.html#request
|
||||
*/
|
||||
const file = this.get('file');
|
||||
return new Promise((resolve, reject) => {
|
||||
const iq = converse.env.$iq({
|
||||
'from': _converse.jid,
|
||||
'to': this.get('slot_request_url'),
|
||||
'type': 'get'
|
||||
}).c('request', {
|
||||
'xmlns': Strophe.NS.HTTPUPLOAD,
|
||||
'filename': file.name,
|
||||
'size': file.size,
|
||||
'content-type': file.type
|
||||
})
|
||||
_converse.connection.sendIQ(iq, resolve, reject);
|
||||
});
|
||||
if (_.isNil(this.file)) {
|
||||
return Promise.reject(new Error("file is undefined"));
|
||||
}
|
||||
const iq = converse.env.$iq({
|
||||
'from': _converse.jid,
|
||||
'to': this.get('slot_request_url'),
|
||||
'type': 'get'
|
||||
}).c('request', {
|
||||
'xmlns': Strophe.NS.HTTPUPLOAD,
|
||||
'filename': this.file.name,
|
||||
'size': this.file.size,
|
||||
'content-type': this.file.type
|
||||
})
|
||||
return _converse.api.sendIQ(iq);
|
||||
},
|
||||
|
||||
async getRequestSlotURL () {
|
||||
|
@ -420,8 +416,8 @@ converse.plugins.add('converse-chatboxes', {
|
|||
|
||||
|
||||
async sendFiles (files) {
|
||||
const result = await _converse.api.disco.supports(Strophe.NS.HTTPUPLOAD, _converse.domain);
|
||||
const item = result.pop(),
|
||||
const result = await _converse.api.disco.supports(Strophe.NS.HTTPUPLOAD, _converse.domain),
|
||||
item = result.pop(),
|
||||
data = item.dataforms.where({'FORM_TYPE': {'value': Strophe.NS.HTTPUPLOAD, 'type': "hidden"}}).pop(),
|
||||
max_file_size = window.parseInt(_.get(data, 'attributes.max-file-size.value')),
|
||||
slot_request_url = _.get(item, 'id');
|
||||
|
@ -429,7 +425,7 @@ converse.plugins.add('converse-chatboxes', {
|
|||
if (!slot_request_url) {
|
||||
this.messages.create({
|
||||
'message': __("Sorry, looks like file upload is not supported by your server."),
|
||||
'type': 'error',
|
||||
'type': 'error'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -438,17 +434,20 @@ converse.plugins.add('converse-chatboxes', {
|
|||
return this.messages.create({
|
||||
'message': __('The size of your file, %1$s, exceeds the maximum allowed by your server, which is %2$s.',
|
||||
file.name, filesize(max_file_size)),
|
||||
'type': 'error',
|
||||
'type': 'error'
|
||||
});
|
||||
} else {
|
||||
this.messages.create(
|
||||
const message = this.messages.create(
|
||||
_.extend(
|
||||
this.getOutgoingMessageAttributes(), {
|
||||
'file': file,
|
||||
'progress': 0,
|
||||
'slot_request_url': slot_request_url
|
||||
})
|
||||
}), {'silent': true}
|
||||
);
|
||||
message.file = file;
|
||||
this.messages.trigger('add', message);
|
||||
message.getRequestSlotURL();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
|
|
@ -1641,6 +1641,7 @@ _converse.api = {
|
|||
*/
|
||||
'send' (stanza) {
|
||||
_converse.connection.send(stanza);
|
||||
_converse.emit('send', stanza);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1650,9 +1651,10 @@ _converse.api = {
|
|||
* @returns {Promise} A promise which resolves when we receive a `result` stanza
|
||||
* or is rejected when we receive an `error` stanza.
|
||||
*/
|
||||
'sendIQ' (stanza) {
|
||||
'sendIQ' (stanza, timeout) {
|
||||
return new Promise((resolve, reject) => {
|
||||
_converse.connection.sendIQ(stanza, resolve, reject, _converse.IQ_TIMEOUT);
|
||||
_converse.connection.sendIQ(stanza, resolve, reject, timeout || _converse.IQ_TIMEOUT);
|
||||
_converse.emit('send', stanza);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -99,9 +99,8 @@ function queryForArchivedMessages (_converse, options, callback, errback) {
|
|||
return true;
|
||||
}, Strophe.NS.MAM);
|
||||
|
||||
_converse.connection.sendIQ(
|
||||
stanza,
|
||||
function (iq) {
|
||||
_converse.api.sendIQ(stanza, _converse.message_archiving_timeout)
|
||||
.then(iq => {
|
||||
_converse.connection.deleteHandler(message_handler);
|
||||
if (_.isFunction(callback)) {
|
||||
const set = iq.querySelector('set');
|
||||
|
@ -112,13 +111,13 @@ function queryForArchivedMessages (_converse, options, callback, errback) {
|
|||
}
|
||||
callback(messages, rsm);
|
||||
}
|
||||
},
|
||||
function () {
|
||||
}).catch(e => {
|
||||
_converse.connection.deleteHandler(message_handler);
|
||||
if (_.isFunction(errback)) { errback.apply(this, arguments); }
|
||||
},
|
||||
_converse.message_archiving_timeout
|
||||
);
|
||||
if (_.isFunction(errback)) {
|
||||
errback.apply(this, arguments);
|
||||
}
|
||||
return;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
@ -333,7 +332,7 @@ converse.plugins.add('converse-mam', {
|
|||
message_archiving_timeout: 8000, // Time (in milliseconds) to wait before aborting MAM request
|
||||
});
|
||||
|
||||
_converse.onMAMError = function (model, iq) {
|
||||
_converse.onMAMError = function (iq) {
|
||||
if (iq.querySelectorAll('feature-not-implemented').length) {
|
||||
_converse.log(
|
||||
"Message Archive Management (XEP-0313) not supported by this server",
|
||||
|
@ -365,17 +364,14 @@ converse.plugins.add('converse-mam', {
|
|||
'xmlns':Strophe.NS.MAM,
|
||||
'default':_converse.message_archiving
|
||||
});
|
||||
_.each(preference.children, function (child) {
|
||||
stanza.cnode(child).up();
|
||||
});
|
||||
_converse.connection.sendIQ(stanza, _.partial(function (feature, iq) {
|
||||
// XXX: Strictly speaking, the server should respond with the updated prefs
|
||||
// (see example 18: https://xmpp.org/extensions/xep-0313.html#config)
|
||||
// but Prosody doesn't do this, so we don't rely on it.
|
||||
feature.save({'preferences': {'default':_converse.message_archiving}});
|
||||
}, feature),
|
||||
_converse.onMAMError
|
||||
);
|
||||
_.each(preference.children, child => stanza.cnode(child).up());
|
||||
|
||||
// XXX: Strictly speaking, the server should respond with the updated prefs
|
||||
// (see example 18: https://xmpp.org/extensions/xep-0313.html#config)
|
||||
// but Prosody doesn't do this, so we don't rely on it.
|
||||
_converse.api.sendIQ(stanza)
|
||||
.then(() => feature.save({'preferences': {'default':_converse.message_archiving}}))
|
||||
.catch(_converse.onMAMError);
|
||||
} else {
|
||||
feature.save({'preferences': {'default':_converse.message_archiving}});
|
||||
}
|
||||
|
@ -388,11 +384,9 @@ converse.plugins.add('converse-mam', {
|
|||
prefs['default'] !== _converse.message_archiving && // eslint-disable-line dot-notation
|
||||
!_.isUndefined(_converse.message_archiving) ) {
|
||||
// Ask the server for archiving preferences
|
||||
_converse.connection.sendIQ(
|
||||
$iq({'type': 'get'}).c('prefs', {'xmlns': Strophe.NS.MAM}),
|
||||
_.partial(_converse.onMAMPreferences, feature),
|
||||
_.partial(_converse.onMAMError, feature)
|
||||
);
|
||||
_converse.api.sendIQ($iq({'type': 'get'}).c('prefs', {'xmlns': Strophe.NS.MAM}))
|
||||
.then(_.partial(_converse.onMAMPreferences, feature))
|
||||
.catch(_converse.onMAMError);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -618,16 +618,10 @@ converse.plugins.add('converse-muc', {
|
|||
* Returns a promise which resolves once the response IQ
|
||||
* has been received.
|
||||
*/
|
||||
return new Promise((resolve, reject) => {
|
||||
_converse.connection.sendIQ(
|
||||
$iq({
|
||||
'to': this.get('jid'),
|
||||
'type': "get"
|
||||
}).c("query", {xmlns: Strophe.NS.MUC_OWNER}),
|
||||
resolve,
|
||||
reject
|
||||
);
|
||||
});
|
||||
return _converse.api.sendIQ(
|
||||
$iq({'to': this.get('jid'), 'type': "get"})
|
||||
.c("query", {xmlns: Strophe.NS.MUC_OWNER})
|
||||
);
|
||||
},
|
||||
|
||||
sendConfiguration (config, callback, errback) {
|
||||
|
@ -650,7 +644,7 @@ converse.plugins.add('converse-muc', {
|
|||
_.each(config || [], function (node) { iq.cnode(node).up(); });
|
||||
callback = _.isUndefined(callback) ? _.noop : _.partial(callback, iq.nodeTree);
|
||||
errback = _.isUndefined(errback) ? _.noop : _.partial(errback, iq.nodeTree);
|
||||
return _converse.connection.sendIQ(iq, callback, errback);
|
||||
return _converse.api.sendIQ(iq).then(callback).catch(errback);
|
||||
},
|
||||
|
||||
saveAffiliationAndRole (pres) {
|
||||
|
@ -683,19 +677,17 @@ converse.plugins.add('converse-muc', {
|
|||
* (Object) member: Map containing the member's jid and
|
||||
* optionally a reason and affiliation.
|
||||
*/
|
||||
return new Promise((resolve, reject) => {
|
||||
const iq = $iq({to: this.get('jid'), type: "set"})
|
||||
.c("query", {xmlns: Strophe.NS.MUC_ADMIN})
|
||||
.c("item", {
|
||||
'affiliation': member.affiliation || affiliation,
|
||||
'nick': member.nick,
|
||||
'jid': member.jid
|
||||
});
|
||||
if (!_.isUndefined(member.reason)) {
|
||||
iq.c("reason", member.reason);
|
||||
}
|
||||
_converse.connection.sendIQ(iq, resolve, reject);
|
||||
});
|
||||
const iq = $iq({to: this.get('jid'), type: "set"})
|
||||
.c("query", {xmlns: Strophe.NS.MUC_ADMIN})
|
||||
.c("item", {
|
||||
'affiliation': member.affiliation || affiliation,
|
||||
'nick': member.nick,
|
||||
'jid': member.jid
|
||||
});
|
||||
if (!_.isUndefined(member.reason)) {
|
||||
iq.c("reason", member.reason);
|
||||
}
|
||||
return _converse.api.sendIQ(iq);
|
||||
},
|
||||
|
||||
setAffiliations (members) {
|
||||
|
|
|
@ -329,7 +329,7 @@ converse.plugins.add('converse-roster', {
|
|||
const iq = $iq({type: 'set'})
|
||||
.c('query', {xmlns: Strophe.NS.ROSTER})
|
||||
.c('item', {jid: this.get('jid'), subscription: "remove"});
|
||||
_converse.connection.sendIQ(iq, callback, errback);
|
||||
_converse.api.sendIQ(iq).then(callback).catch(errback);
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
@ -451,7 +451,7 @@ converse.plugins.add('converse-roster', {
|
|||
this.addContactToRoster(jid, name, groups, attributes).then(handler, handler);
|
||||
},
|
||||
|
||||
sendContactAddIQ (jid, name, groups, callback, errback) {
|
||||
sendContactAddIQ (jid, name, groups) {
|
||||
/* Send an IQ stanza to the XMPP server to add a new roster contact.
|
||||
*
|
||||
* Parameters:
|
||||
|
@ -462,14 +462,14 @@ converse.plugins.add('converse-roster', {
|
|||
* (Function) errback - A function to call if an error occurred
|
||||
*/
|
||||
name = _.isEmpty(name)? jid: name;
|
||||
const iq = $iq({type: 'set'})
|
||||
.c('query', {xmlns: Strophe.NS.ROSTER})
|
||||
const iq = $iq({'type': 'set'})
|
||||
.c('query', {'xmlns': Strophe.NS.ROSTER})
|
||||
.c('item', { jid, name });
|
||||
_.each(groups, function (group) { iq.c('group').t(group).up(); });
|
||||
_converse.connection.sendIQ(iq, callback, errback);
|
||||
_.each(groups, group => iq.c('group').t(group).up());
|
||||
_converse.api.sendIQ(iq);
|
||||
},
|
||||
|
||||
addContactToRoster (jid, name, groups, attributes) {
|
||||
async addContactToRoster (jid, name, groups, attributes) {
|
||||
/* Adds a RosterContact instance to _converse.roster and
|
||||
* registers the contact on the XMPP server.
|
||||
* Returns a promise which is resolved once the XMPP server has
|
||||
|
@ -481,27 +481,22 @@ converse.plugins.add('converse-roster', {
|
|||
* (Array of Strings) groups - Any roster groups the user might belong to
|
||||
* (Object) attributes - Any additional attributes to be stored on the user's model.
|
||||
*/
|
||||
return new Promise((resolve, reject) => {
|
||||
groups = groups || [];
|
||||
this.sendContactAddIQ(jid, name, groups,
|
||||
() => {
|
||||
const contact = this.create(_.assignIn({
|
||||
'ask': undefined,
|
||||
'nickname': name,
|
||||
groups,
|
||||
jid,
|
||||
'requesting': false,
|
||||
'subscription': 'none'
|
||||
}, attributes), {sort: false});
|
||||
resolve(contact);
|
||||
},
|
||||
function (err) {
|
||||
alert(__('Sorry, there was an error while trying to add %1$s as a contact.', name));
|
||||
_converse.log(err, Strophe.LogLevel.ERROR);
|
||||
resolve(err);
|
||||
}
|
||||
);
|
||||
});
|
||||
groups = groups || [];
|
||||
try {
|
||||
await this.sendContactAddIQ(jid, name, groups);
|
||||
} catch (e) {
|
||||
_converse.log(e, Strophe.LogLevel.ERROR);
|
||||
alert(__('Sorry, there was an error while trying to add %1$s as a contact.', name));
|
||||
return e;
|
||||
}
|
||||
return this.create(_.assignIn({
|
||||
'ask': undefined,
|
||||
'nickname': name,
|
||||
groups,
|
||||
jid,
|
||||
'requesting': false,
|
||||
'subscription': 'none'
|
||||
}, attributes), {'sort': false});
|
||||
},
|
||||
|
||||
subscribeBack (bare_jid, presence) {
|
||||
|
@ -570,24 +565,26 @@ converse.plugins.add('converse-roster', {
|
|||
return _converse.api.disco.stream.getFeature('ver', 'urn:xmpp:features:rosterver') && this.data.get('version');
|
||||
},
|
||||
|
||||
fetchFromServer () {
|
||||
async fetchFromServer () {
|
||||
/* Fetch the roster from the XMPP server */
|
||||
return new Promise((resolve, reject) => {
|
||||
const iq = $iq({
|
||||
'type': 'get',
|
||||
'id': _converse.connection.getUniqueId('roster')
|
||||
}).c('query', {xmlns: Strophe.NS.ROSTER});
|
||||
if (this.rosterVersioningSupported()) {
|
||||
iq.attrs({'ver': this.data.get('version')});
|
||||
}
|
||||
const callback = _.flow(this.onReceivedFromServer.bind(this), resolve);
|
||||
const errback = function (iq) {
|
||||
const errmsg = "Error while trying to fetch roster from the server";
|
||||
_converse.log(errmsg, Strophe.LogLevel.ERROR);
|
||||
reject(new Error(errmsg));
|
||||
}
|
||||
return _converse.connection.sendIQ(iq, callback, errback);
|
||||
});
|
||||
const stanza = $iq({
|
||||
'type': 'get',
|
||||
'id': _converse.connection.getUniqueId('roster')
|
||||
}).c('query', {xmlns: Strophe.NS.ROSTER});
|
||||
if (this.rosterVersioningSupported()) {
|
||||
stanza.attrs({'ver': this.data.get('version')});
|
||||
}
|
||||
let iq;
|
||||
try {
|
||||
iq = await _converse.api.sendIQ(stanza);
|
||||
} catch (e) {
|
||||
_converse.log(e, Strophe.LogLevel.ERROR);
|
||||
return _converse.log(
|
||||
"Error while trying to fetch roster from the server",
|
||||
Strophe.LogLevel.ERROR
|
||||
);
|
||||
}
|
||||
return this.onReceivedFromServer(iq);
|
||||
},
|
||||
|
||||
onReceivedFromServer (iq) {
|
||||
|
@ -646,7 +643,7 @@ converse.plugins.add('converse-roster', {
|
|||
|
||||
createRequestingContact (presence) {
|
||||
const bare_jid = Strophe.getBareJidFromJid(presence.getAttribute('from')),
|
||||
nickname = _.get(sizzle(`nick[xmlns="${Strophe.NS.NICK}"]`, presence).pop(), 'textContent', null);
|
||||
nickname = _.get(sizzle(`nick[xmlns="${Strophe.NS.NICK}"]`, presence).pop(), 'textContent', null);
|
||||
const user_data = {
|
||||
'jid': bare_jid,
|
||||
'subscription': 'none',
|
||||
|
|
|
@ -56,7 +56,7 @@ converse.plugins.add('converse-vcard', {
|
|||
});
|
||||
|
||||
|
||||
function onVCardData (jid, iq, callback) {
|
||||
async function onVCardData (jid, iq) {
|
||||
const vcard = iq.querySelector('vCard');
|
||||
let result = {};
|
||||
if (!_.isNull(vcard)) {
|
||||
|
@ -75,24 +75,10 @@ converse.plugins.add('converse-vcard', {
|
|||
}
|
||||
if (result.image) {
|
||||
const buffer = u.base64ToArrayBuffer(result['image']);
|
||||
crypto.subtle.digest('SHA-1', buffer)
|
||||
.then(ab => {
|
||||
result['image_hash'] = u.arrayBufferToHex(ab);
|
||||
if (callback) callback(result);
|
||||
});
|
||||
} else {
|
||||
if (callback) callback(result);
|
||||
}
|
||||
}
|
||||
|
||||
function onVCardError (jid, iq, errback) {
|
||||
if (errback) {
|
||||
errback({
|
||||
'stanza': iq,
|
||||
'jid': jid,
|
||||
'vcard_error': moment().format()
|
||||
});
|
||||
const ab = await crypto.subtle.digest('SHA-1', buffer);
|
||||
result['image_hash'] = u.arrayBufferToHex(ab);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function createStanza (type, jid, vcard_el) {
|
||||
|
@ -113,7 +99,7 @@ converse.plugins.add('converse-vcard', {
|
|||
return _converse.api.sendIQ(createStanza("set", jid, vcard_el));
|
||||
}
|
||||
|
||||
function getVCard (_converse, jid) {
|
||||
async function getVCard (_converse, jid) {
|
||||
/* Request the VCard of another user. Returns a promise.
|
||||
*
|
||||
* Parameters:
|
||||
|
@ -121,14 +107,17 @@ converse.plugins.add('converse-vcard', {
|
|||
* is being requested.
|
||||
*/
|
||||
const to = Strophe.getBareJidFromJid(jid) === _converse.bare_jid ? null : jid;
|
||||
return new Promise((resolve, reject) => {
|
||||
_converse.connection.sendIQ(
|
||||
createStanza("get", to),
|
||||
_.partial(onVCardData, jid, _, resolve),
|
||||
_.partial(onVCardError, jid, _, resolve),
|
||||
_converse.IQ_TIMEOUT
|
||||
);
|
||||
});
|
||||
let iq;
|
||||
try {
|
||||
iq = await _converse.api.sendIQ(createStanza("get", to))
|
||||
} catch (iq) {
|
||||
return {
|
||||
'stanza': iq,
|
||||
'jid': jid,
|
||||
'vcard_error': moment().format()
|
||||
}
|
||||
}
|
||||
return onVCardData(jid, iq);
|
||||
}
|
||||
|
||||
/* Event handlers */
|
||||
|
|
32
src/headless/package-lock.json
generated
Normal file
32
src/headless/package-lock.json
generated
Normal file
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"name": "@converse/headless",
|
||||
"version": "4.0.3",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"backbone.browserStorage": {
|
||||
"version": "0.0.4",
|
||||
"resolved": "https://registry.npmjs.org/backbone.browserStorage/-/backbone.browserStorage-0.0.4.tgz",
|
||||
"integrity": "sha512-4LvDP2IkOu9Nt6kj6ft4moKmqKqm3c0WY3c/aie0Cf374wjFuO7vCh/afcKdu1YSuVsryM8yH90/J7yqWbaPHw==",
|
||||
"requires": {
|
||||
"backbone": "~1.x.x",
|
||||
"underscore": ">=1.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"backbone": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/backbone/-/backbone-1.3.3.tgz",
|
||||
"integrity": "sha1-TMgOp8sWMaxHSInOQPL4vGg7KZk=",
|
||||
"requires": {
|
||||
"underscore": ">=1.8.3"
|
||||
}
|
||||
},
|
||||
"underscore": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz",
|
||||
"integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@
|
|||
"gitHead": "9641dcdc820e029b05930479c242d2b707bbe8e2",
|
||||
"dependencies": {
|
||||
"backbone": "1.3.3",
|
||||
"backbone.browserStorage": "0.0.4",
|
||||
"backbone.browserStorage": "jcbrand/Backbone.browserStorage#03bfa13f68b71f97be361840adc5a5064f57b47e",
|
||||
"es6-promise": "^4.1.0",
|
||||
"filesize": "^3.6.1",
|
||||
"lodash": "^4.17.10",
|
||||
|
|
Loading…
Reference in New Issue
Block a user