MUC: create role/affiliation change message objects

in @converse/headless instead of injecting HTML via the view
This commit is contained in:
JC Brand 2020-04-13 11:10:25 +02:00
parent dcd8c8d418
commit e91a38547a
4 changed files with 157 additions and 101 deletions

View File

@ -2804,8 +2804,8 @@
'role': 'visitor' 'role': 'visitor'
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
let info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0); const info_msg = await u.waitUntil(() => view.el.querySelector('.chat-info__message'));
expect(info_msgs.pop().textContent.trim()).toBe("annoyingGuy has been muted"); expect(info_msg.textContent.trim()).toBe("annoyingGuy has been muted");
presence = $pres({ presence = $pres({
'from': 'lounge@montague.lit/annoyingGuy', 'from': 'lounge@montague.lit/annoyingGuy',
@ -2818,8 +2818,10 @@
'role': 'participant' 'role': 'participant'
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0); await u.waitUntil(() =>
expect(info_msgs.pop().textContent.trim()).toBe("annoyingGuy has been given a voice"); Array.from(view.el.querySelectorAll('.chat-info__message')).pop()?.textContent.trim() ===
"annoyingGuy has been given a voice"
);
// Check that we don't see an info message concerning the role, // Check that we don't see an info message concerning the role,
// if the affiliation has changed. // if the affiliation has changed.
@ -2834,8 +2836,10 @@
'role': 'visitor' 'role': 'visitor'
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0); await u.waitUntil(() =>
expect(info_msgs.pop().textContent.trim()).toBe("annoyingGuy is no longer a member of this groupchat"); Array.from(view.el.querySelectorAll('.chat-info__message')).pop()?.textContent.trim() ===
"annoyingGuy is no longer a member of this groupchat"
);
done(); done();
})); }));
@ -3331,7 +3335,10 @@
'role': 'participant' 'role': 'participant'
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect(view.el.querySelectorAll('.chat-info')[2].textContent.trim()).toBe("annoyingGuy is now an owner of this groupchat"); await u.waitUntil(() =>
Array.from(view.el.querySelectorAll('.chat-info__message')).pop()?.textContent.trim() ===
"annoyingGuy is now an owner of this groupchat"
);
done(); done();
})); }));
@ -3547,7 +3554,6 @@
}); });
spyOn(view.model, 'setRole').and.callThrough(); spyOn(view.model, 'setRole').and.callThrough();
spyOn(view, 'showErrorMessage').and.callThrough(); spyOn(view, 'showErrorMessage').and.callThrough();
spyOn(view, 'showChatEvent').and.callThrough();
spyOn(view, 'validateRoleOrAffiliationChangeArgs').and.callThrough(); spyOn(view, 'validateRoleOrAffiliationChangeArgs').and.callThrough();
// New user enters the groupchat // New user enters the groupchat
@ -3628,8 +3634,11 @@
'role': 'moderator' 'role': 'moderator'
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
let info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0); await u.waitUntil(() =>
expect(info_msgs.pop().textContent.trim()).toBe("trustworthyguy is now a moderator"); Array.from(view.el.querySelectorAll('.chat-info__message')).pop()?.textContent.trim() ===
"trustworthyguy is now a moderator"
);
// Call now with the correct amount of arguments. // Call now with the correct amount of arguments.
// XXX: Calling onFormSubmitted directly, trying // XXX: Calling onFormSubmitted directly, trying
// again via triggering Event doesn't work for some weird // again via triggering Event doesn't work for some weird
@ -3638,7 +3647,6 @@
view.onFormSubmitted(new Event('submit')); view.onFormSubmitted(new Event('submit'));
expect(view.validateRoleOrAffiliationChangeArgs.calls.count()).toBe(3); expect(view.validateRoleOrAffiliationChangeArgs.calls.count()).toBe(3);
expect(view.showChatEvent.calls.count()).toBe(1);
expect(view.model.setRole).toHaveBeenCalled(); expect(view.model.setRole).toHaveBeenCalled();
expect(sent_IQ.toLocaleString()).toBe( expect(sent_IQ.toLocaleString()).toBe(
`<iq id="${IQ_id}" to="lounge@montague.lit" type="set" xmlns="jabber:client">`+ `<iq id="${IQ_id}" to="lounge@montague.lit" type="set" xmlns="jabber:client">`+
@ -3669,8 +3677,10 @@
'role': 'participant' 'role': 'participant'
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0); await u.waitUntil(() =>
expect(info_msgs.pop().textContent.trim()).toBe("trustworthyguy is no longer a moderator"); Array.from(view.el.querySelectorAll('.chat-info__message')).pop()?.textContent.trim() ===
"trustworthyguy is no longer a moderator"
);
done(); done();
})); }));
@ -3690,7 +3700,6 @@
}); });
spyOn(view.model, 'setRole').and.callThrough(); spyOn(view.model, 'setRole').and.callThrough();
spyOn(view, 'showErrorMessage').and.callThrough(); spyOn(view, 'showErrorMessage').and.callThrough();
spyOn(view, 'showChatEvent').and.callThrough();
spyOn(view, 'validateRoleOrAffiliationChangeArgs').and.callThrough(); spyOn(view, 'validateRoleOrAffiliationChangeArgs').and.callThrough();
// New user enters the groupchat // New user enters the groupchat
@ -3770,8 +3779,10 @@
'role': 'visitor' 'role': 'visitor'
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
let info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0); await u.waitUntil(() =>
expect(info_msgs.pop().textContent.trim()).toBe("annoyingGuy has been muted"); Array.from(view.el.querySelectorAll('.chat-info__message')).pop()?.textContent.trim() ===
"annoyingGuy has been muted"
);
// Call now with the correct of arguments. // Call now with the correct of arguments.
// XXX: Calling onFormSubmitted directly, trying // XXX: Calling onFormSubmitted directly, trying
@ -3781,7 +3792,6 @@
view.onFormSubmitted(new Event('submit')); view.onFormSubmitted(new Event('submit'));
expect(view.validateRoleOrAffiliationChangeArgs.calls.count()).toBe(3); expect(view.validateRoleOrAffiliationChangeArgs.calls.count()).toBe(3);
expect(view.showChatEvent.calls.count()).toBe(1);
expect(view.model.setRole).toHaveBeenCalled(); expect(view.model.setRole).toHaveBeenCalled();
expect(sent_IQ.toLocaleString()).toBe( expect(sent_IQ.toLocaleString()).toBe(
`<iq id="${IQ_id}" to="lounge@montague.lit" type="set" xmlns="jabber:client">`+ `<iq id="${IQ_id}" to="lounge@montague.lit" type="set" xmlns="jabber:client">`+
@ -3813,8 +3823,10 @@
'role': 'participant' 'role': 'participant'
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
info_msgs = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0); await u.waitUntil(() =>
expect(info_msgs.pop().textContent.trim()).toBe("annoyingGuy has been given a voice"); Array.from(view.el.querySelectorAll('.chat-info__message')).pop()?.textContent.trim() ===
"annoyingGuy has been given a voice"
);
done(); done();
})); }));
@ -5231,9 +5243,10 @@
expect(bottom_panel.textContent.trim()).toBe("You're not allowed to send messages in this room"); expect(bottom_panel.textContent.trim()).toBe("You're not allowed to send messages in this room");
// Check now that things get restored when the user is given a voice // Check now that things get restored when the user is given a voice
let info_msgs = sizzle('.chat-info', view.el); await u.waitUntil(() =>
expect(info_msgs.length).toBe(1); Array.from(view.el.querySelectorAll('.chat-info__message')).pop()?.textContent.trim() ===
expect(info_msgs[0].textContent.trim()).toBe("troll is no longer an owner of this groupchat"); "troll is no longer an owner of this groupchat"
);
stanza = u.toStanza(` stanza = u.toStanza(`
<presence <presence
@ -5247,16 +5260,18 @@
</x> </x>
</presence>`); </presence>`);
_converse.connection._dataRecv(test_utils.createRequest(stanza)); _converse.connection._dataRecv(test_utils.createRequest(stanza));
info_msgs = sizzle('.chat-info', view.el);
bottom_panel = view.el.querySelector('.muc-bottom-panel'); bottom_panel = view.el.querySelector('.muc-bottom-panel');
expect(bottom_panel).toBe(null); expect(bottom_panel).toBe(null);
textarea = view.el.querySelector('.chat-textarea'); textarea = view.el.querySelector('.chat-textarea');
expect(textarea === null).toBe(false); expect(textarea === null).toBe(false);
expect(info_msgs.length).toBe(2); // Check now that things get restored when the user is given a voice
expect(info_msgs[1].textContent.trim()).toBe("troll has been given a voice"); await u.waitUntil(() =>
Array.from(view.el.querySelectorAll('.chat-info__message')).pop()?.textContent.trim() ===
"troll has been given a voice"
);
expect(view.el.querySelectorAll('.chat-info__message').length).toBe(2);
done(); done();
})); }));
}); });

View File

@ -12,8 +12,8 @@
async function sendAndThenRetractMessage (_converse, view) { async function sendAndThenRetractMessage (_converse, view) {
view.model.sendMessage('hello world'); view.model.sendMessage('hello world');
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 1); await u.waitUntil(() => view.el.querySelectorAll('.chat-msg__text').length === 1);
const msg_obj = view.model.messages.at(0); const msg_obj = view.model.messages.last();
const reflection_stanza = u.toStanza(` const reflection_stanza = u.toStanza(`
<message xmlns="jabber:client" <message xmlns="jabber:client"
from="${msg_obj.get('from')}" from="${msg_obj.get('from')}"
@ -625,7 +625,7 @@
const retraction_stanza = await sendAndThenRetractMessage(_converse, view); const retraction_stanza = await sendAndThenRetractMessage(_converse, view);
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 1); await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 1);
const msg_obj = view.model.messages.at(0); const msg_obj = view.model.messages.last();
expect(Strophe.serialize(retraction_stanza)).toBe( expect(Strophe.serialize(retraction_stanza)).toBe(
`<message id="${retraction_stanza.getAttribute('id')}" to="${muc_jid}" type="groupchat" xmlns="jabber:client">`+ `<message id="${retraction_stanza.getAttribute('id')}" to="${muc_jid}" type="groupchat" xmlns="jabber:client">`+
`<store xmlns="urn:xmpp:hints"/>`+ `<store xmlns="urn:xmpp:hints"/>`+
@ -634,7 +634,7 @@
`</apply-to>`+ `</apply-to>`+
`</message>`); `</message>`);
const message = view.model.messages.at(0); const message = view.model.messages.last();
expect(message.get('retracted')).toBeTruthy(); expect(message.get('retracted')).toBeTruthy();
expect(message.get('is_ephemeral')).toBe(false); expect(message.get('is_ephemeral')).toBe(false);
expect(message.get('editable')).toBeFalsy(); expect(message.get('editable')).toBeFalsy();
@ -654,10 +654,10 @@
_converse.connection._dataRecv(test_utils.createRequest(reflection)); _converse.connection._dataRecv(test_utils.createRequest(reflection));
await u.waitUntil(() => view.model.handleRetraction.calls.count() === 1); await u.waitUntil(() => view.model.handleRetraction.calls.count() === 1);
expect(view.model.messages.length).toBe(1); expect(view.model.messages.length).toBe(2);
expect(view.model.messages.at(0).get('retracted')).toBeTruthy(); expect(view.model.messages.last().get('retracted')).toBeTruthy();
expect(view.model.messages.at(0).get('is_ephemeral')).toBe(false); expect(view.model.messages.last().get('is_ephemeral')).toBe(false);
expect(view.model.messages.at(0).get('editable')).toBe(false); expect(view.model.messages.last().get('editable')).toBe(false);
expect(view.el.querySelectorAll('.chat-msg--retracted').length).toBe(1); expect(view.el.querySelectorAll('.chat-msg--retracted').length).toBe(1);
const el = view.el.querySelector('.chat-msg--retracted .chat-msg__message div'); const el = view.el.querySelector('.chat-msg--retracted .chat-msg__message div');
expect(el.textContent).toBe('romeo has removed this message'); expect(el.textContent).toBe('romeo has removed this message');
@ -676,15 +676,19 @@
const occupant = view.model.getOwnOccupant(); const occupant = view.model.getOwnOccupant();
expect(occupant.get('role')).toBe('moderator'); expect(occupant.get('role')).toBe('moderator');
occupant.save('role', 'member'); occupant.save('role', 'member');
await u.waitUntil(() =>
Array.from(view.el.querySelectorAll('.chat-info__message')).pop()?.textContent.trim() ===
"romeo is no longer a moderator"
);
const retraction_stanza = await sendAndThenRetractMessage(_converse, view); const retraction_stanza = await sendAndThenRetractMessage(_converse, view);
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 1); await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 1);
expect(view.model.messages.length).toBe(1); expect(view.model.messages.length).toBe(2);
expect(view.model.messages.at(0).get('retracted')).toBeTruthy(); expect(view.model.messages.last().get('retracted')).toBeTruthy();
const el = view.el.querySelector('.chat-msg--retracted .chat-msg__message div'); const el = view.el.querySelector('.chat-msg--retracted .chat-msg__message div');
expect(el.textContent.trim()).toBe('romeo has removed this message'); expect(el.textContent.trim()).toBe('romeo has removed this message');
const message = view.model.messages.at(0); const message = view.model.messages.last();
const stanza_id = message.get(`stanza_id ${view.model.get('jid')}`); const stanza_id = message.get(`stanza_id ${view.model.get('jid')}`);
// The server responds with an error message // The server responds with an error message
const error = u.toStanza(` const error = u.toStanza(`
@ -702,10 +706,10 @@
_converse.connection._dataRecv(test_utils.createRequest(error)); _converse.connection._dataRecv(test_utils.createRequest(error));
await u.waitUntil(() => view.el.querySelectorAll('.chat-error').length === 1); await u.waitUntil(() => view.el.querySelectorAll('.chat-error').length === 1);
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 0); await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 0);
expect(view.model.messages.length).toBe(1); expect(view.model.messages.length).toBe(2);
expect(view.model.messages.at(0).get('retracted')).toBeFalsy(); expect(view.model.messages.last().get('retracted')).toBeFalsy();
expect(view.model.messages.at(0).get('is_ephemeral')).toBeFalsy(); expect(view.model.messages.last().get('is_ephemeral')).toBeFalsy();
expect(view.model.messages.at(0).get('editable')).toBeTruthy(); expect(view.model.messages.last().get('editable')).toBeTruthy();
expect(view.el.querySelectorAll('.chat-error').length).toBe(1); expect(view.el.querySelectorAll('.chat-error').length).toBe(1);
const errmsg = view.el.querySelector('.chat-error'); const errmsg = view.el.querySelector('.chat-error');
@ -713,7 +717,7 @@
done(); done();
})); }));
it("can be retracted by its author, causing an timeout error in response", it("can be retracted by its author, causing a timeout error in response",
mock.initConverse( mock.initConverse(
['rosterGroupsFetched', 'chatBoxesFetched'], {}, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) { async function (done, _converse) {
@ -727,21 +731,25 @@
const occupant = view.model.getOwnOccupant(); const occupant = view.model.getOwnOccupant();
expect(occupant.get('role')).toBe('moderator'); expect(occupant.get('role')).toBe('moderator');
occupant.save('role', 'member'); occupant.save('role', 'member');
await u.waitUntil(() =>
Array.from(view.el.querySelectorAll('.chat-info__message')).pop()?.textContent.trim() ===
"romeo is no longer a moderator"
);
await sendAndThenRetractMessage(_converse, view); await sendAndThenRetractMessage(_converse, view);
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 1); await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 1);
expect(view.model.messages.length).toBe(1); expect(view.model.messages.length).toBe(2);
expect(view.model.messages.at(0).get('retracted')).toBeTruthy(); expect(view.model.messages.last().get('retracted')).toBeTruthy();
const el = view.el.querySelector('.chat-msg--retracted .chat-msg__message div'); const el = view.el.querySelector('.chat-msg--retracted .chat-msg__message div');
expect(el.textContent.trim()).toBe('romeo has removed this message'); expect(el.textContent.trim()).toBe('romeo has removed this message');
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 1); await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 1);
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 0); await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 0);
expect(view.model.messages.length).toBe(1); expect(view.model.messages.length).toBe(2);
expect(view.model.messages.at(0).get('retracted')).toBeFalsy(); expect(view.model.messages.last().get('retracted')).toBeFalsy();
expect(view.model.messages.at(0).get('is_ephemeral')).toBeFalsy(); expect(view.model.messages.last().get('is_ephemeral')).toBeFalsy();
expect(view.model.messages.at(0).get('editable')).toBeTruthy(); expect(view.model.messages.last().get('editable')).toBeTruthy();
const error_messages = view.el.querySelectorAll('.chat-error'); const error_messages = view.el.querySelectorAll('.chat-error');
expect(error_messages.length).toBe(2); expect(error_messages.length).toBe(2);

View File

@ -1123,60 +1123,12 @@ converse.plugins.add('converse-muc-views', {
if (occupant.get('jid') === _converse.bare_jid) { if (occupant.get('jid') === _converse.bare_jid) {
this.renderHeading(); this.renderHeading();
} }
this.informOfOccupantsAffiliationChange(occupant);
}, },
informOfOccupantsAffiliationChange (occupant) { onOccupantRoleChanged (occupant) {
const previous_affiliation = occupant._previousAttributes.affiliation;
const current_affiliation = occupant.get('affiliation');
if (previous_affiliation === 'admin') {
this.showChatEvent(__("%1$s is no longer an admin of this groupchat", occupant.get('nick')))
} else if (previous_affiliation === 'owner') {
this.showChatEvent(__("%1$s is no longer an owner of this groupchat", occupant.get('nick')))
} else if (previous_affiliation === 'outcast') {
this.showChatEvent(__("%1$s is no longer banned from this groupchat", occupant.get('nick')))
}
if (current_affiliation === 'none' && previous_affiliation === 'member') {
this.showChatEvent(__("%1$s is no longer a member of this groupchat", occupant.get('nick')))
} if (current_affiliation === 'member') {
this.showChatEvent(__("%1$s is now a member of this groupchat", occupant.get('nick')))
} else if (current_affiliation === 'admin' || current_affiliation == 'owner') {
// For example: AppleJack is now an (admin|owner) of this groupchat
this.showChatEvent(__('%1$s is now an %2$s of this groupchat', occupant.get('nick'), current_affiliation))
}
},
onOccupantRoleChanged (occupant, changed) {
if (occupant.get('jid') === _converse.bare_jid) { if (occupant.get('jid') === _converse.bare_jid) {
this.renderBottomPanel(); this.renderBottomPanel();
} }
this.informOfOccupantsRoleChange(occupant, changed);
},
informOfOccupantsRoleChange (occupant, changed) {
if (changed === "none" || occupant.changed.affiliation) {
// We don't inform of role changes if they accompany affiliation changes.
return;
}
const previous_role = occupant._previousAttributes.role;
if (previous_role === 'moderator') {
this.showChatEvent(__("%1$s is no longer a moderator", occupant.get('nick')))
}
if (previous_role === 'visitor') {
this.showChatEvent(__("%1$s has been given a voice", occupant.get('nick')))
}
if (occupant.get('role') === 'visitor') {
this.showChatEvent(__("%1$s has been muted", occupant.get('nick')))
}
if (occupant.get('role') === 'moderator') {
if (!['owner', 'admin'].includes(occupant.get('affiliation'))) {
// We only show this message if the user isn't already
// an admin or owner, otherwise this isn't new
// information.
this.showChatEvent(__("%1$s is now a moderator", occupant.get('nick')))
}
}
}, },
/** /**

View File

@ -383,6 +383,8 @@ converse.plugins.add('converse-muc', {
this.listenTo(this.occupants, 'add', this.onOccupantAdded); this.listenTo(this.occupants, 'add', this.onOccupantAdded);
this.listenTo(this.occupants, 'remove', this.onOccupantRemoved); this.listenTo(this.occupants, 'remove', this.onOccupantRemoved);
this.listenTo(this.occupants, 'change:show', this.onOccupantShowChanged); this.listenTo(this.occupants, 'change:show', this.onOccupantShowChanged);
this.listenTo(this.occupants, 'change:affiliation', this.createAffiliationChangeMessage);
this.listenTo(this.occupants, 'change:role', this.createRoleChangeMessage);
const restored = await this.restoreFromCache() const restored = await this.restoreFromCache()
if (!restored) { if (!restored) {
@ -2109,6 +2111,86 @@ converse.plugins.add('converse-muc', {
} }
}, },
createAffiliationChangeMessage (occupant) {
const previous_affiliation = occupant._previousAttributes.affiliation;
const current_affiliation = occupant.get('affiliation');
if (previous_affiliation === 'admin') {
this.createMessage({
'type': 'info',
'message': __("%1$s is no longer an admin of this groupchat", occupant.get('nick'))
});
} else if (previous_affiliation === 'owner') {
this.createMessage({
'type': 'info',
'message': __("%1$s is no longer an owner of this groupchat", occupant.get('nick'))
});
} else if (previous_affiliation === 'outcast') {
this.createMessage({
'type': 'info',
'message': __("%1$s is no longer banned from this groupchat", occupant.get('nick'))
});
}
if (current_affiliation === 'none' && previous_affiliation === 'member') {
this.createMessage({
'type': 'info',
'message': __("%1$s is no longer a member of this groupchat", occupant.get('nick'))
});
}
if (current_affiliation === 'member') {
this.createMessage({
'type': 'info',
'message': __("%1$s is now a member of this groupchat", occupant.get('nick'))
});
} else if (current_affiliation === 'admin' || current_affiliation == 'owner') {
// For example: AppleJack is now an (admin|owner) of this groupchat
this.createMessage({
'type': 'info',
'message': __(
'%1$s is now an %2$s of this groupchat',
occupant.get('nick'),
current_affiliation
)
});
}
},
createRoleChangeMessage (occupant, changed) {
if (changed === "none" || occupant.changed.affiliation) {
// We don't inform of role changes if they accompany affiliation changes.
return;
}
const previous_role = occupant._previousAttributes.role;
if (previous_role === 'moderator') {
this.createMessage({
'type': 'info',
'message': __("%1$s is no longer a moderator", occupant.get('nick'))
});
}
if (previous_role === 'visitor') {
this.createMessage({
'type': 'info',
'message': __("%1$s has been given a voice", occupant.get('nick'))
});
}
if (occupant.get('role') === 'visitor') {
this.createMessage({
'type': 'info',
'message': __("%1$s has been muted", occupant.get('nick'))
});
}
if (occupant.get('role') === 'moderator') {
if (!['owner', 'admin'].includes(occupant.get('affiliation'))) {
// Oly show this message if the user isn't already
// an admin or owner, otherwise this isn't new information.
this.createMessage({
'type': 'info',
'message': __("%1$s is now a moderator", occupant.get('nick'))
});
}
}
},
/** /**
* Create info messages based on a received presence or message stanza * Create info messages based on a received presence or message stanza
@ -2122,10 +2204,9 @@ converse.plugins.add('converse-muc', {
if (!x) { if (!x) {
return; return;
} }
const codes = sizzle('status', x).map(s => s.getAttribute('code')); sizzle('status', x).map(s => s.getAttribute('code')).forEach(code => {
codes.forEach(code => {
const data = { const data = {
'type': 'info' 'type': 'info',
}; };
if (code === '110' || (code === '100' && !is_self)) { if (code === '110' || (code === '100' && !is_self)) {
return; return;