From 2f5df3db4a082fb5b81651d0152755298a3d5485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82?= Date: Tue, 22 Dec 2020 09:55:58 +0100 Subject: [PATCH] Migrated follow and unfollow methods to Helix API (#2306) --- CHANGELOG.md | 1 + .../commands/CommandController.cpp | 58 ++++++++++++------- src/providers/twitch/TwitchAccount.cpp | 41 ------------- src/providers/twitch/TwitchAccount.hpp | 4 -- src/providers/twitch/api/Helix.cpp | 44 ++++++++++++++ src/providers/twitch/api/Helix.hpp | 8 +++ src/providers/twitch/api/README.md | 35 +++++------ src/widgets/dialogs/UserInfoPopup.cpp | 14 +++-- 8 files changed, 118 insertions(+), 87 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b0a35205..643ed6f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,7 @@ - Bugfix: Fix a crash bug that occurred when moving splits across windows and closing the "parent tab" (#2249, #2259) - Dev: Updated minimum required Qt framework version to 5.12. (#2210) - Dev: Migrated `Kraken::getUser` to Helix (#2260) +- Dev: Migrated `TwitchAccount::(un)followUser` from Kraken to Helix and moved it to `Helix::(un)followUser`. (#2306) ## 2.2.2 diff --git a/src/controllers/commands/CommandController.cpp b/src/controllers/commands/CommandController.cpp index b4832d92..1a6ae6e2 100644 --- a/src/controllers/commands/CommandController.cpp +++ b/src/controllers/commands/CommandController.cpp @@ -313,29 +313,39 @@ void CommandController::initialize(Settings &, Paths &paths) channel->addMessage(makeSystemMessage("Usage: /follow [user]")); return ""; } - auto app = getApp(); - auto user = app->accounts->twitch.getCurrent(); - auto target = words.at(1); + auto currentUser = getApp()->accounts->twitch.getCurrent(); - if (user->isAnon()) + if (currentUser->isAnon()) { channel->addMessage( makeSystemMessage("You must be logged in to follow someone")); return ""; } + auto target = words.at(1); + getHelix()->getUserByName( target, - [user, channel, target](const auto &targetUser) { - user->followUser(targetUser.id, [channel, target]() { - channel->addMessage(makeSystemMessage( - "You successfully followed " + target)); - }); + [currentUser, channel, target](const auto &targetUser) { + getHelix()->followUser( + currentUser->getUserId(), targetUser.id, + [channel, target]() { + channel->addMessage(makeSystemMessage( + "You successfully followed " + target)); + }, + [channel, target]() { + channel->addMessage(makeSystemMessage( + QString("User %1 could not be followed, an unknown " + "error occured!") + .arg(target))); + }); }, [channel, target] { - channel->addMessage(makeSystemMessage( - "User " + target + " could not be followed!")); + channel->addMessage( + makeSystemMessage(QString("User %1 could not be followed, " + "no user with that name found!") + .arg(target))); }); return ""; @@ -347,29 +357,35 @@ void CommandController::initialize(Settings &, Paths &paths) channel->addMessage(makeSystemMessage("Usage: /unfollow [user]")); return ""; } - auto app = getApp(); - auto user = app->accounts->twitch.getCurrent(); - auto target = words.at(1); + auto currentUser = getApp()->accounts->twitch.getCurrent(); - if (user->isAnon()) + if (currentUser->isAnon()) { channel->addMessage( makeSystemMessage("You must be logged in to follow someone")); return ""; } + auto target = words.at(1); + getHelix()->getUserByName( target, - [user, channel, target](const auto &targetUser) { - user->unfollowUser(targetUser.id, [channel, target]() { - channel->addMessage(makeSystemMessage( - "You successfully unfollowed " + target)); - }); + [currentUser, channel, target](const auto &targetUser) { + getHelix()->unfollowUser( + currentUser->getUserId(), targetUser.id, + [channel, target]() { + channel->addMessage(makeSystemMessage( + "You successfully unfollowed " + target)); + }, + [channel, target]() { + channel->addMessage(makeSystemMessage( + "An error occurred while unfollowing " + target)); + }); }, [channel, target] { channel->addMessage(makeSystemMessage( - "User " + target + " could not be followed!")); + QString("User %1 could not be followed!").arg(target))); }); return ""; diff --git a/src/providers/twitch/TwitchAccount.cpp b/src/providers/twitch/TwitchAccount.cpp index 90cef379..90b4c6ae 100644 --- a/src/providers/twitch/TwitchAccount.cpp +++ b/src/providers/twitch/TwitchAccount.cpp @@ -290,47 +290,6 @@ void TwitchAccount::checkFollow(const QString targetUserID, [] {}); } -void TwitchAccount::followUser(const QString userID, - std::function successCallback) -{ - QUrl requestUrl("https://api.twitch.tv/kraken/users/" + this->getUserId() + - "/follows/channels/" + userID); - - NetworkRequest(requestUrl, NetworkRequestType::Put) - - .authorizeTwitchV5(this->getOAuthClient(), this->getOAuthToken()) - .onSuccess([successCallback](auto result) -> Outcome { - // TODO: Properly check result of follow request - successCallback(); - - return Success; - }) - .execute(); -} - -void TwitchAccount::unfollowUser(const QString userID, - std::function successCallback) -{ - QUrl requestUrl("https://api.twitch.tv/kraken/users/" + this->getUserId() + - "/follows/channels/" + userID); - - NetworkRequest(requestUrl, NetworkRequestType::Delete) - - .authorizeTwitchV5(this->getOAuthClient(), this->getOAuthToken()) - .onError([successCallback](NetworkResult result) { - if (result.status() >= 200 && result.status() <= 299) - { - successCallback(); - } - }) - .onSuccess([successCallback](const auto &document) -> Outcome { - successCallback(); - - return Success; - }) - .execute(); -} - std::set TwitchAccount::getIgnores() const { std::lock_guard lock(this->ignoresMutex_); diff --git a/src/providers/twitch/TwitchAccount.hpp b/src/providers/twitch/TwitchAccount.hpp index e5db1749..d4e2bfd3 100644 --- a/src/providers/twitch/TwitchAccount.hpp +++ b/src/providers/twitch/TwitchAccount.hpp @@ -98,10 +98,6 @@ public: void checkFollow(const QString targetUserID, std::function onFinished); - void followUser(const QString userID, - std::function successCallback); - void unfollowUser(const QString userID, - std::function successCallback); std::set getIgnores() const; diff --git a/src/providers/twitch/api/Helix.cpp b/src/providers/twitch/api/Helix.cpp index 9a42851c..3187d074 100644 --- a/src/providers/twitch/api/Helix.cpp +++ b/src/providers/twitch/api/Helix.cpp @@ -315,6 +315,50 @@ void Helix::getGameById(QString gameId, failureCallback); } +void Helix::followUser(QString userId, QString targetId, + std::function successCallback, + HelixFailureCallback failureCallback) +{ + QUrlQuery urlQuery; + + urlQuery.addQueryItem("from_id", userId); + urlQuery.addQueryItem("to_id", targetId); + + this->makeRequest("users/follows", urlQuery) + .type(NetworkRequestType::Post) + .onSuccess([successCallback](auto result) -> Outcome { + successCallback(); + return Success; + }) + .onError([failureCallback](auto result) { + // TODO: make better xd + failureCallback(); + }) + .execute(); +} + +void Helix::unfollowUser(QString userId, QString targetId, + std::function successCallback, + HelixFailureCallback failureCallback) +{ + QUrlQuery urlQuery; + + urlQuery.addQueryItem("from_id", userId); + urlQuery.addQueryItem("to_id", targetId); + + this->makeRequest("users/follows", urlQuery) + .type(NetworkRequestType::Delete) + .onSuccess([successCallback](auto result) -> Outcome { + successCallback(); + return Success; + }) + .onError([failureCallback](auto result) { + // TODO: make better xd + failureCallback(); + }) + .execute(); +} + NetworkRequest Helix::makeRequest(QString url, QUrlQuery urlQuery) { assert(!url.startsWith("/")); diff --git a/src/providers/twitch/api/Helix.hpp b/src/providers/twitch/api/Helix.hpp index 1da8c1c7..bea88b25 100644 --- a/src/providers/twitch/api/Helix.hpp +++ b/src/providers/twitch/api/Helix.hpp @@ -184,6 +184,14 @@ public: void getGameById(QString gameId, ResultCallback successCallback, HelixFailureCallback failureCallback); + void followUser(QString userId, QString targetId, + std::function successCallback, + HelixFailureCallback failureCallback); + + void unfollowUser(QString userId, QString targetlId, + std::function successCallback, + HelixFailureCallback failureCallback); + void update(QString clientId, QString oauthToken); static void initialize(); diff --git a/src/providers/twitch/api/README.md b/src/providers/twitch/api/README.md index 3ae218fe..21a98e66 100644 --- a/src/providers/twitch/api/README.md +++ b/src/providers/twitch/api/README.md @@ -13,23 +13,6 @@ Migration path: **Unknown** Used in: * `TwitchChannel::refreshTitle` to check the current stream title/game of offline channels -### Follow Channel -URL: https://dev.twitch.tv/docs/v5/reference/users#follow-channel -Requires `user_follows_edit` scope - -Migration path: **Unknown** - - * We implement this API in `providers/twitch/TwitchAccount.cpp followUser` - -### Unfollow Channel -URL: https://dev.twitch.tv/docs/v5/reference/users#unfollow-channel -Requires `user_follows_edit` scope - -Migration path: **Unknown** - - * We implement this API in `providers/twitch/TwitchAccount.cpp unfollowUser` - - ### Get Cheermotes URL: https://dev.twitch.tv/docs/v5/reference/bits#get-cheermotes @@ -106,6 +89,24 @@ URL: https://dev.twitch.tv/docs/api/reference#get-streams * `TwitchChannel` to get live status, game, title, and viewer count of a channel * `NotificationController` to provide notifications for channels you might not have open in Chatterino, but are still interested in getting notifications for +### Follow User +URL: https://dev.twitch.tv/docs/api/reference#create-user-follows +Requires `user:edit:follows` scope + + * We implement this in `providers/twitch/api/Helix.cpp followUser` + Used in: + * `widgets/dialogs/UserInfoPopup.cpp` to follow a user by ticking follow checkbox in usercard + * `controllers/commands/CommandController.cpp` in /follow command + +### Unfollow User +URL: https://dev.twitch.tv/docs/api/reference#delete-user-follows +Requires `user:edit:follows` scope + + * We implement this in `providers/twitch/api/Helix.cpp unfollowUser` + Used in: + * `widgets/dialogs/UserInfoPopup.cpp` to unfollow a user by unticking follow checkbox in usercard + * `controllers/commands/CommandController.cpp` in /unfollow command + ## TMI The TMI api is undocumented. diff --git a/src/widgets/dialogs/UserInfoPopup.cpp b/src/widgets/dialogs/UserInfoPopup.cpp index 0d3560da..92cf7cf5 100644 --- a/src/widgets/dialogs/UserInfoPopup.cpp +++ b/src/widgets/dialogs/UserInfoPopup.cpp @@ -386,8 +386,11 @@ void UserInfoPopup::installEvents() { case Qt::CheckState::Unchecked: { this->ui_.follow->setEnabled(false); - currentUser->unfollowUser(this->userId_, - reenableFollowCheckbox); + getHelix()->unfollowUser(currentUser->getUserId(), + this->userId_, + reenableFollowCheckbox, [] { + // + }); } break; @@ -398,8 +401,11 @@ void UserInfoPopup::installEvents() case Qt::CheckState::Checked: { this->ui_.follow->setEnabled(false); - currentUser->followUser(this->userId_, - reenableFollowCheckbox); + getHelix()->followUser(currentUser->getUserId(), + this->userId_, + reenableFollowCheckbox, [] { + // + }); } break; }