Commit 95837968 authored by JC Brand's avatar JC Brand

muc: Render role change messages as ephemeral notifications

parent c6f8ef0c
......@@ -235,10 +235,6 @@
font-style: italic;
line-height: var(--line-height-small);
padding: 0 1em 0.3em;
&:before {
content: " ";
}
}
video {
......
This diff is collapsed.
......@@ -648,7 +648,7 @@ describe("Message Retractions", function () {
_converse.connection._dataRecv(mock.createRequest(reflection));
await u.waitUntil(() => view.model.handleRetraction.calls.count() === 1);
expect(view.model.messages.length).toBe(2);
expect(view.model.messages.length).toBe(1);
expect(view.model.messages.last().get('retracted')).toBeTruthy();
expect(view.model.messages.last().get('is_ephemeral')).toBe(false);
expect(view.model.messages.last().get('editable')).toBe(false);
......@@ -670,14 +670,11 @@ describe("Message Retractions", function () {
const occupant = view.model.getOwnOccupant();
expect(occupant.get('role')).toBe('moderator');
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 u.waitUntil(() => view.el.querySelector('.chat-content__notifications').textContent.includes("romeo is no longer a moderator"));
const retraction_stanza = await sendAndThenRetractMessage(_converse, view);
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 1);
expect(view.model.messages.length).toBe(2);
expect(view.model.messages.length).toBe(1);
expect(view.model.messages.last().get('retracted')).toBeTruthy();
const el = view.el.querySelector('.chat-msg--retracted .chat-msg__message div');
expect(el.textContent.trim()).toBe('romeo has removed this message');
......@@ -700,14 +697,14 @@ describe("Message Retractions", function () {
_converse.connection._dataRecv(mock.createRequest(error));
await u.waitUntil(() => view.el.querySelectorAll('.chat-error').length === 1);
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 0);
expect(view.model.messages.length).toBe(3);
expect(view.model.messages.at(1).get('retracted')).toBeFalsy();
expect(view.model.messages.at(1).get('is_ephemeral')).toBeFalsy();
expect(view.model.messages.at(1).get('editable')).toBeTruthy();
expect(view.model.messages.length).toBe(2);
expect(view.model.messages.at(0).get('retracted')).toBeFalsy();
expect(view.model.messages.at(0).get('is_ephemeral')).toBeFalsy();
expect(view.model.messages.at(0).get('editable')).toBeTruthy();
const err_msg = "Sorry, something went wrong while trying to retract your message."
expect(view.model.messages.at(2).get('message')).toBe(err_msg);
expect(view.model.messages.at(2).get('type')).toBe('error');
expect(view.model.messages.at(1).get('message')).toBe(err_msg);
expect(view.model.messages.at(1).get('type')).toBe('error');
expect(view.el.querySelectorAll('.chat-error').length).toBe(1);
const errmsg = view.el.querySelector('.chat-error');
......@@ -729,14 +726,11 @@ describe("Message Retractions", function () {
const occupant = view.model.getOwnOccupant();
expect(occupant.get('role')).toBe('moderator');
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 u.waitUntil(() => view.el.querySelector('.chat-content__notifications').textContent.includes("romeo is no longer a moderator"))
await sendAndThenRetractMessage(_converse, view);
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 1);
expect(view.model.messages.length).toBe(2);
expect(view.model.messages.length).toBe(1);
expect(view.model.messages.last().get('retracted')).toBeTruthy();
const el = view.el.querySelector('.chat-msg--retracted .chat-msg__message div');
expect(el.textContent.trim()).toBe('romeo has removed this message');
......@@ -744,10 +738,10 @@ describe("Message Retractions", function () {
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg').length === 1);
await u.waitUntil(() => view.el.querySelectorAll('.chat-msg--retracted').length === 0);
expect(view.model.messages.length).toBe(4);
expect(view.model.messages.at(1).get('retracted')).toBeFalsy();
expect(view.model.messages.at(1).get('is_ephemeral')).toBeFalsy();
expect(view.model.messages.at(1).get('editable')).toBeTruthy();
expect(view.model.messages.length).toBe(3);
expect(view.model.messages.at(0).get('retracted')).toBeFalsy();
expect(view.model.messages.at(0).get('is_ephemeral')).toBeFalsy();
expect(view.model.messages.at(0).get('editable')).toBeTruthy();
const error_messages = view.el.querySelectorAll('.chat-error');
expect(error_messages.length).toBe(2);
......
......@@ -725,7 +725,7 @@ converse.plugins.add('converse-muc-views', {
renderNotifications () {
const actors_per_state = this.model.notifications.toJSON();
const states = api.settings.get('muc_show_join_leave') ?
[...converse.CHAT_STATES, ...converse.MUC_TRAFFIC_STATES] :
[...converse.CHAT_STATES, ...converse.MUC_TRAFFIC_STATES, ...converse.MUC_ROLE_CHANGES] :
converse.CHAT_STATES;
const message = states.reduce((result, state) => {
......@@ -736,15 +736,23 @@ converse.plugins.add('converse-muc-views', {
const actors = existing_actors.map(a => this.model.getOccupant(a)?.getDisplayName() || a);
if (actors.length === 1) {
if (state === 'composing') {
return `${result} ${__('%1$s is typing', actors[0])}\n`;
return `${result}${__('%1$s is typing', actors[0])}\n`;
} else if (state === 'paused') {
return `${result} ${__('%1$s has stopped typing', actors[0])}\n`;
return `${result}${__('%1$s has stopped typing', actors[0])}\n`;
} else if (state === _converse.GONE) {
return `${result} ${__('%1$s has gone away', actors[0])}\n`;
return `${result}${__('%1$s has gone away', actors[0])}\n`;
} else if (state === 'entered') {
return `${result} ${__('%1$s has entered the groupchat', actors[0])}\n`;
return `${result}${__('%1$s has entered the groupchat', actors[0])}\n`;
} else if (state === 'exited') {
return `${result} ${__('%1$s has left the groupchat', actors[0])}\n`;
return `${result}${__('%1$s has left the groupchat', actors[0])}\n`;
} else if (state === 'op') {
return `${result}${__("%1$s is now a moderator", actors[0])}\n`;
} else if (state === 'deop') {
return `${result}${__("%1$s is no longer a moderator", actors[0])}\n`;
} else if (state === 'voice') {
return `${result}${__("%1$s has been given a voice", actors[0])}\n`;
} else if (state === 'mute') {
return `${result}${__("%1$s has been muted", actors[0])}\n`;
}
} else if (actors.length > 1) {
let actors_str;
......@@ -756,15 +764,23 @@ converse.plugins.add('converse-muc-views', {
}
if (state === 'composing') {
return `${result} ${__('%1$s are typing', actors_str)}\n`;
return `${result}${__('%1$s are typing', actors_str)}\n`;
} else if (state === 'paused') {
return `${result} ${__('%1$s have stopped typing', actors_str)}\n`;
return `${result}${__('%1$s have stopped typing', actors_str)}\n`;
} else if (state === _converse.GONE) {
return `${result} ${__('%1$s have gone away', actors_str)}\n`;
return `${result}${__('%1$s have gone away', actors_str)}\n`;
} else if (state === 'entered') {
return `${result} ${__('%1$s have entered the groupchat', actors_str)}\n`;
return `${result}${__('%1$s have entered the groupchat', actors_str)}\n`;
} else if (state === 'exited') {
return `${result} ${__('%1$s have left the groupchat', actors_str)}\n`;
return `${result}${__('%1$s have left the groupchat', actors_str)}\n`;
} else if (state === 'op') {
return `${result}${__("%1$s are now moderators", actors[0])}\n`;
} else if (state === 'deop') {
return `${result}${__("%1$s are no longer moderator", actors[0])}\n`;
} else if (state === 'voice') {
return `${result}${__("%1$s have been given voices", actors[0])}\n`;
} else if (state === 'mute') {
return `${result}${__("%1$s have been muted", actors[0])}\n`;
}
}
return result;
......
......@@ -17,6 +17,7 @@ import st from "./utils/stanza";
import u from "./utils/form";
converse.MUC_TRAFFIC_STATES = ['entered', 'exited'];
converse.MUC_ROLE_CHANGES = ['op', 'deop', 'voice', 'mute'];
const MUC_ROLE_WEIGHTS = {
'moderator': 1,
......@@ -1938,7 +1939,12 @@ converse.plugins.add('converse-muc', {
};
const actors_per_chat_state = converse.CHAT_STATES.reduce(reducer, {});
const actors_per_traffic_state = converse.MUC_TRAFFIC_STATES.reduce(reducer, {});
this.notifications.set(Object.assign(actors_per_chat_state, actors_per_traffic_state));
const actors_per_role_change = converse.MUC_ROLE_CHANGES.reduce(reducer, {});
this.notifications.set(Object.assign(
actors_per_chat_state,
actors_per_traffic_state,
actors_per_role_change
));
window.setTimeout(() => this.removeNotification(actor, state), 10000);
},
......@@ -2109,31 +2115,17 @@ converse.plugins.add('converse-muc', {
}
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'))
});
this.updateNotifications(occupant.get('nick'), 'deop');
} else if (previous_role === 'visitor') {
this.updateNotifications(occupant.get('nick'), 'voice');
}
if (occupant.get('role') === 'visitor') {
this.createMessage({
'type': 'info',
'message': __("%1$s has been muted", occupant.get('nick'))
});
}
if (occupant.get('role') === 'moderator') {
this.updateNotifications(occupant.get('nick'), 'mute');
} else 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'))
});
this.updateNotifications(occupant.get('nick'), 'op');
}
}
},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment