From dd6f204adc21cfb2833cb6cc38295d5d77339e02 Mon Sep 17 00:00:00 2001 From: nerix Date: Sat, 15 Feb 2025 19:29:25 +0100 Subject: [PATCH] feat: delete messages from context menu (#5956) --- CHANGELOG.md | 1 + src/common/Channel.cpp | 2 +- src/common/Channel.hpp | 2 +- .../builtin/twitch/DeleteMessages.cpp | 53 +-------------- src/providers/twitch/TwitchChannel.cpp | 65 +++++++++++++++++++ src/providers/twitch/TwitchChannel.hpp | 7 ++ src/providers/twitch/TwitchIrcServer.cpp | 2 +- src/widgets/helper/ChannelView.cpp | 12 ++++ 8 files changed, 89 insertions(+), 55 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 829eb034..c23e1ae7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - Minor: Added the ability to filter on messages by the author's user ID (example: `author.user_id == "22484632"`). (#5862) - Minor: Improved error messaging of the `/clip` command. (#5879) - Minor: Added Linux support for Live Notifications toasts. (#5881) +- Minor: Messages can now be deleted from the context menu in a channel. (#5956) - Bugfix: Fixed a potential way to escape the Lua Plugin sandbox. (#5846) - Bugfix: Fixed a crash relating to Lua HTTP. (#5800) - Bugfix: Fixed a crash that could occur on Linux and macOS when clicking "Install" from the update prompt. (#5818) diff --git a/src/common/Channel.cpp b/src/common/Channel.cpp index 13b82816..e492ece4 100644 --- a/src/common/Channel.cpp +++ b/src/common/Channel.cpp @@ -283,7 +283,7 @@ void Channel::replaceMessage(size_t hint, const MessagePtr &message, } } -void Channel::deleteMessage(QString messageID) +void Channel::disableMessage(QString messageID) { auto msg = this->findMessage(messageID); if (msg != nullptr) diff --git a/src/common/Channel.hpp b/src/common/Channel.hpp index 2b7569c8..c2655cbc 100644 --- a/src/common/Channel.hpp +++ b/src/common/Channel.hpp @@ -99,7 +99,7 @@ public: void replaceMessage(size_t index, const MessagePtr &replacement); void replaceMessage(size_t hint, const MessagePtr &message, const MessagePtr &replacement); - void deleteMessage(QString messageID); + void disableMessage(QString messageID); /// Removes all messages from this channel and invokes #messagesCleared void clearMessages(); diff --git a/src/controllers/commands/builtin/twitch/DeleteMessages.cpp b/src/controllers/commands/builtin/twitch/DeleteMessages.cpp index ab3b61a8..c79e558c 100644 --- a/src/controllers/commands/builtin/twitch/DeleteMessages.cpp +++ b/src/controllers/commands/builtin/twitch/DeleteMessages.cpp @@ -32,58 +32,7 @@ QString deleteMessages(TwitchChannel *twitchChannel, const QString &messageID) return ""; } - getHelix()->deleteChatMessages( - twitchChannel->roomId(), user->getUserId(), messageID, - []() { - // Success handling, we do nothing: IRC/pubsub-edge will dispatch the correct - // events to update state for us. - }, - [twitchChannel, messageID](auto error, auto message) { - QString errorMessage = QString("Failed to delete chat messages - "); - - switch (error) - { - case HelixDeleteChatMessagesError::UserMissingScope: { - errorMessage += - "Missing required scope. Re-login with your " - "account and try again."; - } - break; - - case HelixDeleteChatMessagesError::UserNotAuthorized: { - errorMessage += - "you don't have permission to perform that action."; - } - break; - - case HelixDeleteChatMessagesError::MessageUnavailable: { - // Override default message prefix to match with IRC message format - errorMessage = - QString("The message %1 does not exist, was deleted, " - "or is too old to be deleted.") - .arg(messageID); - } - break; - - case HelixDeleteChatMessagesError::UserNotAuthenticated: { - errorMessage += "you need to re-authenticate."; - } - break; - - case HelixDeleteChatMessagesError::Forwarded: { - errorMessage += message; - } - break; - - case HelixDeleteChatMessagesError::Unknown: - default: { - errorMessage += "An unknown error has occurred."; - } - break; - } - - twitchChannel->addSystemMessage(errorMessage); - }); + twitchChannel->deleteMessagesAs(messageID, user.get()); return ""; } diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index 7aa6ad51..8f731842 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -1897,6 +1897,71 @@ void TwitchChannel::createClip() }); } +void TwitchChannel::deleteMessagesAs(const QString &messageID, + TwitchAccount *moderator) +{ + getHelix()->deleteChatMessages( + this->roomId(), moderator->getUserId(), messageID, + []() { + // Success handling, we do nothing: IRC/pubsub will dispatch the correct + // events to update state for us. + }, + [lifetime{this->weak_from_this()}, messageID](auto error, + const auto &message) { + auto self = + std::dynamic_pointer_cast(lifetime.lock()); + if (!self) + { + return; + } + + QString errorMessage = QString("Failed to delete chat messages - "); + + switch (error) + { + case HelixDeleteChatMessagesError::UserMissingScope: { + errorMessage += + "Missing required scope. Re-login with your " + "account and try again."; + } + break; + + case HelixDeleteChatMessagesError::UserNotAuthorized: { + errorMessage += + "you don't have permission to perform that action."; + } + break; + + case HelixDeleteChatMessagesError::MessageUnavailable: { + // Override default message prefix to match with IRC message format + errorMessage = + QString("The message %1 does not exist, was deleted, " + "or is too old to be deleted.") + .arg(messageID); + } + break; + + case HelixDeleteChatMessagesError::UserNotAuthenticated: { + errorMessage += "you need to re-authenticate."; + } + break; + + case HelixDeleteChatMessagesError::Forwarded: { + errorMessage += message; + } + break; + + case HelixDeleteChatMessagesError::Unknown: + default: { + errorMessage += "An unknown error has occurred."; + } + break; + } + + self->addSystemMessage(errorMessage); + }); +} + std::optional TwitchChannel::twitchBadge(const QString &set, const QString &version) const { diff --git a/src/providers/twitch/TwitchChannel.hpp b/src/providers/twitch/TwitchChannel.hpp index 8cd1c434..f5057470 100644 --- a/src/providers/twitch/TwitchChannel.hpp +++ b/src/providers/twitch/TwitchChannel.hpp @@ -59,6 +59,7 @@ struct HelixGlobalBadges; using HelixChannelBadges = HelixGlobalBadges; class TwitchIrcServer; +class TwitchAccount; const int MAX_QUEUED_REDEMPTIONS = 16; @@ -164,6 +165,12 @@ public: QString getCurrentStreamID() const override; void createClip(); + /// Delete the message with the specified ID as a moderator. + /// + /// If the ID is empty, all messages will be deleted, effectively clearing + /// the chat. + void deleteMessagesAs(const QString &messageID, TwitchAccount *moderator); + // Data const QString &subscriptionUrl(); const QString &channelUrl(); diff --git a/src/providers/twitch/TwitchIrcServer.cpp b/src/providers/twitch/TwitchIrcServer.cpp index c2505502..acb2df55 100644 --- a/src/providers/twitch/TwitchIrcServer.cpp +++ b/src/providers/twitch/TwitchIrcServer.cpp @@ -647,7 +647,7 @@ void TwitchIrcServer::initialize() { // Gray out approve/deny button upon "ALLOWED" and "DENIED" statuses // They are versions of automod_message_(denied|approved) but for mods. - chan->deleteMessage("automod_" + msg.messageID); + chan->disableMessage("automod_" + msg.messageID); } } break; diff --git a/src/widgets/helper/ChannelView.cpp b/src/widgets/helper/ChannelView.cpp index 83eb0a42..d6702ff8 100644 --- a/src/widgets/helper/ChannelView.cpp +++ b/src/widgets/helper/ChannelView.cpp @@ -2570,6 +2570,18 @@ void ChannelView::addMessageContextMenuItems(QMenu *menu, } } + auto *twitchChannel = + dynamic_cast(this->underlyingChannel_.get()); + if (!layout->getMessage()->id.isEmpty() && twitchChannel && + twitchChannel->hasModRights()) + { + menu->addAction( + "&Delete message", [twitchChannel, id = layout->getMessage()->id] { + twitchChannel->deleteMessagesAs( + id, getApp()->getAccounts()->twitch.getCurrent().get()); + }); + } + bool isSearch = this->context_ == Context::Search; bool isReplyOrUserCard = (this->context_ == Context::ReplyThread || this->context_ == Context::UserCard) &&