diff --git a/package.json b/package.json index 14e44c92..94494133 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "frankerfacez", "author": "Dan Salvato LLC", - "version": "4.60.0", + "version": "4.60.1", "description": "FrankerFaceZ is a Twitch enhancement suite.", "private": true, "license": "Apache-2.0", diff --git a/src/modules/chat/actions/actions.jsx b/src/modules/chat/actions/actions.jsx index 9bccd293..6dd2c40d 100644 --- a/src/modules/chat/actions/actions.jsx +++ b/src/modules/chat/actions/actions.jsx @@ -1268,6 +1268,11 @@ export default class Actions extends Module { } + addNotice(room, message) { + return this.resolve('site.chat').addNotice(room, message); + } + + sendMessage(room, message) { return this.resolve('site.chat').sendMessage(room, message); } diff --git a/src/modules/chat/actions/types.jsx b/src/modules/chat/actions/types.jsx index 42e355d9..8a399be4 100644 --- a/src/modules/chat/actions/types.jsx +++ b/src/modules/chat/actions/types.jsx @@ -1,5 +1,6 @@ 'use strict'; +import { TranslatableError } from 'src/utilities/object'; import {createElement} from 'utilities/dom'; @@ -368,7 +369,11 @@ export const msg_delete = { }, click(event, data) { - this.sendMessage(data.room.login, `/delete ${data.message_id}`); + const td = this.resolve('site.twitch_data'); + return td.deleteChatMessage(data.room.id, data.message_id).catch(err => { + if ( err instanceof TranslatableError ) + this.addNotice(data.room.login, this.i18n.t(err.i18n_key, err.message, err.data)); + }); } } diff --git a/src/utilities/mutations/delete-chat-message.gql b/src/utilities/mutations/delete-chat-message.gql new file mode 100644 index 00000000..26a160f2 --- /dev/null +++ b/src/utilities/mutations/delete-chat-message.gql @@ -0,0 +1,16 @@ +mutation FFZ_DeleteChatMessage($input: DeleteChatMessageInput!) { + deleteChatMessage(input: $input) { + responseCode + message { + id + sender { + id + login + displayName + } + content { + text + } + } + } +} diff --git a/src/utilities/object.ts b/src/utilities/object.ts index 6170129f..822e138a 100644 --- a/src/utilities/object.ts +++ b/src/utilities/object.ts @@ -62,6 +62,33 @@ export function isValidShortcut(key: string) { */ export const generateUUID = () => crypto.randomUUID(); + +/** + * An error that can be localized using the i18n module. + */ +export class TranslatableError extends Error { + + i18n_key: string; + data: any; + + constructor(message: string, key: string, data?: any) { + super(message); + this.i18n_key = key; + this.data = data; + } + + toString() { + const ffz = window.FrankerFaceZ?.get?.(), + i18n = ffz?.resolve?.('i18n'); + + if ( i18n && this.i18n_key ) + return i18n.t(this.i18n_key, this.message, this.data); + + return this.message; + } +} + + /** * Get a SHA-256 hash of a string. Uses {@link crypto.subtle.digest} * diff --git a/src/utilities/twitch-data.js b/src/utilities/twitch-data.js index d3d10ae6..f421a41a 100644 --- a/src/utilities/twitch-data.js +++ b/src/utilities/twitch-data.js @@ -6,7 +6,7 @@ // ============================================================================ import Module from 'utilities/module'; -import {get, debounce} from 'utilities/object'; +import {get, debounce, TranslatableError} from 'utilities/object'; const LANGUAGE_MATCHER = /^auto___lang_(\w+)$/; @@ -171,6 +171,51 @@ export default class TwitchData extends Module { } + // ======================================================================== + // Chat + // ======================================================================== + + async deleteChatMessage( + channel_id/* :string*/, + message_id/* :string*/ + ) { + channel_id = String(channel_id); + + const data = await this.mutate({ + mutation: await import(/* webpackChunkName: 'queries' */ './mutations/delete-chat-message.gql'), + variables: { + input: { + channelID: channel_id, + messageID: message_id + } + } + }); + + const code = get('data.deleteChatMessage.responseCode', data); + + if ( code === 'TARGET_IS_BROADCASTER' ) + throw new TranslatableError( + "You cannot delete the broadcaster's messages.", + "chat.delete.forbidden.broadcaster" + ); + + if ( code === 'TARGET_IS_MODERATOR' ) + throw new TranslatableError( + "You cannot delete messages from moderator {displayName}.", + "chat.delete.forbidden.moderator", + get('data.deleteChatMessage.message.sender', data) + ); + + if ( code !== 'SUCCESS' ) + throw new TranslatableError( + "You don't have permission to delete messages.", + "chat.delete.forbidden" + ); + + return true; + } + + // ======================================================================== // Users // ========================================================================