Restrict editing of MUC messages...
to ones with the same XEP-0421 occupant ID
This commit is contained in:
parent
342c75775b
commit
7028286855
@ -10,6 +10,7 @@
|
||||
- Move the `converse-oauth` plugin to the [community-plugins](https://github.com/conversejs/community-plugins)
|
||||
- Don't apply message corrections when the MUC occupant-id doesn't match.
|
||||
- Update `nick` attribute on ChatRoom when user nickname changes
|
||||
- Restrict editing of MUC messages to ones with the same XEP-0421 occupant ID
|
||||
- #2936: Fix documentation about enable_smacks option, which is true by default.
|
||||
|
||||
## 9.1.1 (2022-05-05)
|
||||
|
@ -234,7 +234,7 @@ const ChatBox = ModelWithContact.extend({
|
||||
this.notifications.set('chat_state', attrs.chat_state);
|
||||
}
|
||||
if (u.shouldCreateMessage(attrs)) {
|
||||
const msg = handleCorrection(this, attrs) || await this.createMessage(attrs);
|
||||
const msg = await handleCorrection(this, attrs) || await this.createMessage(attrs);
|
||||
this.notifications.set({'chat_state': null});
|
||||
this.handleUnreadMessage(msg);
|
||||
}
|
||||
|
@ -2280,7 +2280,7 @@ const ChatRoomMixin = {
|
||||
this.updateNotifications(attrs.nick, attrs.chat_state);
|
||||
}
|
||||
if (u.shouldCreateGroupchatMessage(attrs)) {
|
||||
const msg = handleCorrection(this, attrs) || (await this.createMessage(attrs));
|
||||
const msg = await handleCorrection(this, attrs) || (await this.createMessage(attrs));
|
||||
this.removeNotification(attrs.nick, ['composing', 'paused']);
|
||||
this.handleUnreadMessage(msg);
|
||||
}
|
||||
|
@ -245,12 +245,15 @@ export async function parseMUCMessage (stanza, chatbox) {
|
||||
const from_real_jid = attrs.is_archived && getJIDFromMUCUserData(stanza, attrs) ||
|
||||
chatbox.occupants.findOccupant(attrs)?.get('jid');
|
||||
|
||||
const own_occupant_id = chatbox.get('occupant_id');
|
||||
const is_me = attrs.occupant_id && own_occupant_id ? own_occupant_id === attrs.occupant_id : attrs.nick === chatbox.get('nick');
|
||||
|
||||
attrs = Object.assign( {
|
||||
from_real_jid,
|
||||
'is_only_emojis': attrs.body ? u.isOnlyEmojis(attrs.body) : false,
|
||||
'is_valid_receipt_request': isValidReceiptRequest(stanza, attrs),
|
||||
'message': attrs.body || attrs.error, // TODO: Remove and use body and error attributes instead
|
||||
'sender': attrs.nick === chatbox.get('nick') ? 'me' : 'them',
|
||||
'message': attrs.body || attrs.error, // TODO: Should only be used for error and info messages
|
||||
'sender': is_me ? 'me' : 'them',
|
||||
}, attrs);
|
||||
|
||||
if (attrs.is_archived && original_stanza.getAttribute('from') !== attrs.from_muc) {
|
||||
|
@ -72,7 +72,7 @@ export function getMediaURLs (arr, text, offset=0) {
|
||||
* @returns { _converse.Message|undefined } Returns the corrected
|
||||
* message or `undefined` if not applicable.
|
||||
*/
|
||||
export function handleCorrection (model, attrs) {
|
||||
export async function handleCorrection (model, attrs) {
|
||||
if (!attrs.replace_id || !attrs.from) {
|
||||
return;
|
||||
}
|
||||
@ -84,7 +84,8 @@ export function handleCorrection (model, attrs) {
|
||||
|
||||
const message = model.messages.models.find(query);
|
||||
if (!message) {
|
||||
return;
|
||||
attrs['older_versions'] = [];
|
||||
return await model.createMessage(attrs); // eslint-disable-line no-return-await
|
||||
}
|
||||
|
||||
const older_versions = message.get('older_versions') || {};
|
||||
|
@ -296,10 +296,11 @@ describe('A Groupchat Message XEP-0308 correction ', function () {
|
||||
from="lounge@montague.lit/newguy"
|
||||
to="_converse.connection.jid"
|
||||
type="groupchat"
|
||||
id="${msg_id}">
|
||||
id="${u.getUniqueId()}">
|
||||
|
||||
<body>But soft, what light through yonder chimney breaks?</body>
|
||||
<occupant-id xmlns="urn:xmpp:occupant-id:0" id="2"></occupant-id>
|
||||
<replace id="${msg_id}" xmlns="urn:xmpp:message-correct:0"></replace>
|
||||
</message>`
|
||||
);
|
||||
|
||||
@ -309,7 +310,7 @@ describe('A Groupchat Message XEP-0308 correction ', function () {
|
||||
expect(model.messages.at(0).get('edited')).toBeFalsy();
|
||||
|
||||
expect(model.messages.at(1).get('body')).toBe('But soft, what light through yonder chimney breaks?');
|
||||
expect(model.messages.at(1).get('edited')).toBeFalsy();
|
||||
expect(model.messages.at(1).get('edited')).toBeTruthy();
|
||||
|
||||
await model.handleMessageStanza(
|
||||
stx`
|
||||
@ -317,9 +318,10 @@ describe('A Groupchat Message XEP-0308 correction ', function () {
|
||||
from="lounge@montague.lit/newguy"
|
||||
to="_converse.connection.jid"
|
||||
type="groupchat"
|
||||
id="${msg_id}">
|
||||
id="${u.getUniqueId()}">
|
||||
|
||||
<body>But soft, what light through yonder hatch breaks?</body>
|
||||
<replace id="${msg_id}" xmlns="urn:xmpp:message-correct:0"></replace>
|
||||
</message>`
|
||||
);
|
||||
|
||||
@ -329,13 +331,91 @@ describe('A Groupchat Message XEP-0308 correction ', function () {
|
||||
expect(model.messages.at(0).get('edited')).toBeFalsy();
|
||||
|
||||
expect(model.messages.at(1).get('body')).toBe('But soft, what light through yonder chimney breaks?');
|
||||
expect(model.messages.at(1).get('edited')).toBeFalsy();
|
||||
expect(model.messages.at(1).get('edited')).toBeTruthy();
|
||||
|
||||
expect(model.messages.at(2).get('body')).toBe('But soft, what light through yonder hatch breaks?');
|
||||
expect(model.messages.at(2).get('edited')).toBeFalsy();
|
||||
expect(model.messages.at(2).get('edited')).toBeTruthy();
|
||||
|
||||
const message_els = Array.from(view.querySelectorAll('.chat-msg'));
|
||||
expect(message_els.reduce((acc, m) => acc && u.hasClass('chat-msg--followup', m), true)).toBe(false);
|
||||
})
|
||||
);
|
||||
|
||||
it(
|
||||
"cannot be edited if it's from a different occupant id",
|
||||
mock.initConverse([], {}, async function (_converse) {
|
||||
const nick = 'romeo';
|
||||
const muc_jid = 'lounge@montague.lit';
|
||||
const features = [...mock.default_muc_features, Strophe.NS.OCCUPANTID];
|
||||
const model = await mock.openAndEnterChatRoom(_converse, muc_jid, nick, features);
|
||||
|
||||
expect(model.get('occupant_id')).toBe(model.occupants.at(0).get('occupant_id'));
|
||||
|
||||
const msg_id = u.getUniqueId();
|
||||
await model.handleMessageStanza(
|
||||
stx`
|
||||
<message
|
||||
from="lounge@montague.lit/${nick}"
|
||||
to="_converse.connection.jid"
|
||||
type="groupchat"
|
||||
id="${msg_id}">
|
||||
|
||||
<body>But soft, what light through yonder airlock breaks?</body>
|
||||
<occupant-id xmlns="urn:xmpp:occupant-id:0" id="${model.get('occupant_id')}"></occupant-id>
|
||||
</message>`
|
||||
);
|
||||
|
||||
const view = _converse.chatboxviews.get(muc_jid);
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length);
|
||||
expect(model.messages.at(0).get('body')).toBe('But soft, what light through yonder airlock breaks?');
|
||||
|
||||
await model.handleMessageStanza(
|
||||
stx`
|
||||
<message
|
||||
from="lounge@montague.lit/${nick}"
|
||||
to="_converse.connection.jid"
|
||||
type="groupchat"
|
||||
id="${u.getUniqueId()}">
|
||||
|
||||
<body>But soft, what light through yonder chimney breaks?</body>
|
||||
<occupant-id xmlns="urn:xmpp:occupant-id:0" id="${model.get('occupant_id')}"></occupant-id>
|
||||
<replace id="${msg_id}" xmlns="urn:xmpp:message-correct:0"></replace>
|
||||
</message>`
|
||||
);
|
||||
|
||||
expect(model.messages.at(0).get('body')).toBe('But soft, what light through yonder chimney breaks?');
|
||||
expect(model.messages.at(0).get('edited')).toBeTruthy();
|
||||
|
||||
await model.handleMessageStanza(
|
||||
stx`
|
||||
<message
|
||||
from="lounge@montague.lit/${nick}"
|
||||
to="_converse.connection.jid"
|
||||
type="groupchat"
|
||||
id="${u.getUniqueId()}">
|
||||
|
||||
<body>But soft, what light through yonder hatch breaks?</body>
|
||||
<occupant-id xmlns="urn:xmpp:occupant-id:0" id="${u.getUniqueId()}"></occupant-id>
|
||||
<replace id="${msg_id}" xmlns="urn:xmpp:message-correct:0"></replace>
|
||||
</message>`
|
||||
);
|
||||
|
||||
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 2);
|
||||
expect(model.messages.length).toBe(2);
|
||||
expect(model.messages.at(0).get('body')).toBe('But soft, what light through yonder chimney breaks?');
|
||||
expect(model.messages.at(0).get('edited')).toBeTruthy();
|
||||
expect(model.messages.at(0).get('editable')).toBeTruthy();
|
||||
|
||||
expect(model.messages.at(1).get('body')).toBe('But soft, what light through yonder hatch breaks?');
|
||||
expect(model.messages.at(1).get('edited')).toBeTruthy();
|
||||
expect(model.messages.at(1).get('editable')).toBeFalsy();
|
||||
|
||||
const message_els = Array.from(view.querySelectorAll('.chat-msg'));
|
||||
expect(message_els.reduce((acc, m) => acc && u.hasClass('chat-msg--followup', m), true)).toBe(false);
|
||||
|
||||
// We can edit our own message, but not the other
|
||||
expect(message_els[0].querySelector('converse-dropdown .chat-msg__action-edit')).toBeDefined();
|
||||
expect(message_els[1].querySelector('converse-dropdown .chat-msg__action-edit')).toBe(null);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
@ -1,9 +1,13 @@
|
||||
import { CustomElement } from './element.js';
|
||||
import { api, converse } from '@converse/headless/core';
|
||||
import { html } from 'lit';
|
||||
import { __ } from 'i18n';
|
||||
import './styles/message-versions.scss';
|
||||
|
||||
const { dayjs } = converse.env;
|
||||
|
||||
const tpl_older_version = (k, older_versions) => html`<p class="older-msg"><time>${dayjs(k).format('MMM D, YYYY, HH:mm:ss')}</time>: ${older_versions[k]}</p>`;
|
||||
|
||||
|
||||
export class MessageVersions extends CustomElement {
|
||||
|
||||
@ -15,13 +19,15 @@ export class MessageVersions extends CustomElement {
|
||||
|
||||
render () {
|
||||
const older_versions = this.model.get('older_versions');
|
||||
const keys = Object.keys(older_versions);
|
||||
return html`
|
||||
<h4>Older versions</h4>
|
||||
${ Object.keys(older_versions).map(
|
||||
k => html`<p class="older-msg"><time>${dayjs(k).format('MMM D, YYYY, HH:mm:ss')}</time>: ${older_versions[k]}</p>`) }
|
||||
${ keys.length ?
|
||||
html`<h4>${__('Older versions')}</h4> ${keys.map(k => tpl_older_version(k, older_versions))}` :
|
||||
html`<h4>${__('No older versions found')}</h4>`
|
||||
}
|
||||
<hr/>
|
||||
<h4>Current version</h4>
|
||||
<p>${this.model.getMessageText()}</p>`;
|
||||
<h4>${__('Current version')}</h4>
|
||||
<p><time>${dayjs(this.model.get('time')).format('MMM D, YYYY, HH:mm:ss')}</time>: ${this.model.getMessageText()}</p>`;
|
||||
}
|
||||
}
|
||||
|
||||
|
7
src/shared/components/styles/message-versions.scss
Normal file
7
src/shared/components/styles/message-versions.scss
Normal file
@ -0,0 +1,7 @@
|
||||
.conversejs {
|
||||
converse-message-versions {
|
||||
time {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
@ -3,12 +3,6 @@
|
||||
color: var(--subdued-color);
|
||||
}
|
||||
|
||||
.older-msg {
|
||||
time {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.message {
|
||||
.show-msg-author-modal {
|
||||
align-self: flex-start; // Don't expand height to that of largest sibling
|
||||
|
Loading…
Reference in New Issue
Block a user