Improved error messaging for Update Channel API (#5429)

This commit is contained in:
JakeRYW 2024-06-09 07:15:25 -04:00 committed by GitHub
parent b81a947134
commit 25284fc703
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 145 additions and 22 deletions

View file

@ -9,6 +9,7 @@
- Minor: Added `flags.action` filter variable, allowing you to filter on `/me` messages. (#5397) - Minor: Added `flags.action` filter variable, allowing you to filter on `/me` messages. (#5397)
- Minor: The size of the emote popup is now saved. (#5415) - Minor: The size of the emote popup is now saved. (#5415)
- Minor: Added the ability to duplicate tabs. (#5277) - Minor: Added the ability to duplicate tabs. (#5277)
- Minor: Improved error messages for channel update commands. (#5429)
- Minor: Moderators can now see when users are warned. (#5441) - Minor: Moderators can now see when users are warned. (#5441)
- Bugfix: Fixed tab move animation occasionally failing to start after closing a tab. (#5426) - Bugfix: Fixed tab move animation occasionally failing to start after closing a tab. (#5426)
- Bugfix: If a network request errors with 200 OK, Qt's error code is now reported instead of the HTTP status. (#5378) - Bugfix: If a network request errors with 200 OK, Qt's error code is now reported instead of the HTTP status. (#5378)

View file

@ -119,11 +119,11 @@ public:
HelixFailureCallback failureCallback), HelixFailureCallback failureCallback),
(override)); (override));
MOCK_METHOD(void, updateChannel, MOCK_METHOD(
(QString broadcasterId, QString gameId, QString language, void, updateChannel,
QString title, (QString broadcasterId, QString gameId, QString language, QString title,
std::function<void(NetworkResult)> successCallback, std::function<void(NetworkResult)> successCallback,
HelixFailureCallback failureCallback), (FailureCallback<HelixUpdateChannelError, QString> failureCallback)),
(override)); (override));
MOCK_METHOD(void, manageAutoModMessages, MOCK_METHOD(void, manageAutoModMessages,

View file

@ -7,6 +7,58 @@
#include "providers/twitch/api/Helix.hpp" #include "providers/twitch/api/Helix.hpp"
#include "providers/twitch/TwitchChannel.hpp" #include "providers/twitch/TwitchChannel.hpp"
namespace {
using namespace chatterino;
QString formatUpdateChannelError(const char *updateType,
HelixUpdateChannelError error,
const QString &message)
{
using Error = HelixUpdateChannelError;
QString errorMessage = QString("Failed to set %1 - ").arg(updateType);
switch (error)
{
case Error::UserMissingScope: {
errorMessage += "Missing required scope. "
"Re-login with your "
"account and try again.";
}
break;
case Error::UserNotAuthorized: {
errorMessage += QString("You must be the broadcaster "
"to set the %1.")
.arg(updateType);
}
break;
case Error::Ratelimited: {
errorMessage += "You are being ratelimited by Twitch. Try "
"again in a few seconds.";
}
break;
case Error::Forwarded: {
errorMessage += message;
}
break;
case Error::Unknown:
default: {
errorMessage +=
QString("An unknown error has occurred (%1).").arg(message);
}
break;
}
return errorMessage;
}
} // namespace
namespace chatterino::commands { namespace chatterino::commands {
QString setTitle(const CommandContext &ctx) QString setTitle(const CommandContext &ctx)
@ -30,8 +82,8 @@ QString setTitle(const CommandContext &ctx)
return ""; return "";
} }
auto status = ctx.twitchChannel->accessStreamStatus();
auto title = ctx.words.mid(1).join(" "); auto title = ctx.words.mid(1).join(" ");
getHelix()->updateChannel( getHelix()->updateChannel(
ctx.twitchChannel->roomId(), "", "", title, ctx.twitchChannel->roomId(), "", "", title,
[channel{ctx.channel}, title](const auto &result) { [channel{ctx.channel}, title](const auto &result) {
@ -40,10 +92,10 @@ QString setTitle(const CommandContext &ctx)
channel->addMessage( channel->addMessage(
makeSystemMessage(QString("Updated title to %1").arg(title))); makeSystemMessage(QString("Updated title to %1").arg(title)));
}, },
[channel{ctx.channel}] { [channel{ctx.channel}](auto error, auto message) {
channel->addMessage( auto errorMessage =
makeSystemMessage("Title update failed! Are you " formatUpdateChannelError("title", error, message);
"missing the required scope?")); channel->addMessage(makeSystemMessage(errorMessage));
}); });
return ""; return "";
@ -105,10 +157,10 @@ QString setGame(const CommandContext &ctx)
channel->addMessage(makeSystemMessage( channel->addMessage(makeSystemMessage(
QString("Updated game to %1").arg(matchedGame.name))); QString("Updated game to %1").arg(matchedGame.name)));
}, },
[channel] { [channel](auto error, auto message) {
channel->addMessage( auto errorMessage =
makeSystemMessage("Game update failed! Are you " formatUpdateChannelError("game", error, message);
"missing the required scope?")); channel->addMessage(makeSystemMessage(errorMessage));
}); });
}, },
[channel{ctx.channel}] { [channel{ctx.channel}] {

View file

@ -613,11 +613,13 @@ void Helix::unblockUser(QString targetUserId, const QObject *caller,
.execute(); .execute();
} }
void Helix::updateChannel(QString broadcasterId, QString gameId, void Helix::updateChannel(
QString language, QString title, QString broadcasterId, QString gameId, QString language, QString title,
std::function<void(NetworkResult)> successCallback, std::function<void(NetworkResult)> successCallback,
HelixFailureCallback failureCallback) FailureCallback<HelixUpdateChannelError, QString> failureCallback)
{ {
using Error = HelixUpdateChannelError;
QUrlQuery urlQuery; QUrlQuery urlQuery;
auto obj = QJsonObject(); auto obj = QJsonObject();
if (!gameId.isEmpty()) if (!gameId.isEmpty())
@ -646,7 +648,61 @@ void Helix::updateChannel(QString broadcasterId, QString gameId,
successCallback(result); successCallback(result);
}) })
.onError([failureCallback](NetworkResult result) { .onError([failureCallback](NetworkResult result) {
failureCallback(); if (!result.status())
{
failureCallback(Error::Unknown, result.formatError());
return;
}
auto obj = result.parseJson();
auto message = obj.value("message").toString();
switch (*result.status())
{
case 401: {
if (message.startsWith("Missing scope",
Qt::CaseInsensitive))
{
failureCallback(Error::UserMissingScope, message);
}
else if (message.compare(
"The ID in broadcaster_id must match the user "
"ID found in the request's OAuth token.",
Qt::CaseInsensitive) == 0)
{
failureCallback(Error::UserNotAuthorized, message);
}
else
{
failureCallback(Error::Forwarded, message);
}
}
break;
case 400:
case 403: {
failureCallback(Error::Forwarded, message);
}
break;
case 429: {
failureCallback(Error::Ratelimited, message);
}
break;
case 500: {
failureCallback(Error::Unknown, message);
}
break;
default: {
qCDebug(chatterinoTwitch)
<< "Helix update channel, unhandled error data:"
<< result.formatError() << result.getData() << obj;
failureCallback(Error::Unknown, message);
}
break;
}
}) })
.execute(); .execute();
} }

View file

@ -595,6 +595,19 @@ enum class HelixUpdateChatSettingsError { // update chat settings
Forwarded, Forwarded,
}; // update chat settings }; // update chat settings
/// Error type for Helix::updateChannel
///
/// Used in the /settitle and /setgame commands
enum class HelixUpdateChannelError {
Unknown,
UserMissingScope,
UserNotAuthorized,
Ratelimited,
// The error message is forwarded directly from the Twitch API
Forwarded,
};
enum class HelixBanUserError { // /timeout, /ban enum class HelixBanUserError { // /timeout, /ban
Unknown, Unknown,
UserMissingScope, UserMissingScope,
@ -862,7 +875,7 @@ public:
virtual void updateChannel( virtual void updateChannel(
QString broadcasterId, QString gameId, QString language, QString title, QString broadcasterId, QString gameId, QString language, QString title,
std::function<void(NetworkResult)> successCallback, std::function<void(NetworkResult)> successCallback,
HelixFailureCallback failureCallback) = 0; FailureCallback<HelixUpdateChannelError, QString> failureCallback) = 0;
// https://dev.twitch.tv/docs/api/reference#manage-held-automod-messages // https://dev.twitch.tv/docs/api/reference#manage-held-automod-messages
virtual void manageAutoModMessages( virtual void manageAutoModMessages(
@ -1183,7 +1196,8 @@ public:
void updateChannel(QString broadcasterId, QString gameId, QString language, void updateChannel(QString broadcasterId, QString gameId, QString language,
QString title, QString title,
std::function<void(NetworkResult)> successCallback, std::function<void(NetworkResult)> successCallback,
HelixFailureCallback failureCallback) final; FailureCallback<HelixUpdateChannelError, QString>
failureCallback) final;
// https://dev.twitch.tv/docs/api/reference#manage-held-automod-messages // https://dev.twitch.tv/docs/api/reference#manage-held-automod-messages
void manageAutoModMessages( void manageAutoModMessages(