Skip to content

Commit

Permalink
Deprecated /(un)follow commands and respective usercard action (Chatt…
Browse files Browse the repository at this point in the history
…erino#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 <rasmus.karlsson@pajlada.com>
Co-authored-by: Felanbird <41973452+Felanbird@users.noreply.github.com>
  • Loading branch information
3 people committed Aug 4, 2021
1 parent 28dcdb2 commit 0c5abb8
Show file tree
Hide file tree
Showing 9 changed files with 17 additions and 270 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
100 changes: 16 additions & 84 deletions src/controllers/commands/CommandController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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)
{
Expand Down
17 changes: 0 additions & 17 deletions src/providers/twitch/TwitchAccount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,23 +186,6 @@ void TwitchAccount::unblockUser(QString userId, std::function<void()> onSuccess,
std::move(onFailure));
}

void TwitchAccount::checkFollow(const QString targetUserID,
std::function<void(FollowResult)> 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<const std::set<TwitchUser>> TwitchAccount::accessBlocks()
const
{
Expand Down
3 changes: 0 additions & 3 deletions src/providers/twitch/TwitchAccount.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,6 @@ class TwitchAccount : public Account
void unblockUser(QString userId, std::function<void()> onSuccess,
std::function<void()> onFailure);

void checkFollow(const QString targetUserID,
std::function<void(FollowResult)> onFinished);

SharedAccessGuard<const std::set<QString>> accessBlockedUserIds() const;
SharedAccessGuard<const std::set<TwitchUser>> accessBlocks() const;

Expand Down
63 changes: 0 additions & 63 deletions src/providers/twitch/api/Helix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,25 +142,6 @@ void Helix::getUserFollowers(
std::move(failureCallback));
}

void Helix::getUserFollow(
QString userId, QString targetId,
ResultCallback<bool, HelixUsersFollowsRecord> 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<std::vector<HelixStream>> successCallback,
Expand Down Expand Up @@ -354,50 +335,6 @@ void Helix::getGameById(QString gameId,
failureCallback);
}

void Helix::followUser(QString userId, QString targetId,
std::function<void()> 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<void()> 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<HelixClip> successCallback,
std::function<void(HelixClipError)> failureCallback,
Expand Down
15 changes: 0 additions & 15 deletions src/providers/twitch/api/Helix.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,11 +341,6 @@ class Helix final : boost::noncopyable
ResultCallback<HelixUsersFollowsResponse> successCallback,
HelixFailureCallback failureCallback);

void getUserFollow(
QString userId, QString targetId,
ResultCallback<bool, HelixUsersFollowsRecord> successCallback,
HelixFailureCallback failureCallback);

// https://dev.twitch.tv/docs/api/reference#get-streams
void fetchStreams(QStringList userIds, QStringList userLogins,
ResultCallback<std::vector<HelixStream>> successCallback,
Expand All @@ -372,16 +367,6 @@ class Helix final : boost::noncopyable
void getGameById(QString gameId, ResultCallback<HelixGame> successCallback,
HelixFailureCallback failureCallback);

// https://dev.twitch.tv/docs/api/reference#create-user-follows
void followUser(QString userId, QString targetId,
std::function<void()> successCallback,
HelixFailureCallback failureCallback);

// https://dev.twitch.tv/docs/api/reference#delete-user-follows
void unfollowUser(QString userId, QString targetlId,
std::function<void()> successCallback,
HelixFailureCallback failureCallback);

// https://dev.twitch.tv/docs/api/reference#create-clip
void createClip(QString channelId,
ResultCallback<HelixClip> successCallback,
Expand Down
20 changes: 0 additions & 20 deletions src/providers/twitch/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
67 changes: 0 additions & 67 deletions src/widgets/dialogs/UserInfoPopup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,6 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, QWidget *parent)
{
user->addStretch(1);

user.emplace<QCheckBox>("Follow").assign(&this->ui_.follow);
user.emplace<QCheckBox>("Block").assign(&this->ui_.block);
user.emplace<QCheckBox>("Ignore highlights")
.assign(&this->ui_.ignoreHighlights);
Expand Down Expand Up @@ -403,56 +402,6 @@ void UserInfoPopup::scaleChangedEvent(float /*scale*/)

void UserInfoPopup::installEvents()
{
std::weak_ptr<bool> 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<bool> ignoreNext = std::make_shared<bool>(false);

// block
Expand Down Expand Up @@ -616,8 +565,6 @@ void UserInfoPopup::updateLatestMessages()

void UserInfoPopup::updateUserData()
{
this->ui_.follow->setEnabled(false);

std::weak_ptr<bool> hack = this->hack_;
auto currentUser = getApp()->accounts->twitch.getCurrent();

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
}
Expand Down
1 change: 0 additions & 1 deletion src/widgets/dialogs/UserInfoPopup.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ class UserInfoPopup final : public BaseWindow
Label *followageLabel = nullptr;
Label *subageLabel = nullptr;

QCheckBox *follow = nullptr;
QCheckBox *block = nullptr;
QCheckBox *ignoreHighlights = nullptr;

Expand Down

0 comments on commit 0c5abb8

Please sign in to comment.