Create occupants based on messages

That way the occupant modal can still be shown in MUCs even if the user
is no longer online.
This commit is contained in:
JC Brand 2023-02-17 12:14:48 +01:00
parent 3f6ad0d950
commit b69e5b5482
7 changed files with 48 additions and 49 deletions

View File

@ -1,4 +1,3 @@
import log from '../../log';
import { Strophe } from 'strophe.js/src/strophe';
import { _converse, api } from '../../core.js';
@ -20,6 +19,7 @@ const ChatRoomMessageMixin = {
this.on('change:type', () => this.setOccupant());
this.on('change:is_ephemeral', () => this.setTimerForEphemeralMessage());
this.chatbox = this.collection?.chatbox;
this.setTimerForEphemeralMessage();
this.setOccupant();
/**
@ -53,24 +53,20 @@ const ChatRoomMessageMixin = {
return (
['all', 'moderator'].includes(api.settings.get('allow_message_retraction')) &&
this.get(`stanza_id ${this.get('from_muc')}`) &&
this.collection.chatbox.canModerateMessages()
this.chatbox.canModerateMessages()
);
},
checkValidity () {
const result = _converse.Message.prototype.checkValidity.call(this);
!result && this.collection.chatbox.debouncedRejoin();
!result && this.chatbox.debouncedRejoin();
return result;
},
onOccupantRemoved () {
this.stopListening(this.occupant);
delete this.occupant;
const chatbox = this?.collection?.chatbox;
if (!chatbox) {
return log.error(`Could not get collection.chatbox for message: ${JSON.stringify(this.toJSON())}`);
}
this.listenTo(chatbox.occupants, 'add', this.onOccupantAdded);
this.listenTo(this.chatbox.occupants, 'add', this.onOccupantAdded);
},
onOccupantAdded (occupant) {
@ -81,10 +77,6 @@ const ChatRoomMessageMixin = {
} else if (occupant.get('nick') !== Strophe.getResourceFromJid(this.get('from'))) {
return;
}
const chatbox = this?.collection?.chatbox;
if (!chatbox) {
return log.error(`Could not get collection.chatbox for message: ${JSON.stringify(this.toJSON())}`);
}
this.occupant = occupant;
if (occupant.get('jid')) {
@ -93,32 +85,40 @@ const ChatRoomMessageMixin = {
this.trigger('occupantAdded');
this.listenTo(this.occupant, 'destroy', this.onOccupantRemoved);
this.stopListening(chatbox.occupants, 'add', this.onOccupantAdded);
this.stopListening(this.chatbox.occupants, 'add', this.onOccupantAdded);
},
getOccupant() {
if (this.occupant) return this.occupant;
this.setOccupant();
return this.occupant;
},
setOccupant () {
if (this.get('type') !== 'groupchat' || this.isEphemeral() || this.occupant) {
return;
}
const chatbox = this?.collection?.chatbox;
if (!chatbox) {
return log.error(`Could not get collection.chatbox for message: ${JSON.stringify(this.toJSON())}`);
}
const nick = Strophe.getResourceFromJid(this.get('from'));
const occupant_id = this.get('occupant_id');
this.occupant = chatbox.occupants.findOccupant({ nick, occupant_id });
if (!this.occupant && api.settings.get('muc_send_probes')) {
this.occupant = chatbox.occupants.create({ nick, occupant_id, 'type': 'unavailable' });
const jid = `${chatbox.get('jid')}/${nick}`;
api.user.presence.send('probe', jid);
this.occupant = this.chatbox.occupants.findOccupant({ nick, occupant_id });
if (!this.occupant) {
this.occupant = this.chatbox.occupants.create({
nick,
occupant_id,
jid: this.get('from_real_jid'),
});
if (api.settings.get('muc_send_probes')) {
const jid = `${this.chatbox.get('jid')}/${nick}`;
api.user.presence.send('probe', jid);
}
}
if (this.occupant) {
this.listenTo(this.occupant, 'destroy', this.onOccupantRemoved);
} else {
this.listenTo(chatbox.occupants, 'add', this.onOccupantAdded);
}
this.listenTo(this.occupant, 'destroy', this.onOccupantRemoved);
}
};

View File

@ -10,9 +10,9 @@ class ChatRoomOccupant extends Model {
defaults () { // eslint-disable-line class-methods-use-this
return {
'hats': [],
'show': 'offline',
'states': []
hats: [],
show: 'offline',
states: []
}
}

View File

@ -83,7 +83,14 @@ describe("A MUC occupant", function () {
await u.waitUntil(() => model.messages.length);
let message = model.messages.at(0);
expect(message.get('occupant_id')).toBe("dd72603deec90a38ba552f7c68cbcc61bca202cd");
expect(message.occupant).toBeUndefined();
expect(message.occupant).not.toBeUndefined();
let occupant = message.occupant;
expect(occupant.getDisplayName()).toBe('3rdwitch');
expect(occupant.get('nick')).toBe('3rdwitch');
expect(occupant.get('jid')).toBe(undefined);
expect(occupant.get('occupant_id')).toBe("dd72603deec90a38ba552f7c68cbcc61bca202cd");
expect(message.getDisplayName()).toBe('3rdwitch');
const presence = u.toStanza(`
@ -98,7 +105,7 @@ describe("A MUC occupant", function () {
</presence>`);
_converse.connection._dataRecv(mock.createRequest(presence));
const occupant = await u.waitUntil(() => model.getOccupantByNickname('thirdwitch'));
occupant = await u.waitUntil(() => model.getOccupantByNickname('thirdwitch'));
expect(occupant.get('occupant_id')).toBe('dd72603deec90a38ba552f7c68cbcc61bca202cd');
expect(model.occupants.findWhere({'occupant_id': "dd72603deec90a38ba552f7c68cbcc61bca202cd"})).toBe(occupant);

View File

@ -39,9 +39,7 @@ export default class OccupantModal extends BaseModal {
addToContacts () {
const model = this.model ?? this.message;
const jid = model.get('jid');
if (jid) {
api.modal.show('converse-add-contact-modal', {'model': new Model({ jid })});
}
if (jid) api.modal.show('converse-add-contact-modal', {'model': new Model({ jid })});
}
}

View File

@ -46,7 +46,7 @@ export default (el) => {
${ affiliation ? html`<div class="row"><strong>${__('Affiliation')}:</strong></div><div class="row">${affiliation}</div>` : '' }
</li>
<li>
${ role ? html`<div class="row"><strong>${__('Roles')}:</strong></div><div class="row">${role}</div>` : '' }
${ role ? html`<div class="row"><strong>${__('Role')}:</strong></div><div class="row">${role}</div>` : '' }
</li>
<li>
${ hats ? html`<div class="row"><strong>${__('Hats')}:</strong></div><div class="row">${hats}</div>` : '' }

View File

@ -1,7 +1,7 @@
/*global mock, converse */
const { Promise, Strophe, $msg, $pres, sizzle,u } = converse.env;
const original_timeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
const { Promise, Strophe, $msg, $pres, sizzle,u } = converse.env;
const original_timeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
describe("A Groupchat Message", function () {
@ -214,7 +214,6 @@ describe("A Groupchat Message", function () {
expect(view.querySelectorAll('.chat-msg').length).toBe(3);
await u.waitUntil(() => sizzle('.chat-msg', view).pop().classList.value.trim() === 'message chat-msg groupchat chat-msg--with-avatar moderator owner');
const add_events = view.model.occupants._events.add.length;
msg = $msg({
from: 'lounge@montague.lit/some1',
id: u.getUniqueId(),
@ -223,9 +222,9 @@ describe("A Groupchat Message", function () {
}).c('body').t('Message from someone not in the MUC right now').tree();
await view.model.handleMessageStanza(msg);
await u.waitUntil(() => view.querySelectorAll('.chat-msg').length === 4);
expect(view.model.messages.last().occupant).toBeUndefined();
// Check that there's a new "add" event handler, for when the occupant appears.
expect(view.model.occupants._events.add.length).toBe(add_events+1);
expect(view.model.messages.last().occupant.get('nick')).toBe('some1');
expect(view.model.messages.last().occupant.get('jid')).toBe(undefined);
// Check that the occupant gets added/removed to the message as it
// gets removed or added.
@ -239,8 +238,7 @@ describe("A Groupchat Message", function () {
await u.waitUntil(() => view.model.messages.last().occupant);
expect(view.model.messages.last().get('message')).toBe('Message from someone not in the MUC right now');
expect(view.model.messages.last().occupant.get('nick')).toBe('some1');
// Check that the "add" event handler was removed.
expect(view.model.occupants._events.add.length).toBe(add_events);
expect(view.model.messages.last().occupant.get('jid')).toBe('some1@montague.lit');
presence = $pres({
to:'romeo@montague.lit/orchard',
@ -253,8 +251,6 @@ describe("A Groupchat Message", function () {
await u.waitUntil(() => !view.model.messages.last().occupant);
expect(view.model.messages.last().get('message')).toBe('Message from someone not in the MUC right now');
expect(view.model.messages.last().occupant).toBeUndefined();
// Check that there's a new "add" event handler, for when the occupant appears.
expect(view.model.occupants._events.add.length).toBe(add_events+1);
presence = $pres({
to:'romeo@montague.lit/orchard',
@ -266,8 +262,6 @@ describe("A Groupchat Message", function () {
await u.waitUntil(() => view.model.messages.last().occupant);
expect(view.model.messages.last().get('message')).toBe('Message from someone not in the MUC right now');
expect(view.model.messages.last().occupant.get('nick')).toBe('some1');
// Check that the "add" event handler was removed.
expect(view.model.occupants._events.add.length).toBe(add_events);
}));
it("will be shown as received upon MUC reflection",

View File

@ -217,7 +217,7 @@ export default class Message extends CustomElement {
api.modal.show('converse-profile-modal', {model: this.model}, ev);
} else if (this.model.get('type') === 'groupchat') {
ev.preventDefault();
api.modal.show('converse-muc-occupant-modal', { 'model': this.model.occupant, 'message': this.model }, ev);
api.modal.show('converse-muc-occupant-modal', { 'model': this.model.getOccupant(), 'message': this.model }, ev);
} else {
ev.preventDefault();
const chatbox = this.model.collection.chatbox;