Update chat message visibility for moderation (#524)
* update message viz in db * create admin endpoint to update message visibility * convert UpdateMessageVisibility api to take in an array of IDs to change visibility on instead * Support requesting filtered or unfiltered chat messages * Handle UPDATE chat events on front and backend for toggling messages * Return entire message with UPDATE events * Remove the UPDATE message type * Revert "Remove the UPDATE message type" This reverts commit 3a83df3d492f7ecf2bab65e845aa2b0365d3a7f6. * update -> visibility update * completely remove messages when they turn hidden on VISIBILITY-UPDATEs, and insert them if they turn visible * Explicitly set visibility * Fix multi-id sql updates * increate scroll buffer a bit so chat scrolls when new large messages come in * Add automated test around chat moderation * Add new chat admin APIs to api spec * Commit updated API documentation Co-authored-by: Gabe Kangas <gabek@real-ity.com> Co-authored-by: Owncast <owncast@owncast.online>
This commit is contained in:
@@ -39,7 +39,7 @@ export default class ChatMessageView extends Component {
|
||||
|
||||
render() {
|
||||
const { message } = this.props;
|
||||
const { author, timestamp } = message;
|
||||
const { author, timestamp, visible } = message;
|
||||
|
||||
const { formattedMessage } = this.state;
|
||||
if (!formattedMessage) {
|
||||
|
||||
@@ -26,6 +26,7 @@ export default class Chat extends Component {
|
||||
|
||||
this.websocket = null;
|
||||
this.receivedFirstMessages = false;
|
||||
this.receivedMessageUpdate = false;
|
||||
|
||||
this.windowBlurred = false;
|
||||
this.numMessagesSinceBlur = 0;
|
||||
@@ -88,7 +89,7 @@ export default class Chat extends Component {
|
||||
}
|
||||
|
||||
// scroll to bottom of messages list when new ones come in
|
||||
if (messages.length > prevMessages.length) {
|
||||
if (messages.length !== prevMessages.length) {
|
||||
this.setState({
|
||||
newMessagesReceived: true,
|
||||
});
|
||||
@@ -144,7 +145,7 @@ export default class Chat extends Component {
|
||||
}
|
||||
|
||||
receivedWebsocketMessage(message) {
|
||||
this.addMessage(message);
|
||||
this.handleMessage(message);
|
||||
}
|
||||
|
||||
handleNetworkingError(error) {
|
||||
@@ -152,16 +153,48 @@ export default class Chat extends Component {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
addMessage(message) {
|
||||
// handle any incoming message
|
||||
handleMessage(message) {
|
||||
const {
|
||||
id: messageId,
|
||||
type: messageType,
|
||||
timestamp: messageTimestamp,
|
||||
visible: messageVisible,
|
||||
} = message;
|
||||
const { messages: curMessages } = this.state;
|
||||
const { messagesOnly } = this.props;
|
||||
|
||||
// if incoming message has same id as existing message, don't add it
|
||||
const existing = curMessages.filter(function (item) {
|
||||
return item.id === message.id;
|
||||
})
|
||||
const existingIndex = curMessages.findIndex(item => item.id === messageId);
|
||||
|
||||
if (existing.length === 0 || !existing) {
|
||||
// If the message already exists and this is an update event
|
||||
// then update it.
|
||||
if (messageType === 'VISIBILITY-UPDATE') {
|
||||
const updatedMessageList = [...curMessages];
|
||||
const convertedMessage = {
|
||||
...message,
|
||||
type: 'CHAT',
|
||||
};
|
||||
// if message exists and should now hide, take it out.
|
||||
if (existingIndex >= 0 && !messageVisible) {
|
||||
this.setState({
|
||||
messages: curMessages.filter(item => item.id !== messageId),
|
||||
});
|
||||
} else if (existingIndex === -1 && messageVisible) {
|
||||
// insert message at timestamp
|
||||
const insertAtIndex = curMessages.findIndex((item, index) => {
|
||||
const time = item.timestamp || messageTimestamp;
|
||||
const nextMessage = index < curMessages.length - 1 && curMessages[index + 1];
|
||||
const nextTime = nextMessage.timestamp || messageTimestamp;
|
||||
const messageTimestampDate = new Date(messageTimestamp);
|
||||
return messageTimestampDate > (new Date(time)) && messageTimestampDate <= (new Date(nextTime));
|
||||
});
|
||||
updatedMessageList.splice(insertAtIndex + 1, 0, convertedMessage);
|
||||
this.setState({
|
||||
messages: updatedMessageList,
|
||||
});
|
||||
}
|
||||
} else if (existingIndex === -1) {
|
||||
// else if message doesn't exist, add it and extra username
|
||||
const newState = {
|
||||
messages: [...curMessages, message],
|
||||
};
|
||||
@@ -173,7 +206,7 @@ export default class Chat extends Component {
|
||||
}
|
||||
|
||||
// if window is blurred and we get a new message, add 1 to title
|
||||
if (!messagesOnly && message.type === 'CHAT' && this.windowBlurred) {
|
||||
if (!messagesOnly && messageType === 'CHAT' && this.windowBlurred) {
|
||||
this.numMessagesSinceBlur += 1;
|
||||
}
|
||||
}
|
||||
@@ -279,7 +312,7 @@ export default class Chat extends Component {
|
||||
const { username, messagesOnly, chatInputEnabled } = props;
|
||||
const { messages, chatUserNames, webSocketConnected } = state;
|
||||
|
||||
const messageList = messages.map(
|
||||
const messageList = messages.filter(message => message.visible !== false).map(
|
||||
(message) =>
|
||||
html`<${Message}
|
||||
message=${message}
|
||||
|
||||
@@ -48,7 +48,7 @@ export const CHAT_KEY_MODIFIERS = [
|
||||
'Meta',
|
||||
'Alt',
|
||||
];
|
||||
export const MESSAGE_JUMPTOBOTTOM_BUFFER = 260;
|
||||
export const MESSAGE_JUMPTOBOTTOM_BUFFER = 300;
|
||||
|
||||
// app styling
|
||||
export const WIDTH_SINGLE_COL = 730;
|
||||
|
||||
Reference in New Issue
Block a user