diff --git a/CHANGELOG.md b/CHANGELOG.md index 130cfb8cf20..17ed858d2e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ - Minor: The account switcher is now styled to match your theme. (#4817) - Minor: Add an invisible resize handle to the bottom of frameless user info popups and reply thread popups. (#4795) - Minor: The installer now checks for the VC Runtime version and shows more info when it's outdated. (#4847) -- Minor: Allow running `/ban` and `/timeout` on User IDs by using the `id:123` syntax (e.g. `/timeout id:22484632 1m stop winning`). (#4945) +- Minor: Allow running `/ban`, `/timeout`, `/unban`, and `/untimeout` on User IDs by using the `id:123` syntax (e.g. `/timeout id:22484632 1m stop winning`). (#4945, #4956) - Minor: The `/usercard` command now accepts user ids. (#4934) - Minor: Add menu actions to reply directly to a message or the original thread root. (#4923) - Minor: The `/reply` command now replies to the latest message of the user. (#4919) diff --git a/src/controllers/commands/builtin/twitch/Unban.cpp b/src/controllers/commands/builtin/twitch/Unban.cpp index 02b942494b7..b43ad550058 100644 --- a/src/controllers/commands/builtin/twitch/Unban.cpp +++ b/src/controllers/commands/builtin/twitch/Unban.cpp @@ -8,6 +8,79 @@ #include "providers/twitch/TwitchChannel.hpp" #include "util/Twitch.hpp" +namespace { + +using namespace chatterino; + +void unbanUserByID(const ChannelPtr &channel, + const TwitchChannel *twitchChannel, + const QString &sourceUserID, const QString &targetUserID, + const QString &displayName) +{ + getHelix()->unbanUser( + twitchChannel->roomId(), sourceUserID, targetUserID, + [] { + // No response for unbans, they're emitted over pubsub/IRC instead + }, + [channel, displayName](auto error, auto message) { + using Error = HelixUnbanUserError; + + QString errorMessage = QString("Failed to unban user - "); + + switch (error) + { + case Error::ConflictingOperation: { + errorMessage += "There was a conflicting ban operation on " + "this user. Please try again."; + } + break; + + case Error::Forwarded: { + errorMessage += message; + } + break; + + case Error::Ratelimited: { + errorMessage += "You are being ratelimited by Twitch. Try " + "again in a few seconds."; + } + break; + + case Error::TargetNotBanned: { + // Equivalent IRC error + errorMessage = + QString("%1 is not banned from this channel.") + .arg(displayName); + } + break; + + case Error::UserMissingScope: { + // TODO(pajlada): Phrase MISSING_REQUIRED_SCOPE + errorMessage += "Missing required scope. " + "Re-login with your " + "account and try again."; + } + break; + + case Error::UserNotAuthorized: { + // TODO(pajlada): Phrase MISSING_PERMISSION + errorMessage += "You don't have permission to " + "perform that action."; + } + break; + + case Error::Unknown: { + errorMessage += "An unknown error has occurred."; + } + break; + } + + channel->addMessage(makeSystemMessage(errorMessage)); + }); +} + +} // namespace + namespace chatterino::commands { QString unbanUser(const CommandContext &ctx) @@ -41,82 +114,30 @@ QString unbanUser(const CommandContext &ctx) return ""; } - auto target = ctx.words.at(1); - stripChannelName(target); - - getHelix()->getUserByName( - target, - [channel{ctx.channel}, currentUser, twitchChannel{ctx.twitchChannel}, - target](const auto &targetUser) { - getHelix()->unbanUser( - twitchChannel->roomId(), currentUser->getUserId(), - targetUser.id, - [] { - // No response for unbans, they're emitted over pubsub/IRC instead - }, - [channel, target, targetUser](auto error, auto message) { - using Error = HelixUnbanUserError; - - QString errorMessage = QString("Failed to unban user - "); - - switch (error) - { - case Error::ConflictingOperation: { - errorMessage += - "There was a conflicting ban operation on " - "this user. Please try again."; - } - break; - - case Error::Forwarded: { - errorMessage += message; - } - break; - - case Error::Ratelimited: { - errorMessage += - "You are being ratelimited by Twitch. Try " - "again in a few seconds."; - } - break; - - case Error::TargetNotBanned: { - // Equivalent IRC error - errorMessage = - QString("%1 is not banned from this channel.") - .arg(targetUser.displayName); - } - break; - - case Error::UserMissingScope: { - // TODO(pajlada): Phrase MISSING_REQUIRED_SCOPE - errorMessage += "Missing required scope. " - "Re-login with your " - "account and try again."; - } - break; - - case Error::UserNotAuthorized: { - // TODO(pajlada): Phrase MISSING_PERMISSION - errorMessage += "You don't have permission to " - "perform that action."; - } - break; - - case Error::Unknown: { - errorMessage += "An unknown error has occurred."; - } - break; - } - - channel->addMessage(makeSystemMessage(errorMessage)); - }); - }, - [channel{ctx.channel}, target] { - // Equivalent error from IRC - channel->addMessage( - makeSystemMessage(QString("Invalid username: %1").arg(target))); - }); + const auto &rawTarget = ctx.words.at(1); + auto [targetUserName, targetUserID] = parseUserNameOrID(rawTarget); + + if (!targetUserID.isEmpty()) + { + unbanUserByID(ctx.channel, ctx.twitchChannel, currentUser->getUserId(), + targetUserID, targetUserID); + } + else + { + getHelix()->getUserByName( + targetUserName, + [channel{ctx.channel}, currentUser, + twitchChannel{ctx.twitchChannel}, + targetUserName{targetUserName}](const auto &targetUser) { + unbanUserByID(channel, twitchChannel, currentUser->getUserId(), + targetUser.id, targetUser.displayName); + }, + [channel{ctx.channel}, targetUserName{targetUserName}] { + // Equivalent error from IRC + channel->addMessage(makeSystemMessage( + QString("Invalid username: %1").arg(targetUserName))); + }); + } return ""; }