From 0c5abb81495d630967547b36027f6a3048b505ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82?= Date: Wed, 4 Aug 2021 22:41:27 +0200 Subject: [PATCH] Deprecated /(un)follow commands and respective usercard action (#3078) /(un)follow commands are marked as deprecated and link to the issue this PR is closing. follow button on the usercard is removed completely Co-authored-by: pajlada Co-authored-by: Felanbird <41973452+Felanbird@users.noreply.github.com> --- CHANGELOG.md | 1 + .../commands/CommandController.cpp | 100 +++--------------- src/providers/twitch/TwitchAccount.cpp | 17 --- src/providers/twitch/TwitchAccount.hpp | 3 - src/providers/twitch/api/Helix.cpp | 63 ----------- src/providers/twitch/api/Helix.hpp | 15 --- src/providers/twitch/api/README.md | 20 ---- src/widgets/dialogs/UserInfoPopup.cpp | 67 ------------ src/widgets/dialogs/UserInfoPopup.hpp | 1 - 9 files changed, 17 insertions(+), 270 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 533ab79b9b5..baafb17d922 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unversioned - Major: Newly uploaded Twitch emotes are once again present in emote picker and can be autocompleted with Tab as well. (#2992) +- Major: Deprecated `/(un)follow` commands and (un)following in the usercards as Twitch has removed this feature for 3rd party applications. (#3076, #3078) - Major: Added the ability to add nicknames for users. (#137, #2981) - Major: Work on rate-limiting JOINs and PARTs. (#3112) - Minor: Added autocompletion in /whispers for Twitch emotes, Global Bttv/Ffz emotes and emojis. (#2999, #3033) diff --git a/src/controllers/commands/CommandController.cpp b/src/controllers/commands/CommandController.cpp index fcca4a2f966..333c29257f0 100644 --- a/src/controllers/commands/CommandController.cpp +++ b/src/controllers/commands/CommandController.cpp @@ -373,6 +373,22 @@ void CommandController::initialize(Settings &, Paths &paths) return ""; }); + this->registerCommand("/follow", [](const auto &words, auto channel) { + channel->addMessage(makeSystemMessage( + "Twitch has removed the ability to follow users through " + "third-party applications. For more information, see " + "https://github.com/Chatterino/chatterino2/issues/3076")); + return ""; + }); + + this->registerCommand("/unfollow", [](const auto &words, auto channel) { + channel->addMessage(makeSystemMessage( + "Twitch has removed the ability to unfollow users through " + "third-party applications. For more information, see " + "https://github.com/Chatterino/chatterino2/issues/3076")); + return ""; + }); + /// Supported commands this->registerCommand( @@ -407,90 +423,6 @@ void CommandController::initialize(Settings &, Paths &paths) this->registerCommand("/unblock", unblockLambda); - this->registerCommand("/follow", [](const auto &words, auto channel) { - if (words.size() < 2) - { - channel->addMessage(makeSystemMessage("Usage: /follow [user]")); - return ""; - } - - auto currentUser = getApp()->accounts->twitch.getCurrent(); - - if (currentUser->isAnon()) - { - channel->addMessage( - makeSystemMessage("You must be logged in to follow someone!")); - return ""; - } - - auto target = words.at(1); - - getHelix()->getUserByName( - 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 occurred!") - .arg(target))); - }); - }, - [channel, target] { - channel->addMessage( - makeSystemMessage(QString("User %1 could not be followed, " - "no user with that name found!") - .arg(target))); - }); - - return ""; - }); - - this->registerCommand("/unfollow", [](const auto &words, auto channel) { - if (words.size() < 2) - { - channel->addMessage(makeSystemMessage("Usage: /unfollow [user]")); - return ""; - } - - auto currentUser = getApp()->accounts->twitch.getCurrent(); - - if (currentUser->isAnon()) - { - channel->addMessage(makeSystemMessage( - "You must be logged in to unfollow someone!")); - return ""; - } - - auto target = words.at(1); - - getHelix()->getUserByName( - 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( - QString("User %1 could not be followed!").arg(target))); - }); - - return ""; - }); - this->registerCommand("/user", [](const auto &words, auto channel) { if (words.size() < 2) { diff --git a/src/providers/twitch/TwitchAccount.cpp b/src/providers/twitch/TwitchAccount.cpp index 416d5ba619b..237ba2df06e 100644 --- a/src/providers/twitch/TwitchAccount.cpp +++ b/src/providers/twitch/TwitchAccount.cpp @@ -186,23 +186,6 @@ void TwitchAccount::unblockUser(QString userId, std::function onSuccess, std::move(onFailure)); } -void TwitchAccount::checkFollow(const QString targetUserID, - std::function onFinished) -{ - const auto onResponse = [onFinished](bool following, const auto &record) { - if (!following) - { - onFinished(FollowResult_NotFollowing); - return; - } - - onFinished(FollowResult_Following); - }; - - getHelix()->getUserFollow(this->getUserId(), targetUserID, onResponse, - [] {}); -} - SharedAccessGuard> TwitchAccount::accessBlocks() const { diff --git a/src/providers/twitch/TwitchAccount.hpp b/src/providers/twitch/TwitchAccount.hpp index af56afaf1cb..36e7d0ad6ab 100644 --- a/src/providers/twitch/TwitchAccount.hpp +++ b/src/providers/twitch/TwitchAccount.hpp @@ -108,9 +108,6 @@ class TwitchAccount : public Account void unblockUser(QString userId, std::function onSuccess, std::function onFailure); - void checkFollow(const QString targetUserID, - std::function onFinished); - SharedAccessGuard> accessBlockedUserIds() const; SharedAccessGuard> accessBlocks() const; diff --git a/src/providers/twitch/api/Helix.cpp b/src/providers/twitch/api/Helix.cpp index 2fe734a5337..12b812d71b6 100644 --- a/src/providers/twitch/api/Helix.cpp +++ b/src/providers/twitch/api/Helix.cpp @@ -142,25 +142,6 @@ void Helix::getUserFollowers( std::move(failureCallback)); } -void Helix::getUserFollow( - QString userId, QString targetId, - ResultCallback successCallback, - HelixFailureCallback failureCallback) -{ - this->fetchUsersFollows( - std::move(userId), std::move(targetId), - [successCallback](const auto &response) { - if (response.data.empty()) - { - successCallback(false, HelixUsersFollowsRecord()); - return; - } - - successCallback(true, response.data[0]); - }, - std::move(failureCallback)); -} - void Helix::fetchStreams( QStringList userIds, QStringList userLogins, ResultCallback> successCallback, @@ -354,50 +335,6 @@ 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(); -} - void Helix::createClip(QString channelId, ResultCallback successCallback, std::function failureCallback, diff --git a/src/providers/twitch/api/Helix.hpp b/src/providers/twitch/api/Helix.hpp index 0b437765cf3..7648243a254 100644 --- a/src/providers/twitch/api/Helix.hpp +++ b/src/providers/twitch/api/Helix.hpp @@ -341,11 +341,6 @@ class Helix final : boost::noncopyable ResultCallback successCallback, HelixFailureCallback failureCallback); - void getUserFollow( - QString userId, QString targetId, - ResultCallback successCallback, - HelixFailureCallback failureCallback); - // https://dev.twitch.tv/docs/api/reference#get-streams void fetchStreams(QStringList userIds, QStringList userLogins, ResultCallback> successCallback, @@ -372,16 +367,6 @@ class Helix final : boost::noncopyable void getGameById(QString gameId, ResultCallback successCallback, HelixFailureCallback failureCallback); - // https://dev.twitch.tv/docs/api/reference#create-user-follows - void followUser(QString userId, QString targetId, - std::function successCallback, - HelixFailureCallback failureCallback); - - // https://dev.twitch.tv/docs/api/reference#delete-user-follows - void unfollowUser(QString userId, QString targetlId, - std::function successCallback, - HelixFailureCallback failureCallback); - // https://dev.twitch.tv/docs/api/reference#create-clip void createClip(QString channelId, ResultCallback successCallback, diff --git a/src/providers/twitch/api/README.md b/src/providers/twitch/api/README.md index 15c52cca9c8..6f1b46a038d 100644 --- a/src/providers/twitch/api/README.md +++ b/src/providers/twitch/api/README.md @@ -47,26 +47,6 @@ 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 - ### Create Clip URL: https://dev.twitch.tv/docs/api/reference#create-clip diff --git a/src/widgets/dialogs/UserInfoPopup.cpp b/src/widgets/dialogs/UserInfoPopup.cpp index 1f5c62afec1..706ca839df1 100644 --- a/src/widgets/dialogs/UserInfoPopup.cpp +++ b/src/widgets/dialogs/UserInfoPopup.cpp @@ -233,7 +233,6 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, QWidget *parent) { user->addStretch(1); - user.emplace("Follow").assign(&this->ui_.follow); user.emplace("Block").assign(&this->ui_.block); user.emplace("Ignore highlights") .assign(&this->ui_.ignoreHighlights); @@ -403,56 +402,6 @@ void UserInfoPopup::scaleChangedEvent(float /*scale*/) void UserInfoPopup::installEvents() { - std::weak_ptr hack = this->hack_; - - // follow - QObject::connect( - this->ui_.follow, &QCheckBox::stateChanged, - [this](int newState) mutable { - auto currentUser = getApp()->accounts->twitch.getCurrent(); - - const auto reenableFollowCheckbox = [this] { - this->ui_.follow->setEnabled(true); - }; - - if (!this->ui_.follow->isEnabled()) - { - // We received a state update while the checkbox was disabled - // This can only happen from the "check current follow state" call - // The state has been updated to properly reflect the users current follow state - reenableFollowCheckbox(); - return; - } - - switch (newState) - { - case Qt::CheckState::Unchecked: { - this->ui_.follow->setEnabled(false); - getHelix()->unfollowUser(currentUser->getUserId(), - this->userId_, - reenableFollowCheckbox, [] { - // - }); - } - break; - - case Qt::CheckState::PartiallyChecked: { - // We deliberately ignore this state - } - break; - - case Qt::CheckState::Checked: { - this->ui_.follow->setEnabled(false); - getHelix()->followUser(currentUser->getUserId(), - this->userId_, - reenableFollowCheckbox, [] { - // - }); - } - break; - } - }); - std::shared_ptr ignoreNext = std::make_shared(false); // block @@ -616,8 +565,6 @@ void UserInfoPopup::updateLatestMessages() void UserInfoPopup::updateUserData() { - this->ui_.follow->setEnabled(false); - std::weak_ptr hack = this->hack_; auto currentUser = getApp()->accounts->twitch.getCurrent(); @@ -683,19 +630,6 @@ void UserInfoPopup::updateUserData() // on failure }); - // get follow state - currentUser->checkFollow(user.id, [this, hack](auto result) { - if (!hack.lock()) - { - return; - } - if (result != FollowResult_Failed) - { - this->ui_.follow->setChecked(result == FollowResult_Following); - this->ui_.follow->setEnabled(true); - } - }); - // get ignore state bool isIgnoring = false; @@ -772,7 +706,6 @@ void UserInfoPopup::updateUserData() getHelix()->getUserByName(this->userName_, onUserFetched, onUserFetchFailed); - this->ui_.follow->setEnabled(false); this->ui_.block->setEnabled(false); this->ui_.ignoreHighlights->setEnabled(false); } diff --git a/src/widgets/dialogs/UserInfoPopup.hpp b/src/widgets/dialogs/UserInfoPopup.hpp index c0b868b9d19..ed195d033cd 100644 --- a/src/widgets/dialogs/UserInfoPopup.hpp +++ b/src/widgets/dialogs/UserInfoPopup.hpp @@ -59,7 +59,6 @@ class UserInfoPopup final : public BaseWindow Label *followageLabel = nullptr; Label *subageLabel = nullptr; - QCheckBox *follow = nullptr; QCheckBox *block = nullptr; QCheckBox *ignoreHighlights = nullptr;