Use origin-id to check for reflected messages.

Also, store the returned `stanza-id` on the message.
This commit is contained in:
JC Brand 2019-02-14 11:32:45 +01:00
parent 6eb05be4be
commit 8d00294681
6 changed files with 117 additions and 54 deletions

View File

@ -7,6 +7,7 @@
- Accessibility: Tag the chat-content as an ARIA live region, for screen readers
- Set releases URL to new Github repo
- Rudimentary support for XEP-0333 chat markers
- Better support for XEP-0359 `stanza-id` and `origin-id` elements.
- #1369 Don't wrongly interpret message with `subject` as a topic change.
- #1405 Status of contacts list are not displayed properly
- #1408 New config option `roomconfig_whitelist`

40
dist/converse.js vendored
View File

@ -66942,7 +66942,7 @@ _converse_core__WEBPACK_IMPORTED_MODULE_6__["default"].plugins.add('converse-muc
const stanza_id = sizzle(`stanza-id[xmlns="${Strophe.NS.SID}"]`, message).pop();
if (!stanza_id) {
return;
return false;
}
const by_jid = stanza_id.getAttribute('by');
@ -66992,22 +66992,32 @@ _converse_core__WEBPACK_IMPORTED_MODULE_6__["default"].plugins.add('converse-muc
const own_message = Strophe.getResourceFromJid(from) == this.get('nick');
if (own_message) {
const msgid = stanza.getAttribute('id'),
jid = stanza.getAttribute('from'); // TODO: use stanza-id?
const origin_id = sizzle(`origin-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop();
if (msgid) {
const msg = this.messages.findWhere({
'msgid': msgid,
'from': jid
});
if (msg && msg.get('sender') === 'me' && !msg.get('received')) {
msg.save({
'received': moment().format()
});
return true;
}
if (!origin_id) {
return false;
}
const msg = this.messages.findWhere({
'origin_id': origin_id.getAttribute('id'),
'sender': 'me'
});
if (msg) {
const stanza_id = sizzle(`stanza-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop();
const attrs = {
'stanza_id': stanza_id ? stanza_id.getAttribute('id') : undefined,
'stanza_id_by_jid': stanza_id ? stanza_id.getAttribute('by') : undefined
};
if (!msg.get('received')) {
attrs.received = moment().format();
}
msg.save(attrs);
}
return msg ? true : false;
}
},

View File

@ -2208,18 +2208,7 @@
null, ['rosterGroupsFetched'], {},
async function (done, _converse) {
const features = [
'http://jabber.org/protocol/muc',
'jabber:iq:register',
'muc_passwordprotected',
'muc_hidden',
'muc_temporary',
'muc_membersonly',
'muc_unmoderated',
'muc_nonanonymous',
Strophe.NS.SID,
];
await test_utils.openAndEnterChatRoom(_converse, 'room', 'muc.example.com', 'dummy', features);
await test_utils.openAndEnterChatRoom(_converse, 'room', 'muc.example.com', 'dummy');
const view = _converse.chatboxviews.get('room@muc.example.com');
spyOn(view.model, 'isDuplicate').and.callThrough();
let stanza = u.toStanza(`
@ -2464,20 +2453,68 @@
});
await new Promise((resolve, reject) => view.once('messageInserted', resolve));
const msg_obj = view.model.messages.at(0);
const msg_id = msg_obj.get('msgid');
const from = msg_obj.get('from');
const body = msg_obj.get('message');
const msg = $msg({
'from': from,
'id': msg_id,
'to': 'dummy@localhost',
'type': 'groupchat',
}).c('body').t(body).up().tree();
await view.model.onMessage(msg);
const stanza = u.toStanza(`
<message xmlns="jabber:client"
from="${msg_obj.get('from')}"
to="${_converse.connection.jid}"
type="groupchat">
<body>${msg_obj.get('message')}</body>
<stanza-id xmlns="urn:xmpp:sid:0"
id="5f3dbc5e-e1d3-4077-a492-693f3769c7ad"
by="lounge@localhost"/>
<origin-id xmlns="urn:xmpp:sid:0" id="${msg_obj.get('origin_id')}"/>
</message>`);
await view.model.onMessage(stanza);
expect(view.el.querySelectorAll('.chat-msg__receipt').length).toBe(1);
done();
}));
it("gets updated with its stanza-id upon MUC reflection",
mock.initConverse(
null, ['rosterGroupsFetched'], {},
async function (done, _converse) {
await test_utils.openAndEnterChatRoom(_converse, 'room', 'muc.example.com', 'dummy');
const view = _converse.chatboxviews.get('room@muc.example.com');
const attrs = {
'id': _converse.connection.getUniqueId(),
'origin_id': _converse.connection.getUniqueId(),
'fullname': 'dummy',
'references': [],
'from': _converse.connection.jid,
'sender': 'me',
'time': moment().format(),
'message': 'Hello world',
'is_spoiler': false,
'type': 'groupchat'
}
view.model.sendMessage(attrs);
await test_utils.waitUntil(() => _converse.api.chats.get().length);
await test_utils.waitUntil(() => view.model.messages.length === 1);
expect(view.model.messages.at(0).get('stanza_id')).toBeUndefined();
expect(view.model.messages.at(0).get('origin_id')).toBe(attrs.origin_id);
const stanza = u.toStanza(`
<message xmlns="jabber:client"
from="room@muc.example.com/dummy"
to="${_converse.connection.jid}"
type="groupchat">
<body>Hello world</body>
<stanza-id xmlns="urn:xmpp:sid:0"
id="5f3dbc5e-e1d3-4077-a492-693f3769c7ad"
by="room@muc.example.com"/>
<origin-id xmlns="urn:xmpp:sid:0" id="${attrs.origin_id}"/>
</message>`);
spyOn(view.model, 'reflectionHandled').and.callThrough();
_converse.connection._dataRecv(test_utils.createRequest(stanza));
await test_utils.waitUntil(() => view.model.reflectionHandled.calls.count() === 1);
expect(view.model.messages.length).toBe(1);
expect(view.model.messages.at(0).get('stanza_id')).toBe("5f3dbc5e-e1d3-4077-a492-693f3769c7ad");
expect(view.model.messages.at(0).get('origin_id')).toBe(attrs.origin_id);
done();
}));
it("can cause a delivery receipt to be returned",
mock.initConverse(
null, ['rosterGroupsFetched'], {},

View File

@ -1869,13 +1869,18 @@
// Let's check that if we receive the same message again, it's
// not shown.
const message = $msg({
from: 'lounge@localhost/dummy',
to: 'dummy@localhost.com',
type: 'groupchat',
id: view.model.messages.at(0).get('msgid')
}).c('body').t(text);
await view.model.onMessage(message.nodeTree);
const stanza = u.toStanza(`
<message xmlns="jabber:client"
from="lounge@localhost/dummy"
to="${_converse.connection.jid}"
type="groupchat">
<body>${text}</body>
<stanza-id xmlns="urn:xmpp:sid:0"
id="5f3dbc5e-e1d3-4077-a492-693f3769c7ad"
by="lounge@localhost"/>
<origin-id xmlns="urn:xmpp:sid:0" id="${view.model.messages.at(0).get('origin_id')}"/>
</message>`);
await view.model.onMessage(stanza);
expect(chat_content.querySelectorAll('.chat-msg').length).toBe(1);
expect(sizzle('.chat-msg__text:last').pop().textContent).toBe(text);
expect(view.model.messages.length).toBe(1);

View File

@ -999,17 +999,26 @@ converse.plugins.add('converse-muc', {
const from = stanza.getAttribute('from');
const own_message = Strophe.getResourceFromJid(from) == this.get('nick');
if (own_message) {
const msgid = stanza.getAttribute('id'),
jid = stanza.getAttribute('from');
// TODO: use stanza-id?
if (msgid) {
const msg = this.messages.findWhere({'msgid': msgid, 'from': jid});
if (msg && msg.get('sender') === 'me' && !msg.get('received')) {
msg.save({'received': moment().format()});
return true;
}
const origin_id = sizzle(`origin-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop();
if (!origin_id) {
return false;
}
const msg = this.messages.findWhere({
'origin_id': origin_id.getAttribute('id'),
'sender': 'me'
});
if (msg) {
const stanza_id = sizzle(`stanza-id[xmlns="${Strophe.NS.SID}"]`, stanza).pop();
const attrs = {
'stanza_id': stanza_id ? stanza_id.getAttribute('id') : undefined,
'stanza_id_by_jid': stanza_id ? stanza_id.getAttribute('by') : undefined
}
if (!msg.get('received')) {
attrs.received = moment().format();
}
msg.save(attrs);
}
return msg ? true : false;
}
},

View File

@ -142,6 +142,7 @@
features = features.length ? features : [
'http://jabber.org/protocol/muc',
'jabber:iq:register',
Strophe.NS.SID,
'muc_passwordprotected',
'muc_hidden',
'muc_temporary',