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: The size of the emote popup is now saved. (#5415)
- 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)
- 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)

View file

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

View file

@ -7,6 +7,58 @@
#include "providers/twitch/api/Helix.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 {
QString setTitle(const CommandContext &ctx)
@ -30,8 +82,8 @@ QString setTitle(const CommandContext &ctx)
return "";
}
auto status = ctx.twitchChannel->accessStreamStatus();
auto title = ctx.words.mid(1).join(" ");
getHelix()->updateChannel(
ctx.twitchChannel->roomId(), "", "", title,
[channel{ctx.channel}, title](const auto &result) {
@ -40,10 +92,10 @@ QString setTitle(const CommandContext &ctx)
channel->addMessage(
makeSystemMessage(QString("Updated title to %1").arg(title)));
},
[channel{ctx.channel}] {
channel->addMessage(
makeSystemMessage("Title update failed! Are you "
"missing the required scope?"));
[channel{ctx.channel}](auto error, auto message) {
auto errorMessage =
formatUpdateChannelError("title", error, message);
channel->addMessage(makeSystemMessage(errorMessage));
});
return "";
@ -105,10 +157,10 @@ QString setGame(const CommandContext &ctx)
channel->addMessage(makeSystemMessage(
QString("Updated game to %1").arg(matchedGame.name)));
},
[channel] {
channel->addMessage(
makeSystemMessage("Game update failed! Are you "
"missing the required scope?"));
[channel](auto error, auto message) {
auto errorMessage =
formatUpdateChannelError("game", error, message);
channel->addMessage(makeSystemMessage(errorMessage));
});
},
[channel{ctx.channel}] {

View file

@ -613,11 +613,13 @@ void Helix::unblockUser(QString targetUserId, const QObject *caller,
.execute();
}
void Helix::updateChannel(QString broadcasterId, QString gameId,
QString language, QString title,
std::function<void(NetworkResult)> successCallback,
HelixFailureCallback failureCallback)
void Helix::updateChannel(
QString broadcasterId, QString gameId, QString language, QString title,
std::function<void(NetworkResult)> successCallback,
FailureCallback<HelixUpdateChannelError, QString> failureCallback)
{
using Error = HelixUpdateChannelError;
QUrlQuery urlQuery;
auto obj = QJsonObject();
if (!gameId.isEmpty())
@ -646,7 +648,61 @@ void Helix::updateChannel(QString broadcasterId, QString gameId,
successCallback(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();
}

View file

@ -595,6 +595,19 @@ enum class HelixUpdateChatSettingsError { // update chat settings
Forwarded,
}; // 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
Unknown,
UserMissingScope,
@ -862,7 +875,7 @@ public:
virtual void updateChannel(
QString broadcasterId, QString gameId, QString language, QString title,
std::function<void(NetworkResult)> successCallback,
HelixFailureCallback failureCallback) = 0;
FailureCallback<HelixUpdateChannelError, QString> failureCallback) = 0;
// https://dev.twitch.tv/docs/api/reference#manage-held-automod-messages
virtual void manageAutoModMessages(
@ -1183,7 +1196,8 @@ public:
void updateChannel(QString broadcasterId, QString gameId, QString language,
QString title,
std::function<void(NetworkResult)> successCallback,
HelixFailureCallback failureCallback) final;
FailureCallback<HelixUpdateChannelError, QString>
failureCallback) final;
// https://dev.twitch.tv/docs/api/reference#manage-held-automod-messages
void manageAutoModMessages(